Merge remote-tracking branch 'origin/main' into test-ios

This commit is contained in:
Kerod-Fresenbet-Gebremedhin2660 2026-05-30 10:57:23 +03:00
commit 485aa7a46f
43 changed files with 493 additions and 394 deletions

View File

@ -183,13 +183,10 @@
"welcome_abroad": "እንኳን ደህና መጣህ", "welcome_abroad": "እንኳን ደህና መጣህ",
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።", "ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
"finish": "አጠናቅቅ", "finish": "አጠናቅቅ",
"finish_all_practice_lesson": "ይህን ልምምድ ለመውሰድ የቀድሞውን የትምህርት ልምምድ ያጠናቅቁ",
"finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።" "finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
"finish_all_practice_previouse_module": "ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ"
} }

View File

@ -183,5 +183,10 @@
"welcome_abroad": "Welcome aboard", "welcome_abroad": "Welcome aboard",
"ready_to_explore": "Youre ready to explore your personalized lessons.", "ready_to_explore": "Youre ready to explore your personalized lessons.",
"finish": "Finish", "finish": "Finish",
"finish_all_practice": "Finish all the practices in the lessons to take this practice" "finish_all_practice_lesson": "Finish the previous lesson practice to take this practice",
"finish_all_practice_module": "Finish the lesson practices to take the Module Practice",
"finish_all_practice_course": "Finish the Module practices to take the Course practice",
"finish_all_practice_previouse_module": "Finish the previous Module practice to take this practice",
"finish_all_practice_previouse_course": "Finish the previous course practice to take this"
} }

View File

@ -49,7 +49,6 @@ import 'package:yimaru_app/services/vimeo_service.dart';
import 'package:yimaru_app/services/url_launcher_service.dart'; import 'package:yimaru_app/services/url_launcher_service.dart';
import 'package:yimaru_app/services/phone_caller_service.dart'; import 'package:yimaru_app/services/phone_caller_service.dart';
import 'package:yimaru_app/ui/views/learn_subscription/learn_subscription_view.dart'; import 'package:yimaru_app/ui/views/learn_subscription/learn_subscription_view.dart';
import 'package:yimaru_app/ui/views/arif_pay/arif_pay_view.dart';
import 'package:yimaru_app/services/learn_service.dart'; import 'package:yimaru_app/services/learn_service.dart';
import 'package:yimaru_app/ui/views/course_catalog/course_catalog_view.dart'; import 'package:yimaru_app/ui/views/course_catalog/course_catalog_view.dart';
import 'package:yimaru_app/ui/views/course_unit/course_unit_view.dart'; import 'package:yimaru_app/ui/views/course_unit/course_unit_view.dart';
@ -58,6 +57,7 @@ import 'package:yimaru_app/ui/views/landing/landing_view.dart';
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart'; import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
import 'package:yimaru_app/services/onboarding_service.dart'; import 'package:yimaru_app/services/onboarding_service.dart';
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart'; import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart';
import 'package:yimaru_app/ui/views/payment/payment_view.dart';
// @stacked-import // @stacked-import
@StackedApp( @StackedApp(
@ -91,12 +91,12 @@ import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart';
MaterialRoute(page: LearnProgramView), MaterialRoute(page: LearnProgramView),
MaterialRoute(page: AssessmentView), MaterialRoute(page: AssessmentView),
MaterialRoute(page: LearnSubscriptionView), MaterialRoute(page: LearnSubscriptionView),
MaterialRoute(page: ArifPayView),
MaterialRoute(page: CourseCatalogView), MaterialRoute(page: CourseCatalogView),
MaterialRoute(page: CourseUnitView), MaterialRoute(page: CourseUnitView),
MaterialRoute(page: LandingView), MaterialRoute(page: LandingView),
MaterialRoute(page: CourseModuleView), MaterialRoute(page: CourseModuleView),
MaterialRoute(page: LearnCourseView), MaterialRoute(page: LearnCourseView),
MaterialRoute(page: PaymentView),
// @stacked-route // @stacked-route
], ],
dependencies: [ dependencies: [

View File

@ -9,7 +9,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/material.dart' as _i37; import 'package:flutter/material.dart' as _i37;
import 'package:stacked/stacked.dart' as _i1; import 'package:stacked/stacked.dart' as _i1;
import 'package:stacked_services/stacked_services.dart' as _i46; import 'package:stacked_services/stacked_services.dart' as _i47;
import 'package:yimaru_app/models/course.dart' as _i42; import 'package:yimaru_app/models/course.dart' as _i42;
import 'package:yimaru_app/models/course_catalog.dart' as _i44; import 'package:yimaru_app/models/course_catalog.dart' as _i44;
import 'package:yimaru_app/models/course_lesson.dart' as _i43; import 'package:yimaru_app/models/course_lesson.dart' as _i43;
@ -17,33 +17,33 @@ import 'package:yimaru_app/models/course_module.dart' as _i45;
import 'package:yimaru_app/models/learn_course.dart' as _i38; import 'package:yimaru_app/models/learn_course.dart' as _i38;
import 'package:yimaru_app/models/learn_lesson.dart' as _i40; import 'package:yimaru_app/models/learn_lesson.dart' as _i40;
import 'package:yimaru_app/models/learn_module.dart' as _i39; import 'package:yimaru_app/models/learn_module.dart' as _i39;
import 'package:yimaru_app/models/learn_subscription.dart' as _i46;
import 'package:yimaru_app/ui/common/enmus.dart' as _i41; import 'package:yimaru_app/ui/common/enmus.dart' as _i41;
import 'package:yimaru_app/ui/views/account_privacy/account_privacy_view.dart' import 'package:yimaru_app/ui/views/account_privacy/account_privacy_view.dart'
as _i9; as _i9;
import 'package:yimaru_app/ui/views/arif_pay/arif_pay_view.dart' as _i31;
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i29; import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i29;
import 'package:yimaru_app/ui/views/call_support/call_support_view.dart' import 'package:yimaru_app/ui/views/call_support/call_support_view.dart'
as _i12; as _i12;
import 'package:yimaru_app/ui/views/course/course_view.dart' as _i27; import 'package:yimaru_app/ui/views/course/course_view.dart' as _i27;
import 'package:yimaru_app/ui/views/course_catalog/course_catalog_view.dart' import 'package:yimaru_app/ui/views/course_catalog/course_catalog_view.dart'
as _i32; as _i31;
import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart' import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart'
as _i25; as _i25;
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart' import 'package:yimaru_app/ui/views/course_module/course_module_view.dart'
as _i35; as _i34;
import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart' import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart'
as _i23; as _i23;
import 'package:yimaru_app/ui/views/course_unit/course_unit_view.dart' as _i33; import 'package:yimaru_app/ui/views/course_unit/course_unit_view.dart' as _i32;
import 'package:yimaru_app/ui/views/downloads/downloads_view.dart' as _i7; import 'package:yimaru_app/ui/views/downloads/downloads_view.dart' as _i7;
import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart' as _i26; import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart' as _i26;
import 'package:yimaru_app/ui/views/failure/failure_view.dart' as _i24; import 'package:yimaru_app/ui/views/failure/failure_view.dart' as _i24;
import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart' import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart'
as _i20; as _i20;
import 'package:yimaru_app/ui/views/home/home_view.dart' as _i2; import 'package:yimaru_app/ui/views/home/home_view.dart' as _i2;
import 'package:yimaru_app/ui/views/landing/landing_view.dart' as _i34; import 'package:yimaru_app/ui/views/landing/landing_view.dart' as _i33;
import 'package:yimaru_app/ui/views/language/language_view.dart' as _i13; import 'package:yimaru_app/ui/views/language/language_view.dart' as _i13;
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart' import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart'
as _i36; as _i35;
import 'package:yimaru_app/ui/views/learn_lesson/learn_lesson_view.dart' import 'package:yimaru_app/ui/views/learn_lesson/learn_lesson_view.dart'
as _i19; as _i19;
import 'package:yimaru_app/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart' import 'package:yimaru_app/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart'
@ -58,6 +58,7 @@ import 'package:yimaru_app/ui/views/learn_subscription/learn_subscription_view.d
as _i30; as _i30;
import 'package:yimaru_app/ui/views/login/login_view.dart' as _i17; import 'package:yimaru_app/ui/views/login/login_view.dart' as _i17;
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.dart' as _i3; import 'package:yimaru_app/ui/views/onboarding/onboarding_view.dart' as _i3;
import 'package:yimaru_app/ui/views/payment/payment_view.dart' as _i36;
import 'package:yimaru_app/ui/views/privacy_policy/privacy_policy_view.dart' import 'package:yimaru_app/ui/views/privacy_policy/privacy_policy_view.dart'
as _i14; as _i14;
import 'package:yimaru_app/ui/views/profile/profile_view.dart' as _i5; import 'package:yimaru_app/ui/views/profile/profile_view.dart' as _i5;
@ -131,8 +132,6 @@ class Routes {
static const learnSubscriptionView = '/learn-subscription-view'; static const learnSubscriptionView = '/learn-subscription-view';
static const arifPayView = '/arif-pay-view';
static const courseCatalogView = '/course-catalog-view'; static const courseCatalogView = '/course-catalog-view';
static const courseUnitView = '/course-unit-view'; static const courseUnitView = '/course-unit-view';
@ -143,6 +142,8 @@ class Routes {
static const learnCourseView = '/learn-course-view'; static const learnCourseView = '/learn-course-view';
static const paymentView = '/payment-view';
static const all = <String>{ static const all = <String>{
homeView, homeView,
onboardingView, onboardingView,
@ -173,12 +174,12 @@ class Routes {
learnProgramView, learnProgramView,
assessmentView, assessmentView,
learnSubscriptionView, learnSubscriptionView,
arifPayView,
courseCatalogView, courseCatalogView,
courseUnitView, courseUnitView,
landingView, landingView,
courseModuleView, courseModuleView,
learnCourseView, learnCourseView,
paymentView,
}; };
} }
@ -300,29 +301,29 @@ class StackedRouter extends _i1.RouterBase {
Routes.learnSubscriptionView, Routes.learnSubscriptionView,
page: _i30.LearnSubscriptionView, page: _i30.LearnSubscriptionView,
), ),
_i1.RouteDef(
Routes.arifPayView,
page: _i31.ArifPayView,
),
_i1.RouteDef( _i1.RouteDef(
Routes.courseCatalogView, Routes.courseCatalogView,
page: _i32.CourseCatalogView, page: _i31.CourseCatalogView,
), ),
_i1.RouteDef( _i1.RouteDef(
Routes.courseUnitView, Routes.courseUnitView,
page: _i33.CourseUnitView, page: _i32.CourseUnitView,
), ),
_i1.RouteDef( _i1.RouteDef(
Routes.landingView, Routes.landingView,
page: _i34.LandingView, page: _i33.LandingView,
), ),
_i1.RouteDef( _i1.RouteDef(
Routes.courseModuleView, Routes.courseModuleView,
page: _i35.CourseModuleView, page: _i34.CourseModuleView,
), ),
_i1.RouteDef( _i1.RouteDef(
Routes.learnCourseView, Routes.learnCourseView,
page: _i36.LearnCourseView, page: _i35.LearnCourseView,
),
_i1.RouteDef(
Routes.paymentView,
page: _i36.PaymentView,
), ),
]; ];
@ -590,52 +591,52 @@ class StackedRouter extends _i1.RouterBase {
settings: data, settings: data,
); );
}, },
_i31.ArifPayView: (data) { _i31.CourseCatalogView: (data) {
final args = data.getArgs<ArifPayViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>(
builder: (context) =>
_i31.ArifPayView(key: args.key, phone: args.phone),
settings: data,
);
},
_i32.CourseCatalogView: (data) {
final args = data.getArgs<CourseCatalogViewArguments>( final args = data.getArgs<CourseCatalogViewArguments>(
orElse: () => const CourseCatalogViewArguments(), orElse: () => const CourseCatalogViewArguments(),
); );
return _i37.MaterialPageRoute<dynamic>( return _i37.MaterialPageRoute<dynamic>(
builder: (context) => _i32.CourseCatalogView(key: args.key), builder: (context) => _i31.CourseCatalogView(key: args.key),
settings: data, settings: data,
); );
}, },
_i33.CourseUnitView: (data) { _i32.CourseUnitView: (data) {
final args = data.getArgs<CourseUnitViewArguments>(nullOk: false); final args = data.getArgs<CourseUnitViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>( return _i37.MaterialPageRoute<dynamic>(
builder: (context) => builder: (context) =>
_i33.CourseUnitView(key: args.key, catalog: args.catalog), _i32.CourseUnitView(key: args.key, catalog: args.catalog),
settings: data, settings: data,
); );
}, },
_i34.LandingView: (data) { _i33.LandingView: (data) {
final args = data.getArgs<LandingViewArguments>( final args = data.getArgs<LandingViewArguments>(
orElse: () => const LandingViewArguments(), orElse: () => const LandingViewArguments(),
); );
return _i37.MaterialPageRoute<dynamic>( return _i37.MaterialPageRoute<dynamic>(
builder: (context) => _i34.LandingView(key: args.key), builder: (context) => _i33.LandingView(key: args.key),
settings: data, settings: data,
); );
}, },
_i35.CourseModuleView: (data) { _i34.CourseModuleView: (data) {
final args = data.getArgs<CourseModuleViewArguments>(nullOk: false); final args = data.getArgs<CourseModuleViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>( return _i37.MaterialPageRoute<dynamic>(
builder: (context) => _i35.CourseModuleView( builder: (context) => _i34.CourseModuleView(
key: args.key, module: args.module, catalog: args.catalog), key: args.key, module: args.module, catalog: args.catalog),
settings: data, settings: data,
); );
}, },
_i36.LearnCourseView: (data) { _i35.LearnCourseView: (data) {
final args = data.getArgs<LearnCourseViewArguments>(nullOk: false); final args = data.getArgs<LearnCourseViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>( return _i37.MaterialPageRoute<dynamic>(
builder: (context) => _i36.LearnCourseView(key: args.key, id: args.id), builder: (context) => _i35.LearnCourseView(key: args.key, id: args.id),
settings: data,
);
},
_i36.PaymentView: (data) {
final args = data.getArgs<PaymentViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>(
builder: (context) => _i36.PaymentView(
key: args.key, phone: args.phone, subscription: args.subscription),
settings: data, settings: data,
); );
}, },
@ -1378,33 +1379,6 @@ class LearnSubscriptionViewArguments {
} }
} }
class ArifPayViewArguments {
const ArifPayViewArguments({
this.key,
required this.phone,
});
final _i37.Key? key;
final String phone;
@override
String toString() {
return '{"key": "$key", "phone": "$phone"}';
}
@override
bool operator ==(covariant ArifPayViewArguments other) {
if (identical(this, other)) return true;
return other.key == key && other.phone == phone;
}
@override
int get hashCode {
return key.hashCode ^ phone.hashCode;
}
}
class CourseCatalogViewArguments { class CourseCatalogViewArguments {
const CourseCatalogViewArguments({this.key}); const CourseCatalogViewArguments({this.key});
@ -1535,7 +1509,39 @@ class LearnCourseViewArguments {
} }
} }
extension NavigatorStateExtension on _i46.NavigationService { class PaymentViewArguments {
const PaymentViewArguments({
this.key,
required this.phone,
required this.subscription,
});
final _i37.Key? key;
final String phone;
final _i46.LearnSubscription subscription;
@override
String toString() {
return '{"key": "$key", "phone": "$phone", "subscription": "$subscription"}';
}
@override
bool operator ==(covariant PaymentViewArguments other) {
if (identical(this, other)) return true;
return other.key == key &&
other.phone == phone &&
other.subscription == subscription;
}
@override
int get hashCode {
return key.hashCode ^ phone.hashCode ^ subscription.hashCode;
}
}
extension NavigatorStateExtension on _i47.NavigationService {
Future<dynamic> navigateToHomeView({ Future<dynamic> navigateToHomeView({
_i37.Key? key, _i37.Key? key,
int? routerId, int? routerId,
@ -2030,23 +2036,6 @@ extension NavigatorStateExtension on _i46.NavigationService {
transition: transition); transition: transition);
} }
Future<dynamic> navigateToArifPayView({
_i37.Key? key,
required String phone,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return navigateTo<dynamic>(Routes.arifPayView,
arguments: ArifPayViewArguments(key: key, phone: phone),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToCourseCatalogView({ Future<dynamic> navigateToCourseCatalogView({
_i37.Key? key, _i37.Key? key,
int? routerId, int? routerId,
@ -2132,6 +2121,25 @@ extension NavigatorStateExtension on _i46.NavigationService {
transition: transition); transition: transition);
} }
Future<dynamic> navigateToPaymentView({
_i37.Key? key,
required String phone,
required _i46.LearnSubscription subscription,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return navigateTo<dynamic>(Routes.paymentView,
arguments: PaymentViewArguments(
key: key, phone: phone, subscription: subscription),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithHomeView({ Future<dynamic> replaceWithHomeView({
_i37.Key? key, _i37.Key? key,
int? routerId, int? routerId,
@ -2626,23 +2634,6 @@ extension NavigatorStateExtension on _i46.NavigationService {
transition: transition); transition: transition);
} }
Future<dynamic> replaceWithArifPayView({
_i37.Key? key,
required String phone,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return replaceWith<dynamic>(Routes.arifPayView,
arguments: ArifPayViewArguments(key: key, phone: phone),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithCourseCatalogView({ Future<dynamic> replaceWithCourseCatalogView({
_i37.Key? key, _i37.Key? key,
int? routerId, int? routerId,
@ -2727,4 +2718,23 @@ extension NavigatorStateExtension on _i46.NavigationService {
parameters: parameters, parameters: parameters,
transition: transition); transition: transition);
} }
Future<dynamic> replaceWithPaymentView({
_i37.Key? key,
required String phone,
required _i46.LearnSubscription subscription,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return replaceWith<dynamic>(Routes.paymentView,
arguments: PaymentViewArguments(
key: key, phone: phone, subscription: subscription),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
} }

View File

@ -122,7 +122,7 @@ String kTelegramSupport = '@yimaruacademy2026';
String kTelegramSupportLink = 'https://t.me/yimaruacademy2026'; String kTelegramSupportLink = 'https://t.me/yimaruacademy2026';
String kErrorUrl = 'https://yimaru.net/api/v1/payments/arifpay/error'; String kErrorUrl = 'https://yimaru.net/api/v1/payments/chapa/error';
String kSuccessUrl = String kSuccessUrl =
'https://api.yimaruacademy.com/api/v1/payments/arifpay/success'; 'https://api.yimaruacademy.com/api/v1/payments/chapa/success';

View File

@ -25,6 +25,9 @@ enum ProgressStatuses { pending, started, completed }
// Duolingo types // Duolingo types
enum DuolingoAssessments { speaking, reading, writing, listening } enum DuolingoAssessments { speaking, reading, writing, listening }
// Practice reason
enum PracticeReason { course, module, lesson, previousModule, previousCourse }
// State object // State object
enum StateObjects { enum StateObjects {
none, none,

View File

@ -202,7 +202,12 @@ class CodegenLoader extends AssetLoader {
"welcome_abroad": "እንኳን ደህና መጣህ", "welcome_abroad": "እንኳን ደህና መጣህ",
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።", "ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
"finish": "አጠናቅቅ", "finish": "አጠናቅቅ",
"finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።" "finish_all_practice_lesson": "ይህን ልምምድ ለመውሰድ የቀድሞውን የትምህርት ልምምድ ያጠናቅቁ",
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
"finish_all_practice_previouse_module":
"ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ"
}; };
static const Map<String, dynamic> _en = { static const Map<String, dynamic> _en = {
"loading": "Loading", "loading": "Loading",
@ -406,8 +411,16 @@ class CodegenLoader extends AssetLoader {
"welcome_abroad": "Welcome aboard", "welcome_abroad": "Welcome aboard",
"ready_to_explore": "Youre ready to explore your personalized lessons.", "ready_to_explore": "Youre ready to explore your personalized lessons.",
"finish": "Finish", "finish": "Finish",
"finish_all_practice": "finish_all_practice_lesson":
"Finish all the practices in the lessons to take this practice" "Finish the previous lesson practice to take this practice",
"finish_all_practice_module":
"Finish the lesson practices to take the Module Practice",
"finish_all_practice_course":
"Finish the Module practices to take the Course practice",
"finish_all_practice_previouse_module":
"Finish the previous Module practice to take this practice",
"finish_all_practice_previouse_course":
"Finish the previous course practice to take this"
}; };
static const Map<String, Map<String, dynamic>> mapLocales = { static const Map<String, Map<String, dynamic>> mapLocales = {
"am": _am, "am": _am,

View File

@ -186,5 +186,11 @@ abstract class LocaleKeys {
static const welcome_abroad = 'welcome_abroad'; static const welcome_abroad = 'welcome_abroad';
static const ready_to_explore = 'ready_to_explore'; static const ready_to_explore = 'ready_to_explore';
static const finish = 'finish'; static const finish = 'finish';
static const finish_all_practice = 'finish_all_practice'; static const finish_all_practice_lesson = 'finish_all_practice_lesson';
static const finish_all_practice_module = 'finish_all_practice_module';
static const finish_all_practice_course = 'finish_all_practice_course';
static const finish_all_practice_previouse_module =
'finish_all_practice_previouse_module';
static const finish_all_practice_previouse_course =
'finish_all_practice_previouse_course';
} }

View File

@ -52,9 +52,9 @@ class AssessmentView extends StackedView<AssessmentViewModel> {
]; ];
Widget _buildAssessmentIntroWrapper(AssessmentViewModel viewModel) => Widget _buildAssessmentIntroWrapper(AssessmentViewModel viewModel) =>
viewModel.busy(StateObjects.assessments) || viewModel.assessments.isEmpty viewModel.busy(StateObjects.assessments)
? _buildPageLoadingIndicator(viewModel) ? _buildPageLoadingIndicator(viewModel)
: _buildAssessmentIntro(); : _buildAssessmentIntro(viewModel);
Widget _buildPageLoadingIndicator(AssessmentViewModel viewModel) => Widget _buildPageLoadingIndicator(AssessmentViewModel viewModel) =>
AssessmentLoadingScreen( AssessmentLoadingScreen(
@ -64,7 +64,10 @@ class AssessmentView extends StackedView<AssessmentViewModel> {
onPop: viewModel.assessments.isEmpty ? viewModel.pop : null, onPop: viewModel.assessments.isEmpty ? viewModel.pop : null,
); );
Widget _buildAssessmentIntro() => const AssessmentIntroScreen(); Widget _buildAssessmentIntro(AssessmentViewModel viewModel) =>
AssessmentIntroScreen(
hasAssessments: viewModel.assessments.isNotEmpty,
);
Widget _buildAssessment() => const AssessmentQuestionsScreen(); Widget _buildAssessment() => const AssessmentQuestionsScreen();

View File

@ -10,7 +10,9 @@ import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
import '../assessment_viewmodel.dart'; import '../assessment_viewmodel.dart';
class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> { class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
const AssessmentIntroScreen({super.key}); final bool hasAssessments;
const AssessmentIntroScreen({super.key, required this.hasAssessments});
Future<void> _next(AssessmentViewModel viewModel) async => Future<void> _next(AssessmentViewModel viewModel) async =>
viewModel.setFirstAssessment(); viewModel.setFirstAssessment();
@ -29,11 +31,8 @@ class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(AssessmentViewModel viewModel) => Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
Expanded(child: _buildBodyWrapper(viewModel)); Expanded(child: _buildBodyWrapper(viewModel));
@ -59,7 +58,7 @@ class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
); );
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),
@ -91,7 +90,7 @@ class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
); );
List<Widget> _buildLowerColumnChildren(AssessmentViewModel viewModel) => [ List<Widget> _buildLowerColumnChildren(AssessmentViewModel viewModel) => [
_buildContinueButton(viewModel), if (hasAssessments) _buildContinueButton(viewModel),
verticalSpaceSmall, verticalSpaceSmall,
_buildSkipButtonWrapper(viewModel) _buildSkipButtonWrapper(viewModel)
]; ];

View File

@ -27,11 +27,8 @@ class AssessmentResultScreen extends ViewModelWidget<AssessmentViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar( Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
showBackButton: true, showBackButton: true,

View File

@ -44,11 +44,8 @@ class StartLessonScreen extends ViewModelWidget<AssessmentViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar( Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
showBackButton: true, showBackButton: true,

View File

@ -88,7 +88,6 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
required ForgetPasswordViewModel viewModel}) => required ForgetPasswordViewModel viewModel}) =>
[ [
_buildAppBar(viewModel), _buildAppBar(viewModel),
verticalSpaceMedium,
_buildExpandedBody(context: context, viewModel: viewModel) _buildExpandedBody(context: context, viewModel: viewModel)
]; ];

View File

@ -86,11 +86,8 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(ForgetPasswordViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(ForgetPasswordViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildAppBar(ForgetPasswordViewModel viewModel) => LargeAppBar( Widget _buildAppBar(ForgetPasswordViewModel viewModel) => LargeAppBar(
showBackButton: true, showBackButton: true,

View File

@ -24,17 +24,28 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
await viewModel.navigateToLearnPractice( await viewModel.navigateToLearnPractice(
id: course.id ?? 0, level: course.name ?? ''); id: course.id ?? 0, level: course.name ?? '');
} else { } else {
await _showSheet(context: context, viewModel: viewModel); if (course.access?.isAccessible ?? false) {
await _showSheet(
context: context,
viewModel: viewModel,
practice: PracticeReason.course);
} else {
await _showSheet(
context: context,
viewModel: viewModel,
practice: PracticeReason.previousCourse);
}
} }
} }
Future<void> _showSheet( Future<void> _showSheet(
{required BuildContext context, {required BuildContext context,
required PracticeReason practice,
required LearnCourseViewModel viewModel}) async => required LearnCourseViewModel viewModel}) async =>
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
backgroundColor: kcTransparent, backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel), builder: (_) => _buildSheet(viewModel: viewModel, practice: practice),
); );
@override @override
@ -156,6 +167,11 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
onPracticeTap: onPracticeTap, onPracticeTap: onPracticeTap,
); );
Widget _buildSheet(LearnCourseViewModel viewModel) => Widget _buildSheet(
FinishPracticeSheet(onTap: viewModel.pop); {required PracticeReason practice,
required LearnCourseViewModel viewModel}) =>
FinishPracticeSheet(
practice: practice,
onTap: viewModel.pop,
);
} }

View File

@ -31,15 +31,22 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
} else { } else {
await _showSheet(context: context, viewModel: viewModel); await _showSheet(context: context, viewModel: viewModel);
} }
/* if (index > 1) { /* if (index > 1) {
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') { if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') {
if (lesson.access?.isAccessible ?? false) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else {
await _showSheet(context: context, viewModel: viewModel);
}
} else { } else {
await viewModel.navigateToLearnSubscription(); await viewModel.navigateToLearnSubscription();
} }
} else { } else {
if (lesson.access?.isAccessible ?? false) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else {
await _showSheet(context: context, viewModel: viewModel);
}
}*/ }*/
} }
@ -197,7 +204,8 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
style: style18DG700, style: style18DG700,
); );
Widget _buildListViewBuilder( {required BuildContext context, Widget _buildListViewBuilder(
{required BuildContext context,
required LearnLessonViewModel viewModel}) => required LearnLessonViewModel viewModel}) =>
viewModel.busy(StateObjects.learnLessons) viewModel.busy(StateObjects.learnLessons)
? _buildProgressIndicator() ? _buildProgressIndicator()
@ -207,14 +215,17 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
child: CustomCircularProgressIndicator(color: kcPrimaryColor), child: CustomCircularProgressIndicator(color: kcPrimaryColor),
); );
Widget _buildListView( {required BuildContext context, Widget _buildListView(
required LearnLessonViewModel viewModel}) => ListView.builder( {required BuildContext context,
required LearnLessonViewModel viewModel}) =>
ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: viewModel.lessons.length, itemCount: viewModel.lessons.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildTile( itemBuilder: (context, index) => _buildTile(
index: index, index: index,
lesson: viewModel.lessons[index], lesson: viewModel.lessons[index],
last: index == viewModel.lessons.length - 1,
onPracticeTap: () async => await _onPractice( onPracticeTap: () async => await _onPractice(
index: index, index: index,
context: context, context: context,
@ -231,18 +242,22 @@ required LearnLessonViewModel viewModel}) => ListView.builder(
); );
Widget _buildTile({ Widget _buildTile({
required bool last,
required int index, required int index,
required LearnLesson lesson, required LearnLesson lesson,
required GestureTapCallback? onLessonTap, required GestureTapCallback? onLessonTap,
required GestureTapCallback? onPracticeTap, required GestureTapCallback? onPracticeTap,
}) => }) =>
LearnLessonTile( LearnLessonTile(
last: last,
index: index, index: index,
lesson: lesson, lesson: lesson,
onLessonTap: onLessonTap, onLessonTap: onLessonTap,
onPracticeTap: onPracticeTap, onPracticeTap: onPracticeTap,
); );
Widget _buildSheet(LearnLessonViewModel viewModel) => Widget _buildSheet(LearnLessonViewModel viewModel) => FinishPracticeSheet(
FinishPracticeSheet(onTap: viewModel.pop); onTap: viewModel.pop,
practice: PracticeReason.lesson,
);
} }

View File

@ -59,14 +59,15 @@ class LearnLessonViewModel extends ReactiveViewModel {
await _navigationService.navigateToLearnSubscriptionView(); await _navigationService.navigateToLearnSubscriptionView();
Future<void> navigateToLearnLessonDetail( Future<void> navigateToLearnLessonDetail(
{ {required int index,
required int index,
required bool hasPractice, required bool hasPractice,
required LearnLesson lesson, required LearnLesson lesson,
required LearnModule module}) async => required LearnModule module}) async =>
await _navigationService.navigateToLearnLessonDetailView( await _navigationService.navigateToLearnLessonDetailView(
index: index, index: index,
lesson: lesson, module: module, hasPractice: hasPractice); lesson: lesson,
module: module,
hasPractice: hasPractice);
// Remote api call // Remote api call

View File

@ -33,13 +33,17 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
required LearnLessonDetailViewModel viewModel}) async { required LearnLessonDetailViewModel viewModel}) async {
await viewModel.pause(); await viewModel.pause();
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
/* if (index > 1) { /* if (index > 1) {
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') { if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') {
await viewModel.pause();
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else { } else {
await viewModel.pause();
await viewModel.navigateToLearnSubscription(); await viewModel.navigateToLearnSubscription();
} }
} else { } else {
await viewModel.pause();
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
}*/ }*/
} }

View File

@ -17,6 +17,7 @@ import 'learn_module_viewmodel.dart';
class LearnModuleView extends StackedView<LearnModuleViewModel> { class LearnModuleView extends StackedView<LearnModuleViewModel> {
final LearnCourse course; final LearnCourse course;
const LearnModuleView({Key? key, required this.course}) : super(key: key); const LearnModuleView({Key? key, required this.course}) : super(key: key);
Future<void> _onPractice( Future<void> _onPractice(
@ -27,17 +28,31 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
await viewModel.navigateToLearnPractice( await viewModel.navigateToLearnPractice(
id: module.id ?? 0, module: module.name ?? ''); id: module.id ?? 0, module: module.name ?? '');
} else { } else {
await _showSheet(context: context, viewModel: viewModel); if (module.access?.isAccessible ?? false) {
print('Accessible');
await _showSheet(
context: context,
viewModel: viewModel,
practice: PracticeReason.module);
} else {
print('Inaccessible');
await _showSheet(
context: context,
viewModel: viewModel,
practice: PracticeReason.previousModule);
}
} }
} }
Future<void> _showSheet( Future<void> _showSheet(
{required BuildContext context, {required BuildContext context,
required PracticeReason practice,
required LearnModuleViewModel viewModel}) async => required LearnModuleViewModel viewModel}) async =>
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
backgroundColor: kcTransparent, backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel), builder: (_) => _buildSheet(viewModel: viewModel, practice: practice),
); );
@override @override
@ -201,6 +216,11 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
onModuleTap: onModuleTap, onModuleTap: onModuleTap,
onPracticeTap: onPracticeTap); onPracticeTap: onPracticeTap);
Widget _buildSheet(LearnModuleViewModel viewModel) => Widget _buildSheet(
FinishPracticeSheet(onTap: viewModel.pop); {required PracticeReason practice,
required LearnModuleViewModel viewModel}) =>
FinishPracticeSheet(
practice: practice,
onTap: viewModel.pop,
);
} }

View File

@ -31,6 +31,10 @@ class LearnSubscriptionViewModel extends FormViewModel {
int get selectedIndex => _selectedIndex; int get selectedIndex => _selectedIndex;
LearnSubscription? _selectedSubscription;
LearnSubscription? get selectedSubscription => _selectedSubscription;
List<LearnSubscription> _subscriptions = []; List<LearnSubscription> _subscriptions = [];
List<LearnSubscription> get subscriptions => _subscriptions; List<LearnSubscription> get subscriptions => _subscriptions;
@ -40,6 +44,13 @@ class LearnSubscriptionViewModel extends FormViewModel {
_focusPhoneNumber = true; _focusPhoneNumber = true;
rebuildUi(); rebuildUi();
} }
//Learn subscriptions
void setSelectedPricing(int index) {
_selectedIndex = index;
_selectedSubscription = _subscriptions[index];
rebuildUi();
}
// In-app navigation // In-app navigation
@ -60,16 +71,11 @@ class LearnSubscriptionViewModel extends FormViewModel {
// Navigation // Navigation
void pop() => _navigationService.back(); void pop() => _navigationService.back();
Future<void> navigateToArifPay(String phone) async { Future<void> navigateToArifPay(
{required String phone, required LearnSubscription? subscription}) async {
pop(); pop();
await _navigationService.navigateToArifPayView(phone: phone); await _navigationService.navigateToPaymentView(
} phone: phone, subscription: subscription ?? _subscriptions[0]);
//Learn subscriptions
void setSelectedPricing(int index) {
_selectedIndex = index;
rebuildUi();
} }
// Remote api call // Remote api call

View File

@ -178,8 +178,9 @@ class LearnSubscriptionFormScreen
? kcPrimaryColor ? kcPrimaryColor
: kcPrimaryColor.withOpacity(0.1), : kcPrimaryColor.withOpacity(0.1),
onTap: phoneNumberController.text.isNotEmpty onTap: phoneNumberController.text.isNotEmpty
? () async => ? () async => await viewModel.navigateToArifPay(
await viewModel.navigateToArifPay(phoneNumberController.text) phone: phoneNumberController.text,
subscription: viewModel.selectedSubscription)
: null, : null,
); );

View File

@ -8,8 +8,8 @@ import 'package:yimaru_app/ui/views/onboarding/screens/country_region_form_scree
import 'package:yimaru_app/ui/views/onboarding/screens/educational_background_form_screen.dart'; import 'package:yimaru_app/ui/views/onboarding/screens/educational_background_form_screen.dart';
import 'package:yimaru_app/ui/views/onboarding/screens/full_name_form_screen.dart'; import 'package:yimaru_app/ui/views/onboarding/screens/full_name_form_screen.dart';
import 'package:yimaru_app/ui/views/onboarding/screens/gender_form_screen.dart'; import 'package:yimaru_app/ui/views/onboarding/screens/gender_form_screen.dart';
import 'package:yimaru_app/ui/views/onboarding/screens/language_goal_form_screen.dart';
import 'package:yimaru_app/ui/views/onboarding/screens/learning_goal_form_screen.dart'; import 'package:yimaru_app/ui/views/onboarding/screens/learning_goal_form_screen.dart';
import 'package:yimaru_app/ui/views/onboarding/screens/language_goal_form_screen.dart';
import 'package:yimaru_app/ui/views/onboarding/screens/occupation_form_screen.dart'; import 'package:yimaru_app/ui/views/onboarding/screens/occupation_form_screen.dart';
import 'package:yimaru_app/ui/views/onboarding/screens/topic_form_screen.dart'; import 'package:yimaru_app/ui/views/onboarding/screens/topic_form_screen.dart';
@ -129,9 +129,9 @@ class OnboardingView extends StackedView<OnboardingViewModel>
Widget _buildCountryRegionForm() => Widget _buildCountryRegionForm() =>
CountryRegionFormScreen(regionController: regionController); CountryRegionFormScreen(regionController: regionController);
Widget _buildLearningGoalForm() => const LearningGoalFormScreen(); Widget _buildLearningGoalForm() => const LanguageGoalFormScreens();
Widget _buildLanguageGoalForm() => const LanguageGoalFormScreen(); Widget _buildLanguageGoalForm() => const LearningGoalFormScreen();
Widget _buildChallengeForm() => const ChallengeFormScreen(); Widget _buildChallengeForm() => const ChallengeFormScreen();

View File

@ -243,8 +243,7 @@ class OnboardingViewModel extends ReactiveViewModel
bool isSelectedLearningGoal(FieldOption value) => bool isSelectedLearningGoal(FieldOption value) =>
_selectedLearningGoal == value; _selectedLearningGoal == value;
// Learning reason // Language goal
void setSelectedLanguageGoal(FieldOption value) { void setSelectedLanguageGoal(FieldOption value) {
_selectedLanguageGoal = value; _selectedLanguageGoal = value;

View File

@ -41,11 +41,8 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildColumnScroller(viewModel)); Expanded(child: _buildColumnScroller(viewModel));
@ -76,7 +73,7 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -42,11 +42,8 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildBodyScroller(viewModel)); Expanded(child: _buildBodyScroller(viewModel));
@ -77,7 +74,7 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -58,11 +58,8 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildBodyWrapper(viewModel)); Expanded(child: _buildBodyWrapper(viewModel));
@ -93,7 +90,7 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -43,11 +43,8 @@ class EducationalBackgroundFormScreen
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildColumnScroller(viewModel)); Expanded(child: _buildColumnScroller(viewModel));
@ -78,7 +75,7 @@ class EducationalBackgroundFormScreen
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -40,11 +40,8 @@ class FullNameFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildBodyWrapper(viewModel)); Expanded(child: _buildBodyWrapper(viewModel));
@ -75,7 +72,7 @@ class FullNameFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -40,11 +40,8 @@ class GenderFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildBodyWrapper(viewModel)); Expanded(child: _buildBodyWrapper(viewModel));
@ -70,7 +67,7 @@ class GenderFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -1,16 +1,41 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:iconsax/iconsax.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:yimaru_app/ui/common/app_colors.dart'; import 'package:yimaru_app/ui/common/app_colors.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import 'package:yimaru_app/ui/common/ui_helpers.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart';
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart'; import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart'; import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart'; import 'package:yimaru_app/ui/widgets/custom_large_radio_button.dart';
import 'package:yimaru_app/ui/widgets/large_app_bar.dart'; import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> { class LanguageGoalFormScreens extends ViewModelWidget<OnboardingViewModel> {
const LanguageGoalFormScreen({super.key}); const LanguageGoalFormScreens({super.key});
IconData getIcon(int index) {
switch (index) {
case 0:
return Iconsax.book;
case 1:
return Iconsax.microphone;
case 2:
return Iconsax.bag;
}
return Icons.book;
}
String getSubtitle(int index) {
switch (index) {
case 0:
return 'I know some English, but i want to learn to speak it';
case 1:
return 'I already speak English, but I want more practice.';
case 2:
return 'I want courses for IELTS, TOEFL, Duolingo, or work';
}
return '';
}
void _pop(OnboardingViewModel viewModel) { void _pop(OnboardingViewModel viewModel) {
viewModel.resetLanguageGoalFormScreen(); viewModel.resetLanguageGoalFormScreen();
@ -42,11 +67,8 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildBodyScroller(viewModel)); Expanded(child: _buildBodyScroller(viewModel));
@ -77,13 +99,10 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceLarge,
_buildTitle(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildTitle(), _buildLanguageGoals(viewModel)
verticalSpaceSmall,
_buildSubtitle(),
verticalSpaceMedium,
_buildReasons(viewModel),
verticalSpaceMedium,
]; ];
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar( Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
@ -96,22 +115,26 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
: viewModel.selectedLanguage['code'], : viewModel.selectedLanguage['code'],
); );
Widget _buildTitle() => Text( Widget _buildTitle(OnboardingViewModel viewModel) => Text.rich(
LocaleKeys.language_goal.tr(), TextSpan(
style: style25DG600, text:
'${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},',
style: style18P600.copyWith(fontSize: 22),
children: [
TextSpan(
text: ' ${LocaleKeys.language_goal.tr()}',
style: style16DG600.copyWith(fontSize: 22),
)
]),
); );
Widget _buildSubtitle() => Text( Widget _buildLanguageGoals(OnboardingViewModel viewModel) => ListView.builder(
LocaleKeys.your_goal.tr(),
style: style14MG400,
);
Widget _buildReasons(OnboardingViewModel viewModel) => ListView.builder(
shrinkWrap: true, shrinkWrap: true,
padding: EdgeInsets.zero,
itemCount: viewModel.languageGoals.length, itemCount: viewModel.languageGoals.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildLanguageGoal( itemBuilder: (context, index) => _buildLanguageGoal(
icon: getIcon(index),
subtitle: getSubtitle(index),
title: viewModel.languageGoals[index].label ?? '', title: viewModel.languageGoals[index].label ?? '',
selected: selected:
viewModel.isSelectedLanguageGoal(viewModel.languageGoals[index]), viewModel.isSelectedLanguageGoal(viewModel.languageGoals[index]),
@ -123,10 +146,14 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
Widget _buildLanguageGoal( Widget _buildLanguageGoal(
{required String title, {required String title,
required bool selected, required bool selected,
required IconData icon,
required String subtitle,
required GestureTapCallback onTap}) => required GestureTapCallback onTap}) =>
CustomSmallRadioButton( CustomLargeRadioButton(
icon: icon,
title: title, title: title,
onTap: onTap, onTap: onTap,
subtitle: subtitle,
selected: selected, selected: selected,
); );
@ -146,5 +173,6 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
: null, : null,
backgroundColor: viewModel.selectedLanguageGoal != null backgroundColor: viewModel.selectedLanguageGoal != null
? kcPrimaryColor ? kcPrimaryColor
: kcPrimaryColor.withOpacity(0.1)); : kcPrimaryColor.withOpacity(0.1),
);
} }

View File

@ -1,54 +1,17 @@
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:iconsax/iconsax.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:yimaru_app/ui/common/app_colors.dart'; import 'package:yimaru_app/ui/common/app_colors.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import 'package:yimaru_app/ui/common/ui_helpers.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart';
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart'; import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart'; import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
import 'package:yimaru_app/ui/widgets/custom_large_radio_button.dart'; import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
import 'package:yimaru_app/ui/widgets/large_app_bar.dart'; import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> { class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
const LearningGoalFormScreen({super.key}); const LearningGoalFormScreen({super.key});
IconData getIcon(int index) {
switch (index) {
case 0:
return Iconsax.book;
case 1:
return Iconsax.microphone;
case 2:
return Iconsax.bag;
}
return Icons.book;
}
String getTitles(int index) {
switch (index) {
case 0:
return 'Learn to Speak English';
case 1:
return 'Practice Speaking English';
case 2:
return 'Skill-based Courses';
}
return '';
}
String getSubtitle(int index) {
switch (index) {
case 0:
return 'I know some English, but i want to learn to speak it';
case 1:
return 'I already speak English, but I want more practice.';
case 2:
return 'I want courses for IELTS, TOEFL, Duolingo, or work';
}
return '';
}
void _pop(OnboardingViewModel viewModel) { void _pop(OnboardingViewModel viewModel) {
viewModel.resetLearningGoalFormScreen(); viewModel.resetLearningGoalFormScreen();
viewModel.goBack(); viewModel.goBack();
@ -79,11 +42,8 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildBodyScroller(viewModel)); Expanded(child: _buildBodyScroller(viewModel));
@ -114,10 +74,13 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceLarge,
_buildTitle(),
verticalSpaceSmall,
_buildSubtitle(),
verticalSpaceMedium, verticalSpaceMedium,
_buildTitle(viewModel), _buildGoals(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildLearningGoals(viewModel)
]; ];
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar( Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
@ -130,27 +93,23 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
: viewModel.selectedLanguage['code'], : viewModel.selectedLanguage['code'],
); );
Widget _buildTitle(OnboardingViewModel viewModel) => Text.rich( Widget _buildTitle() => Text(
TextSpan( LocaleKeys.learning_goal.tr(),
text: style: style25DG600,
'${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},',
style: style18P600.copyWith(fontSize: 22),
children: [
TextSpan(
text: ' ${LocaleKeys.learning_goal.tr()}',
style: style16DG600.copyWith(fontSize: 22),
)
]),
); );
Widget _buildLearningGoals(OnboardingViewModel viewModel) => ListView.builder( Widget _buildSubtitle() => Text(
LocaleKeys.your_goal.tr(),
style: style14MG400,
);
Widget _buildGoals(OnboardingViewModel viewModel) => ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: 3, // viewModel.learningGoals.length, padding: EdgeInsets.zero,
itemCount: viewModel.learningGoals.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildLearningGoal( itemBuilder: (context, index) => _buildLearningGoal(
icon: getIcon(index), title: viewModel.learningGoals[index].label ?? '',
title: getTitles(index),
subtitle: getSubtitle(index),
selected: selected:
viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]), viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]),
onTap: () => onTap: () =>
@ -161,14 +120,10 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
Widget _buildLearningGoal( Widget _buildLearningGoal(
{required String title, {required String title,
required bool selected, required bool selected,
required IconData icon,
required String subtitle,
required GestureTapCallback onTap}) => required GestureTapCallback onTap}) =>
CustomLargeRadioButton( CustomSmallRadioButton(
icon: icon,
title: title, title: title,
onTap: onTap, onTap: onTap,
subtitle: subtitle,
selected: selected, selected: selected,
); );
@ -188,6 +143,5 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
: null, : null,
backgroundColor: viewModel.selectedLearningGoal != null backgroundColor: viewModel.selectedLearningGoal != null
? kcPrimaryColor ? kcPrimaryColor
: kcPrimaryColor.withOpacity(0.1), : kcPrimaryColor.withOpacity(0.1));
);
} }

View File

@ -43,11 +43,8 @@ class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildExpandedBody(OnboardingViewModel viewModel) => Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
Expanded(child: _buildBodyWrapper(viewModel)); Expanded(child: _buildBodyWrapper(viewModel));
@ -78,7 +75,7 @@ class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -45,11 +45,8 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
_buildAppBar(viewModel), [_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
verticalSpaceMedium,
_buildExpandedBody(viewModel)
];
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar( Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
showBackButton: true, showBackButton: true,
@ -90,7 +87,7 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
verticalSpaceMedium, verticalSpaceLarge,
_buildTitle(), _buildTitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildSubtitle(), _buildSubtitle(),

View File

@ -1,55 +1,61 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:yimaru_app/ui/common/app_constants.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/common/ui_helpers.dart';
import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart';
import 'arif_pay_viewmodel.dart'; import '../../../models/learn_subscription.dart';
import '../../common/app_constants.dart';
import '../../common/enmus.dart';
import '../../common/ui_helpers.dart';
import '../../widgets/page_loading_indicator.dart';
import 'payment_viewmodel.dart';
class ArifPayView extends StackedView<ArifPayViewModel> { class PaymentView extends StackedView<PaymentViewModel> {
final String phone; final String phone;
final LearnSubscription subscription;
const ArifPayView({Key? key, required this.phone}) : super(key: key); const PaymentView({Key? key, required this.phone, required this.subscription})
: super(key: key);
void _error(ArifPayViewModel viewModel) => viewModel.pop(); void _error(PaymentViewModel viewModel) => viewModel.pop();
Future<void> _success(ArifPayViewModel viewModel) async { Future<void> _success(PaymentViewModel viewModel) async {
await viewModel.updatePaymentStatus(); await viewModel.updatePaymentStatus();
await viewModel.replaceWithHome(); await viewModel.replaceWithHome();
} }
@override @override
void onViewModelReady(ArifPayViewModel viewModel) async { void onViewModelReady(PaymentViewModel viewModel) async {
await viewModel.createLearnSubscriptionRequest(phone); await viewModel.createLearnSubscriptionRequest(phone: phone,subscription: subscription);
super.onViewModelReady(viewModel); super.onViewModelReady(viewModel);
} }
@override @override
ArifPayViewModel viewModelBuilder(BuildContext context) => ArifPayViewModel(); PaymentViewModel viewModelBuilder(
BuildContext context,
) =>
PaymentViewModel();
@override @override
Widget builder( Widget builder(
BuildContext context, BuildContext context,
ArifPayViewModel viewModel, PaymentViewModel viewModel,
Widget? child, Widget? child,
) => ) =>
_buildScaffoldWrapper(viewModel); _buildScaffoldWrapper(viewModel);
Widget _buildScaffoldWrapper(ArifPayViewModel viewModel) => Widget _buildScaffoldWrapper(PaymentViewModel viewModel) =>
Scaffold(body: _buildScaffoldState(viewModel)); Scaffold(body: _buildScaffoldState(viewModel));
Widget _buildScaffoldState(ArifPayViewModel viewModel) => Widget _buildScaffoldState(PaymentViewModel viewModel) =>
viewModel.busy(StateObjects.learnSubscription) viewModel.busy(StateObjects.learnSubscription)
? const PageLoadingIndicator() ? const PageLoadingIndicator()
: _buildScaffold(viewModel); : _buildScaffold(viewModel);
Widget _buildScaffold(ArifPayViewModel viewModel) => Widget _buildScaffold(PaymentViewModel viewModel) =>
SafeArea(child: _buildBody(viewModel)); SafeArea(child: _buildBody(viewModel));
Widget _buildBody(ArifPayViewModel viewModel) => InAppWebView( Widget _buildBody(PaymentViewModel viewModel) => InAppWebView(
initialUrlRequest: initialUrlRequest:
URLRequest(url: WebUri(viewModel.request?.paymentUrl ?? '')), URLRequest(url: WebUri(viewModel.request?.paymentUrl ?? '')),
onUpdateVisitedHistory: (controller, url, androidIsReload) async { onUpdateVisitedHistory: (controller, url, androidIsReload) async {

View File

@ -1,17 +1,17 @@
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../app/app.locator.dart'; import '../../../app/app.locator.dart';
import '../../../app/app.router.dart'; import '../../../app/app.router.dart';
import '../../../models/learn_subscription.dart';
import '../../../models/learn_subscription_request.dart'; import '../../../models/learn_subscription_request.dart';
import '../../../models/user.dart'; import '../../../models/user.dart';
import '../../../services/api_service.dart'; import '../../../services/api_service.dart';
import '../../../services/authentication_service.dart'; import '../../../services/authentication_service.dart';
import '../../../services/status_checker_service.dart'; import '../../../services/status_checker_service.dart';
import '../../common/ui_helpers.dart'; import '../../common/enmus.dart';
class ArifPayViewModel extends ReactiveViewModel { class PaymentViewModel extends ReactiveViewModel {
// Dependency injection // Dependency injection
final _apiService = locator<ApiService>(); final _apiService = locator<ApiService>();
@ -30,6 +30,7 @@ class ArifPayViewModel extends ReactiveViewModel {
User? get _user => _authenticationService.user; User? get _user => _authenticationService.user;
User? get user => _user; User? get user => _user;
// Learn subscription request // Learn subscription request
LearnSubscriptionRequest? _request; LearnSubscriptionRequest? _request;
@ -44,18 +45,18 @@ class ArifPayViewModel extends ReactiveViewModel {
// Remote api call // Remote api call
// Learn subscription // Learn subscription
Future<void> createLearnSubscriptionRequest(String phone) async => Future<void> createLearnSubscriptionRequest({required String phone,required LearnSubscription subscription}) async =>
await runBusyFuture(_createLearnSubscriptionRequest(phone), await runBusyFuture(_createLearnSubscriptionRequest(phone: phone,subscription: subscription),
busyObject: StateObjects.learnSubscription); busyObject: StateObjects.learnSubscription);
Future<void> _createLearnSubscriptionRequest(String phone) async { Future<void> _createLearnSubscriptionRequest({required String phone,required LearnSubscription subscription}) async {
print('MY SUMMARIES : PAYMENT');
if (await _statusChecker.checkConnection()) { if (await _statusChecker.checkConnection()) {
Map<String, dynamic> data = { Map<String, dynamic> data = {
'plan_id': 1, 'provider': 'CHAPA',
'phone': '251$phone', 'phone': '251$phone',
'provider': 'ARIFPAY',
'email': 'test@gmail.com', 'email': 'test@gmail.com',
'plan_id': subscription.id,
}; };
Map<String, dynamic> response = Map<String, dynamic> response =

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:yimaru_app/models/course_lesson.dart'; import 'package:yimaru_app/models/course_lesson.dart';
import 'package:yimaru_app/models/course_module.dart'; import 'package:yimaru_app/models/course_module.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/views/course_module/course_module_viewmodel.dart'; import 'package:yimaru_app/ui/views/course_module/course_module_viewmodel.dart';
import 'package:yimaru_app/ui/widgets/course_lesson_tile.dart'; import 'package:yimaru_app/ui/widgets/course_lesson_tile.dart';
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart'; import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
@ -182,6 +183,7 @@ class CourseModuleTileLarge extends ViewModelWidget<CourseModuleViewModel> {
Widget _buildSheet(CourseModuleViewModel viewModel) => FinishPracticeSheet( Widget _buildSheet(CourseModuleViewModel viewModel) => FinishPracticeSheet(
onTap: viewModel.pop, onTap: viewModel.pop,
practice: PracticeReason.lesson,
); );
Widget _buildCourseModules(CourseModuleViewModel viewModel) => Widget _buildCourseModules(CourseModuleViewModel viewModel) =>

View File

@ -8,6 +8,7 @@ import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart';
import '../../models/course_catalog.dart'; import '../../models/course_catalog.dart';
import '../common/app_colors.dart'; import '../common/app_colors.dart';
import '../common/enmus.dart';
import '../common/ui_helpers.dart'; import '../common/ui_helpers.dart';
import '../views/course_unit/course_unit_viewmodel.dart'; import '../views/course_unit/course_unit_viewmodel.dart';
import 'custom_circular_progress_indicator.dart'; import 'custom_circular_progress_indicator.dart';
@ -228,6 +229,7 @@ class CourseUnitTile extends ViewModelWidget<CourseUnitViewModel> {
Widget _buildSheet(CourseUnitViewModel viewModel) => FinishPracticeSheet( Widget _buildSheet(CourseUnitViewModel viewModel) => FinishPracticeSheet(
onTap: viewModel.pop, onTap: viewModel.pop,
practice: PracticeReason.course,
); );
Widget _buildCourseModulesState(CourseUnitViewModel viewModel) => Widget _buildCourseModulesState(CourseUnitViewModel viewModel) =>
@ -240,6 +242,7 @@ class CourseUnitTile extends ViewModelWidget<CourseUnitViewModel> {
width: double.maxFinite, width: double.maxFinite,
child: _buildProgressIndicator(), child: _buildProgressIndicator(),
); );
Widget _buildProgressIndicator() => const Center( Widget _buildProgressIndicator() => const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor), child: CustomCircularProgressIndicator(color: kcPrimaryColor),
); );

View File

@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:yimaru_app/ui/common/app_colors.dart'; import 'package:yimaru_app/ui/common/app_colors.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import 'package:yimaru_app/ui/common/ui_helpers.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart';
import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart'; import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart';
@ -9,9 +10,24 @@ import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart';
import 'custom_elevated_button.dart'; import 'custom_elevated_button.dart';
class FinishPracticeSheet extends StatelessWidget { class FinishPracticeSheet extends StatelessWidget {
final PracticeReason practice;
final GestureTapCallback? onTap; final GestureTapCallback? onTap;
const FinishPracticeSheet({super.key, this.onTap}); const FinishPracticeSheet({super.key, this.onTap, required this.practice});
String getWarning() {
if (practice == PracticeReason.lesson) {
return LocaleKeys.finish_all_practice_lesson.tr();
} else if (practice == PracticeReason.module) {
return LocaleKeys.finish_all_practice_module.tr();
} else if (practice == PracticeReason.previousModule) {
return LocaleKeys.finish_all_practice_previouse_module.tr();
} else if (practice == PracticeReason.previousCourse) {
return LocaleKeys.finish_all_practice_previouse_course.tr();
} else {
return LocaleKeys.finish_all_practice_course.tr();
}
}
@override @override
Widget build(BuildContext context) => _buildSheetWrapper(); Widget build(BuildContext context) => _buildSheetWrapper();
@ -44,7 +60,7 @@ class FinishPracticeSheet extends StatelessWidget {
); );
Widget _buildMessage() => Text( Widget _buildMessage() => Text(
LocaleKeys.finish_all_practice.tr(), getWarning(),
style: style16DG600, style: style16DG600,
textAlign: TextAlign.center, textAlign: TextAlign.center,
); );

View File

@ -24,7 +24,13 @@ class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
@override @override
Widget build(BuildContext context, LearnCourseViewModel viewModel) => Widget build(BuildContext context, LearnCourseViewModel viewModel) =>
_buildExpansionTileCard(viewModel); _buildExpansionTileCardWrapper(viewModel);
Widget _buildExpansionTileCardWrapper(LearnCourseViewModel viewModel) =>
GestureDetector(
onTap: !(course.access?.isAccessible ?? false) ? onPracticeTap : null,
child: _buildExpansionTileCard(viewModel),
);
Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container( Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container(
margin: const EdgeInsets.only(bottom: 15), margin: const EdgeInsets.only(bottom: 15),

View File

@ -16,6 +16,7 @@ import 'custom_linear_progress_indicator.dart';
class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> { class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
final int index; final int index;
final bool last;
final LearnLesson lesson; final LearnLesson lesson;
final GestureTapCallback? onLessonTap; final GestureTapCallback? onLessonTap;
final GestureTapCallback? onPracticeTap; final GestureTapCallback? onPracticeTap;
@ -24,6 +25,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
{super.key, {super.key,
this.onLessonTap, this.onLessonTap,
this.onPracticeTap, this.onPracticeTap,
required this.last,
required this.index, required this.index,
required this.lesson}); required this.lesson});
@ -31,10 +33,12 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
Widget build(BuildContext context, LearnLessonViewModel viewModel) => Widget build(BuildContext context, LearnLessonViewModel viewModel) =>
_buildContainerWrapper(viewModel); _buildContainerWrapper(viewModel);
Widget _buildContainerWrapper(LearnLessonViewModel viewModel)=> GestureDetector( Widget _buildContainerWrapper(LearnLessonViewModel viewModel) =>
GestureDetector(
onTap: !(lesson.access?.isAccessible ?? false) ? onPracticeTap : null, onTap: !(lesson.access?.isAccessible ?? false) ? onPracticeTap : null,
child: _buildContainer(viewModel), child: _buildContainer(viewModel),
); );
Widget _buildContainer(LearnLessonViewModel viewModel) => Container( Widget _buildContainer(LearnLessonViewModel viewModel) => Container(
width: double.maxFinite, width: double.maxFinite,
margin: const EdgeInsets.only(bottom: 15), margin: const EdgeInsets.only(bottom: 15),
@ -70,12 +74,14 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
controlAffinity: ListTileControlAffinity.trailing, controlAffinity: ListTileControlAffinity.trailing,
expandedCrossAxisAlignment: CrossAxisAlignment.start, expandedCrossAxisAlignment: CrossAxisAlignment.start,
tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 15), tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
backgroundColor: (lesson.access?.isCompleted ?? false)
? kcGreen.withOpacity(0.1)
: kcPrimaryColor.withOpacity(0.1),
childrenPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15), childrenPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15),
initiallyExpanded: (lesson.access?.isAccessible ?? false) && initiallyExpanded: (lesson.access?.isAccessible ?? false) &&
!(lesson.access?.isCompleted ?? false), !(lesson.access?.isCompleted ?? false),
backgroundColor: last && (lesson.access?.isAccessible ?? false)
? kcGreen.withOpacity(0.1)
: (lesson.access?.isCompleted ?? false)
? kcGreen.withOpacity(0.1)
: kcPrimaryColor.withOpacity(0.1),
collapsedBackgroundColor: (lesson.access?.isCompleted ?? false) collapsedBackgroundColor: (lesson.access?.isCompleted ?? false)
? kcGreen.withOpacity(0.1) ? kcGreen.withOpacity(0.1)
: kcPrimaryColor.withOpacity(0.1), : kcPrimaryColor.withOpacity(0.1),
@ -92,7 +98,9 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
style: style16DG600, style: style16DG600,
); );
Widget _buildIconState() => (lesson.access?.isCompleted ?? false) Widget _buildIconState() => last && (lesson.access?.isAccessible ?? false)
? _buildCompleteIcon()
: (lesson.access?.isCompleted ?? false)
? _buildCompleteIcon() ? _buildCompleteIcon()
: _buildPendingIcon(); : _buildPendingIcon();
@ -128,11 +136,15 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
Widget _buildProgress() => CustomLinearProgressIndicator( Widget _buildProgress() => CustomLinearProgressIndicator(
activeColor: kcPrimaryColor, activeColor: kcPrimaryColor,
backgroundColor: kcVeryLightGrey, backgroundColor: kcVeryLightGrey,
progress: (lesson.access?.progressPercent ?? 0) / 100, progress: last && (lesson.access?.isAccessible ?? false)
? 1
: (lesson.access?.progressPercent ?? 0) / 100,
); );
Widget _buildProgressText() => Text( Widget _buildProgressText() => Text(
(lesson.access?.isCompleted ?? false) last && (lesson.access?.isAccessible ?? false)
? LocaleKeys.completed.tr()
: (lesson.access?.isCompleted ?? false)
? LocaleKeys.completed.tr() ? LocaleKeys.completed.tr()
: LocaleKeys.in_progress.tr(), : LocaleKeys.in_progress.tr(),
style: style14P600, style: style14P600,

View File

@ -23,8 +23,15 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
@override @override
Widget build(BuildContext context, LearnModuleViewModel viewModel) => Widget build(BuildContext context, LearnModuleViewModel viewModel) =>
_buildExpansionTileCard(context: context, viewModel: viewModel); _buildExpansionTileCardWrapper(context: context, viewModel: viewModel);
Widget _buildExpansionTileCardWrapper(
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
GestureDetector(
onTap: !(module.access?.isAccessible ?? false) ? onPracticeTap : null,
child: _buildExpansionTileCard(context: context, viewModel: viewModel),
);
Widget _buildExpansionTileCard( Widget _buildExpansionTileCard(
{required BuildContext context, {required BuildContext context,
required LearnModuleViewModel viewModel}) => required LearnModuleViewModel viewModel}) =>

View File

@ -1,5 +1,5 @@
name: yimaru_app name: yimaru_app
version: 0.1.28+31 version: 0.1.30+32
publish_to: 'none' publish_to: 'none'
description: A new Flutter project. description: A new Flutter project.

View File

@ -4,7 +4,7 @@ import 'package:yimaru_app/app/app.locator.dart';
import '../helpers/test_helpers.dart'; import '../helpers/test_helpers.dart';
void main() { void main() {
group('ArifPayViewModel Tests -', () { group('PaymentViewModel Tests -', () {
setUp(() => registerServices()); setUp(() => registerServices());
tearDown(() => locator.reset()); tearDown(() => locator.reset());
}); });