diff --git a/android/app/google-services.json b/android/app/google-services.json index a783b3b..703b089 100644 --- a/android/app/google-services.json +++ b/android/app/google-services.json @@ -14,11 +14,27 @@ }, "oauth_client": [ { - "client_id": "900714037062-ngc0gc426sfnnjjr494g4vni46ne5uqv.apps.googleusercontent.com", + "client_id": "900714037062-4trqu7ln6en4kcm6gadk0uo01qijn1mk.apps.googleusercontent.com", "client_type": 1, "android_info": { "package_name": "com.yimaru.lms.app", - "certificate_hash": "139ee56ac9763191d1eee882efc440c10530e6e9" + "certificate_hash": "b9cb22406df59b3b9b210896cc10fc704cc25858" + } + }, + { + "client_id": "900714037062-d9aqa2eoni3ppumdpi39d5rtub2bsbbs.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.yimaru.lms.app", + "certificate_hash": "29797902ad6a24212b9d9fad71562907956f6a6c" + } + }, + { + "client_id": "900714037062-ok9oeme95rfcvljtg065aj0f7mmsr0fa.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "com.yimaru.lms.app", + "certificate_hash": "928ead08b5e39d6a861a55ae7cceb8c402d1ee7a" } }, { diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html index 84a82f1..fe0449f 100644 --- a/android/build/reports/problems/problems-report.html +++ b/android/build/reports/problems/problems-report.html @@ -646,7 +646,7 @@ code + .copy-button { diff --git a/lib/app/app.bottomsheets.dart b/lib/app/app.bottomsheets.dart index 777004c..bc4ed33 100644 --- a/lib/app/app.bottomsheets.dart +++ b/lib/app/app.bottomsheets.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedBottomsheetGenerator diff --git a/lib/app/app.dart b/lib/app/app.dart index 3834e90..2ca880b 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -18,8 +18,6 @@ import 'package:yimaru_app/ui/views/privacy_policy/privacy_policy_view.dart'; import 'package:yimaru_app/ui/views/terms_and_conditions/terms_and_conditions_view.dart'; import 'package:yimaru_app/ui/views/register/register_view.dart'; import 'package:yimaru_app/ui/views/login/login_view.dart'; -import 'package:yimaru_app/ui/views/learn/learn_view.dart'; -import 'package:yimaru_app/ui/views/learn_level/learn_level_view.dart'; import 'package:yimaru_app/ui/views/learn_module/learn_module_view.dart'; import 'package:yimaru_app/services/authentication_service.dart'; import 'package:yimaru_app/services/api_service.dart'; @@ -51,8 +49,9 @@ import 'package:yimaru_app/ui/views/course/course_view.dart'; import 'package:yimaru_app/services/audio_player_service.dart'; import 'package:yimaru_app/services/voice_recorder_service.dart'; import 'package:yimaru_app/ui/views/course_practice_question/course_practice_question_view.dart'; -import 'package:yimaru_app/ui/views/learn_subcategory/learn_subcategory_view.dart'; -import 'package:yimaru_app/ui/views/learn_submodule/learn_submodule_view.dart'; +import 'package:yimaru_app/services/in_app_update_service.dart'; +import 'package:yimaru_app/ui/views/learn_program/learn_program_view.dart'; +import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart'; // @stacked-import @StackedApp( @@ -73,8 +72,6 @@ import 'package:yimaru_app/ui/views/learn_submodule/learn_submodule_view.dart'; MaterialRoute(page: TermsAndConditionsView), MaterialRoute(page: RegisterView), MaterialRoute(page: LoginView), - MaterialRoute(page: LearnView), - MaterialRoute(page: LearnLevelView), MaterialRoute(page: LearnModuleView), MaterialRoute(page: WelcomeView), MaterialRoute(page: AssessmentView), @@ -92,8 +89,8 @@ import 'package:yimaru_app/ui/views/learn_submodule/learn_submodule_view.dart'; MaterialRoute(page: CourseSubcategoryView), MaterialRoute(page: CourseView), MaterialRoute(page: CoursePracticeQuestionView), - MaterialRoute(page: LearnSubcategoryView), - MaterialRoute(page: LearnSubmoduleView), + MaterialRoute(page: LearnProgramView), + MaterialRoute(page: LearnCourseView), // @stacked-route ], dependencies: [ @@ -114,6 +111,7 @@ import 'package:yimaru_app/ui/views/learn_submodule/learn_submodule_view.dart'; LazySingleton(classType: CourseService), LazySingleton(classType: AudioPlayerService), LazySingleton(classType: VoiceRecorderService), + LazySingleton(classType: InAppUpdateService), // @stacked-service ], bottomsheets: [ diff --git a/lib/app/app.dialogs.dart b/lib/app/app.dialogs.dart index 2a4e944..b0cf86b 100644 --- a/lib/app/app.dialogs.dart +++ b/lib/app/app.dialogs.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedDialogGenerator diff --git a/lib/app/app.locator.dart b/lib/app/app.locator.dart index 2e05699..2b0bbc7 100644 --- a/lib/app/app.locator.dart +++ b/lib/app/app.locator.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedLocatorGenerator @@ -19,6 +20,7 @@ import '../services/dio_service.dart'; import '../services/google_auth_service.dart'; import '../services/image_downloader_service.dart'; import '../services/image_picker_service.dart'; +import '../services/in_app_update_service.dart'; import '../services/notification_service.dart'; import '../services/permission_handler_service.dart'; import '../services/secure_storage_service.dart'; @@ -28,10 +30,8 @@ import '../services/voice_recorder_service.dart'; final locator = StackedLocator.instance; -Future setupLocator({ - String? environment, - EnvironmentFilter? environmentFilter, -}) async { +Future setupLocator( + {String? environment, EnvironmentFilter? environmentFilter}) async { // Register environments locator.registerEnvironment( environment: environment, environmentFilter: environmentFilter); @@ -54,4 +54,5 @@ Future setupLocator({ locator.registerLazySingleton(() => CourseService()); locator.registerLazySingleton(() => AudioPlayerService()); locator.registerLazySingleton(() => VoiceRecorderService()); + locator.registerLazySingleton(() => InAppUpdateService()); } diff --git a/lib/app/app.router.dart b/lib/app/app.router.dart index feb59cd..2764fc1 100644 --- a/lib/app/app.router.dart +++ b/lib/app/app.router.dart @@ -1,63 +1,62 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedNavigatorGenerator // ************************************************************************** // ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:flutter/material.dart' as _i37; import 'package:flutter/material.dart'; -import 'package:flutter/material.dart' as _i39; import 'package:stacked/stacked.dart' as _i1; -import 'package:stacked_services/stacked_services.dart' as _i48; -import 'package:yimaru_app/models/category.dart' as _i45; -import 'package:yimaru_app/models/course.dart' as _i43; -import 'package:yimaru_app/models/course_lesson.dart' as _i44; -import 'package:yimaru_app/models/lesson.dart' as _i42; -import 'package:yimaru_app/models/level.dart' as _i40; -import 'package:yimaru_app/models/module.dart' as _i47; -import 'package:yimaru_app/models/subcategory.dart' as _i46; -import 'package:yimaru_app/models/submodule.dart' as _i41; +import 'package:stacked_services/stacked_services.dart' as _i46; +import 'package:yimaru_app/models/category.dart' as _i44; +import 'package:yimaru_app/models/course.dart' as _i42; +import 'package:yimaru_app/models/course_lesson.dart' as _i43; +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_module.dart' as _i39; +import 'package:yimaru_app/models/subcategory.dart' as _i45; +import 'package:yimaru_app/ui/common/enmus.dart' as _i41; import 'package:yimaru_app/ui/views/account_privacy/account_privacy_view.dart' as _i9; -import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i22; +import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i20; import 'package:yimaru_app/ui/views/call_support/call_support_view.dart' as _i12; -import 'package:yimaru_app/ui/views/course/course_view.dart' as _i35; +import 'package:yimaru_app/ui/views/course/course_view.dart' as _i33; import 'package:yimaru_app/ui/views/course_category/course_category_view.dart' - as _i29; -import 'package:yimaru_app/ui/views/course_lesson/course_lesson_view.dart' - as _i31; -import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart' - as _i32; -import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart' - as _i28; -import 'package:yimaru_app/ui/views/course_practice/course_practice_view.dart' as _i27; +import 'package:yimaru_app/ui/views/course_lesson/course_lesson_view.dart' + as _i29; +import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart' + as _i30; +import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart' + as _i26; +import 'package:yimaru_app/ui/views/course_practice/course_practice_view.dart' + as _i25; import 'package:yimaru_app/ui/views/course_practice_question/course_practice_question_view.dart' - as _i36; -import 'package:yimaru_app/ui/views/course_subcategory/course_subcategory_view.dart' as _i34; +import 'package:yimaru_app/ui/views/course_subcategory/course_subcategory_view.dart' + as _i32; import 'package:yimaru_app/ui/views/downloads/downloads_view.dart' as _i7; -import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart' as _i33; -import 'package:yimaru_app/ui/views/failure/failure_view.dart' as _i30; +import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart' as _i31; +import 'package:yimaru_app/ui/views/failure/failure_view.dart' as _i28; import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart' - as _i24; + as _i22; import 'package:yimaru_app/ui/views/home/home_view.dart' as _i2; import 'package:yimaru_app/ui/views/language/language_view.dart' as _i13; -import 'package:yimaru_app/ui/views/learn/learn_view.dart' as _i18; +import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart' + as _i36; import 'package:yimaru_app/ui/views/learn_lesson/learn_lesson_view.dart' - as _i23; + as _i21; import 'package:yimaru_app/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart' - as _i25; -import 'package:yimaru_app/ui/views/learn_level/learn_level_view.dart' as _i19; + as _i23; import 'package:yimaru_app/ui/views/learn_module/learn_module_view.dart' - as _i20; + as _i18; import 'package:yimaru_app/ui/views/learn_practice/learn_practice_view.dart' - as _i26; -import 'package:yimaru_app/ui/views/learn_subcategory/learn_subcategory_view.dart' - as _i37; -import 'package:yimaru_app/ui/views/learn_submodule/learn_submodule_view.dart' - as _i38; + as _i24; +import 'package:yimaru_app/ui/views/learn_program/learn_program_view.dart' + as _i35; 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/privacy_policy/privacy_policy_view.dart' @@ -73,7 +72,7 @@ import 'package:yimaru_app/ui/views/telegram_support/telegram_support_view.dart' as _i11; import 'package:yimaru_app/ui/views/terms_and_conditions/terms_and_conditions_view.dart' as _i15; -import 'package:yimaru_app/ui/views/welcome/welcome_view.dart' as _i21; +import 'package:yimaru_app/ui/views/welcome/welcome_view.dart' as _i19; class Routes { static const homeView = '/home-view'; @@ -108,10 +107,6 @@ class Routes { static const loginView = '/login-view'; - static const learnView = '/learn-view'; - - static const learnLevelView = '/learn-level-view'; - static const learnModuleView = '/learn-module-view'; static const welcomeView = '/welcome-view'; @@ -146,9 +141,9 @@ class Routes { static const coursePracticeQuestionView = '/course-practice-question-view'; - static const learnSubcategoryView = '/learn-subcategory-view'; + static const learnProgramView = '/learn-program-view'; - static const learnSubmoduleView = '/learn-submodule-view'; + static const learnCourseView = '/learn-course-view'; static const all = { homeView, @@ -167,8 +162,6 @@ class Routes { termsAndConditionsView, registerView, loginView, - learnView, - learnLevelView, learnModuleView, welcomeView, assessmentView, @@ -186,8 +179,8 @@ class Routes { courseSubcategoryView, courseView, coursePracticeQuestionView, - learnSubcategoryView, - learnSubmoduleView, + learnProgramView, + learnCourseView, }; } @@ -257,102 +250,100 @@ class StackedRouter extends _i1.RouterBase { Routes.loginView, page: _i17.LoginView, ), - _i1.RouteDef( - Routes.learnView, - page: _i18.LearnView, - ), - _i1.RouteDef( - Routes.learnLevelView, - page: _i19.LearnLevelView, - ), _i1.RouteDef( Routes.learnModuleView, - page: _i20.LearnModuleView, + page: _i18.LearnModuleView, ), _i1.RouteDef( Routes.welcomeView, - page: _i21.WelcomeView, + page: _i19.WelcomeView, ), _i1.RouteDef( Routes.assessmentView, - page: _i22.AssessmentView, + page: _i20.AssessmentView, ), _i1.RouteDef( Routes.learnLessonView, - page: _i23.LearnLessonView, + page: _i21.LearnLessonView, ), _i1.RouteDef( Routes.forgetPasswordView, - page: _i24.ForgetPasswordView, + page: _i22.ForgetPasswordView, ), _i1.RouteDef( Routes.learnLessonDetailView, - page: _i25.LearnLessonDetailView, + page: _i23.LearnLessonDetailView, ), _i1.RouteDef( Routes.learnPracticeView, - page: _i26.LearnPracticeView, + page: _i24.LearnPracticeView, ), _i1.RouteDef( Routes.coursePracticeView, - page: _i27.CoursePracticeView, + page: _i25.CoursePracticeView, ), _i1.RouteDef( Routes.coursePaymentView, - page: _i28.CoursePaymentView, + page: _i26.CoursePaymentView, ), _i1.RouteDef( Routes.courseCategoryView, - page: _i29.CourseCategoryView, + page: _i27.CourseCategoryView, ), _i1.RouteDef( Routes.failureView, - page: _i30.FailureView, + page: _i28.FailureView, ), _i1.RouteDef( Routes.courseLessonView, - page: _i31.CourseLessonView, + page: _i29.CourseLessonView, ), _i1.RouteDef( Routes.courseLessonDetailView, - page: _i32.CourseLessonDetailView, + page: _i30.CourseLessonDetailView, ), _i1.RouteDef( Routes.duolingoView, - page: _i33.DuolingoView, + page: _i31.DuolingoView, ), _i1.RouteDef( Routes.courseSubcategoryView, - page: _i34.CourseSubcategoryView, + page: _i32.CourseSubcategoryView, ), _i1.RouteDef( Routes.courseView, - page: _i35.CourseView, + page: _i33.CourseView, ), _i1.RouteDef( Routes.coursePracticeQuestionView, - page: _i36.CoursePracticeQuestionView, + page: _i34.CoursePracticeQuestionView, ), _i1.RouteDef( - Routes.learnSubcategoryView, - page: _i37.LearnSubcategoryView, + Routes.learnProgramView, + page: _i35.LearnProgramView, ), _i1.RouteDef( - Routes.learnSubmoduleView, - page: _i38.LearnSubmoduleView, + Routes.learnCourseView, + page: _i36.LearnCourseView, ), ]; final _pagesMap = { _i2.HomeView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i2.HomeView(), + final args = data.getArgs( + orElse: () => const HomeViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i2.HomeView(key: args.key), settings: data, ); }, _i3.OnboardingView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i3.OnboardingView(), + final args = data.getArgs( + orElse: () => const OnboardingViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i3.OnboardingView(key: args.key), settings: data, ); }, @@ -360,247 +351,282 @@ class StackedRouter extends _i1.RouterBase { final args = data.getArgs( orElse: () => const StartupViewArguments(), ); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => _i4.StartupView(key: args.key, label: args.label), settings: data, ); }, _i5.ProfileView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i5.ProfileView(), + final args = data.getArgs( + orElse: () => const ProfileViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i5.ProfileView(key: args.key), settings: data, ); }, _i6.ProfileDetailView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i6.ProfileDetailView(), + final args = data.getArgs( + orElse: () => const ProfileDetailViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i6.ProfileDetailView(key: args.key), settings: data, ); }, _i7.DownloadsView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i7.DownloadsView(), + final args = data.getArgs( + orElse: () => const DownloadsViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i7.DownloadsView(key: args.key), settings: data, ); }, _i8.ProgressView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i8.ProgressView(), + final args = data.getArgs( + orElse: () => const ProgressViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i8.ProgressView(key: args.key), settings: data, ); }, _i9.AccountPrivacyView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i9.AccountPrivacyView(), + final args = data.getArgs( + orElse: () => const AccountPrivacyViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i9.AccountPrivacyView(key: args.key), settings: data, ); }, _i10.SupportView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i10.SupportView(), + final args = data.getArgs( + orElse: () => const SupportViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i10.SupportView(key: args.key), settings: data, ); }, _i11.TelegramSupportView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i11.TelegramSupportView(), + final args = data.getArgs( + orElse: () => const TelegramSupportViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i11.TelegramSupportView(key: args.key), settings: data, ); }, _i12.CallSupportView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i12.CallSupportView(), + final args = data.getArgs( + orElse: () => const CallSupportViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i12.CallSupportView(key: args.key), settings: data, ); }, _i13.LanguageView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i13.LanguageView(), + final args = data.getArgs( + orElse: () => const LanguageViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i13.LanguageView(key: args.key), settings: data, ); }, _i14.PrivacyPolicyView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i14.PrivacyPolicyView(), + final args = data.getArgs( + orElse: () => const PrivacyPolicyViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i14.PrivacyPolicyView(key: args.key), settings: data, ); }, _i15.TermsAndConditionsView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i15.TermsAndConditionsView(), + final args = data.getArgs( + orElse: () => const TermsAndConditionsViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i15.TermsAndConditionsView(key: args.key), settings: data, ); }, _i16.RegisterView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i16.RegisterView(), + final args = data.getArgs( + orElse: () => const RegisterViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i16.RegisterView(key: args.key), settings: data, ); }, _i17.LoginView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i17.LoginView(), + final args = data.getArgs( + orElse: () => const LoginViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i17.LoginView(key: args.key), settings: data, ); }, - _i18.LearnView: (data) { - final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( - builder: (context) => _i18.LearnView(key: args.key, id: args.id), - settings: data, - ); - }, - _i19.LearnLevelView: (data) { - final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( - builder: (context) => _i19.LearnLevelView(key: args.key, id: args.id), - settings: data, - ); - }, - _i20.LearnModuleView: (data) { + _i18.LearnModuleView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i20.LearnModuleView(key: args.key, level: args.level), + _i18.LearnModuleView(key: args.key, course: args.course), settings: data, ); }, - _i21.WelcomeView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i21.WelcomeView(), + _i19.WelcomeView: (data) { + final args = data.getArgs( + orElse: () => const WelcomeViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i19.WelcomeView(key: args.key), settings: data, ); }, - _i22.AssessmentView: (data) { + _i20.AssessmentView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i22.AssessmentView(key: args.key, data: args.data), + _i20.AssessmentView(key: args.key, data: args.data), settings: data, ); }, - _i23.LearnLessonView: (data) { + _i21.LearnLessonView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i23.LearnLessonView(key: args.key, submodule: args.submodule), + _i21.LearnLessonView(key: args.key, module: args.module), settings: data, ); }, - _i24.ForgetPasswordView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i24.ForgetPasswordView(), + _i22.ForgetPasswordView: (data) { + final args = data.getArgs( + orElse: () => const ForgetPasswordViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i22.ForgetPasswordView(key: args.key), settings: data, ); }, - _i25.LearnLessonDetailView: (data) { + _i23.LearnLessonDetailView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i25.LearnLessonDetailView(key: args.key, lesson: args.lesson), + _i23.LearnLessonDetailView(key: args.key, lesson: args.lesson), settings: data, ); }, - _i26.LearnPracticeView: (data) { + _i24.LearnPracticeView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( - builder: (context) => _i26.LearnPracticeView( - key: args.key, - title: args.title, - subtitle: args.subtitle, - practices: args.practices, - buttonLabel: args.buttonLabel), + return _i37.MaterialPageRoute( + builder: (context) => _i24.LearnPracticeView( + key: args.key, id: args.id, practice: args.practice), settings: data, ); }, - _i27.CoursePracticeView: (data) { + _i25.CoursePracticeView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i27.CoursePracticeView(key: args.key, id: args.id), + _i25.CoursePracticeView(key: args.key, id: args.id), settings: data, ); }, - _i28.CoursePaymentView: (data) { + _i26.CoursePaymentView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i28.CoursePaymentView(key: args.key, course: args.course), + _i26.CoursePaymentView(key: args.key, course: args.course), settings: data, ); }, - _i29.CourseCategoryView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i29.CourseCategoryView(), + _i27.CourseCategoryView: (data) { + final args = data.getArgs( + orElse: () => const CourseCategoryViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i27.CourseCategoryView(key: args.key), settings: data, ); }, - _i30.FailureView: (data) { + _i28.FailureView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i30.FailureView(key: args.key, label: args.label), + _i28.FailureView(key: args.key, label: args.label), settings: data, ); }, - _i31.CourseLessonView: (data) { + _i29.CourseLessonView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i31.CourseLessonView(key: args.key, course: args.course), + _i29.CourseLessonView(key: args.key, course: args.course), settings: data, ); }, - _i32.CourseLessonDetailView: (data) { + _i30.CourseLessonDetailView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i32.CourseLessonDetailView(key: args.key, lesson: args.lesson), + _i30.CourseLessonDetailView(key: args.key, lesson: args.lesson), settings: data, ); }, - _i33.DuolingoView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i33.DuolingoView(), + _i31.DuolingoView: (data) { + final args = data.getArgs( + orElse: () => const DuolingoViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i31.DuolingoView(key: args.key), settings: data, ); }, - _i34.CourseSubcategoryView: (data) { + _i32.CourseSubcategoryView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i34.CourseSubcategoryView(key: args.key, category: args.category), + _i32.CourseSubcategoryView(key: args.key, category: args.category), settings: data, ); }, - _i35.CourseView: (data) { + _i33.CourseView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i35.CourseView(key: args.key, subcategory: args.subcategory), + _i33.CourseView(key: args.key, subcategory: args.subcategory), settings: data, ); }, - _i36.CoursePracticeQuestionView: (data) { + _i34.CoursePracticeQuestionView: (data) { final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( + return _i37.MaterialPageRoute( builder: (context) => - _i36.CoursePracticeQuestionView(key: args.key, id: args.id), + _i34.CoursePracticeQuestionView(key: args.key, id: args.id), settings: data, ); }, - _i37.LearnSubcategoryView: (data) { - return _i39.MaterialPageRoute( - builder: (context) => const _i37.LearnSubcategoryView(), + _i35.LearnProgramView: (data) { + final args = data.getArgs( + orElse: () => const LearnProgramViewArguments(), + ); + return _i37.MaterialPageRoute( + builder: (context) => _i35.LearnProgramView(key: args.key), settings: data, ); }, - _i38.LearnSubmoduleView: (data) { - final args = data.getArgs(nullOk: false); - return _i39.MaterialPageRoute( - builder: (context) => - _i38.LearnSubmoduleView(key: args.key, module: args.module), + _i36.LearnCourseView: (data) { + final args = data.getArgs(nullOk: false); + return _i37.MaterialPageRoute( + builder: (context) => _i36.LearnCourseView(key: args.key, id: args.id), settings: data, ); }, @@ -613,13 +639,57 @@ class StackedRouter extends _i1.RouterBase { Map get pagesMap => _pagesMap; } +class HomeViewArguments { + const HomeViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant HomeViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class OnboardingViewArguments { + const OnboardingViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant OnboardingViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + class StartupViewArguments { const StartupViewArguments({ this.key, this.label = 'Loading', }); - final _i39.Key? key; + final _i37.Key? key; final String label; @@ -640,84 +710,338 @@ class StartupViewArguments { } } -class LearnViewArguments { - const LearnViewArguments({ - this.key, - required this.id, - }); +class ProfileViewArguments { + const ProfileViewArguments({this.key}); - final _i39.Key? key; - - final int id; + final _i37.Key? key; @override String toString() { - return '{"key": "$key", "id": "$id"}'; + return '{"key": "$key"}'; } @override - bool operator ==(covariant LearnViewArguments other) { + bool operator ==(covariant ProfileViewArguments other) { if (identical(this, other)) return true; - return other.key == key && other.id == id; + return other.key == key; } @override int get hashCode { - return key.hashCode ^ id.hashCode; + return key.hashCode; } } -class LearnLevelViewArguments { - const LearnLevelViewArguments({ - this.key, - required this.id, - }); +class ProfileDetailViewArguments { + const ProfileDetailViewArguments({this.key}); - final _i39.Key? key; - - final int id; + final _i37.Key? key; @override String toString() { - return '{"key": "$key", "id": "$id"}'; + return '{"key": "$key"}'; } @override - bool operator ==(covariant LearnLevelViewArguments other) { + bool operator ==(covariant ProfileDetailViewArguments other) { if (identical(this, other)) return true; - return other.key == key && other.id == id; + return other.key == key; } @override int get hashCode { - return key.hashCode ^ id.hashCode; + return key.hashCode; + } +} + +class DownloadsViewArguments { + const DownloadsViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant DownloadsViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class ProgressViewArguments { + const ProgressViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant ProgressViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class AccountPrivacyViewArguments { + const AccountPrivacyViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant AccountPrivacyViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class SupportViewArguments { + const SupportViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant SupportViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class TelegramSupportViewArguments { + const TelegramSupportViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant TelegramSupportViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class CallSupportViewArguments { + const CallSupportViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant CallSupportViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class LanguageViewArguments { + const LanguageViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant LanguageViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class PrivacyPolicyViewArguments { + const PrivacyPolicyViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant PrivacyPolicyViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class TermsAndConditionsViewArguments { + const TermsAndConditionsViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant TermsAndConditionsViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class RegisterViewArguments { + const RegisterViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant RegisterViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + +class LoginViewArguments { + const LoginViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant LoginViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; } } class LearnModuleViewArguments { const LearnModuleViewArguments({ this.key, - required this.level, + required this.course, }); - final _i39.Key? key; + final _i37.Key? key; - final _i40.Level level; + final _i38.LearnCourse course; @override String toString() { - return '{"key": "$key", "level": "$level"}'; + return '{"key": "$key", "course": "$course"}'; } @override bool operator ==(covariant LearnModuleViewArguments other) { if (identical(this, other)) return true; - return other.key == key && other.level == level; + return other.key == key && other.course == course; } @override int get hashCode { - return key.hashCode ^ level.hashCode; + return key.hashCode ^ course.hashCode; + } +} + +class WelcomeViewArguments { + const WelcomeViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant WelcomeViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; } } @@ -727,7 +1051,7 @@ class AssessmentViewArguments { required this.data, }); - final _i39.Key? key; + final _i37.Key? key; final Map data; @@ -751,27 +1075,49 @@ class AssessmentViewArguments { class LearnLessonViewArguments { const LearnLessonViewArguments({ this.key, - required this.submodule, + required this.module, }); - final _i39.Key? key; + final _i37.Key? key; - final _i41.Submodule submodule; + final _i39.LearnModule module; @override String toString() { - return '{"key": "$key", "submodule": "$submodule"}'; + return '{"key": "$key", "module": "$module"}'; } @override bool operator ==(covariant LearnLessonViewArguments other) { if (identical(this, other)) return true; - return other.key == key && other.submodule == submodule; + return other.key == key && other.module == module; } @override int get hashCode { - return key.hashCode ^ submodule.hashCode; + return key.hashCode ^ module.hashCode; + } +} + +class ForgetPasswordViewArguments { + const ForgetPasswordViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant ForgetPasswordViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; } } @@ -781,9 +1127,9 @@ class LearnLessonDetailViewArguments { required this.lesson, }); - final _i39.Key? key; + final _i37.Key? key; - final _i42.Lesson lesson; + final _i40.LearnLesson lesson; @override String toString() { @@ -805,44 +1151,30 @@ class LearnLessonDetailViewArguments { class LearnPracticeViewArguments { const LearnPracticeViewArguments({ this.key, - required this.title, - required this.subtitle, - required this.practices, - required this.buttonLabel, + required this.id, + required this.practice, }); - final _i39.Key? key; + final _i37.Key? key; - final String title; + final int id; - final String subtitle; - - final List> practices; - - final String buttonLabel; + final _i41.LearnPractices practice; @override String toString() { - return '{"key": "$key", "title": "$title", "subtitle": "$subtitle", "practices": "$practices", "buttonLabel": "$buttonLabel"}'; + return '{"key": "$key", "id": "$id", "practice": "$practice"}'; } @override bool operator ==(covariant LearnPracticeViewArguments other) { if (identical(this, other)) return true; - return other.key == key && - other.title == title && - other.subtitle == subtitle && - other.practices == practices && - other.buttonLabel == buttonLabel; + return other.key == key && other.id == id && other.practice == practice; } @override int get hashCode { - return key.hashCode ^ - title.hashCode ^ - subtitle.hashCode ^ - practices.hashCode ^ - buttonLabel.hashCode; + return key.hashCode ^ id.hashCode ^ practice.hashCode; } } @@ -852,7 +1184,7 @@ class CoursePracticeViewArguments { required this.id, }); - final _i39.Key? key; + final _i37.Key? key; final int id; @@ -879,9 +1211,9 @@ class CoursePaymentViewArguments { required this.course, }); - final _i39.Key? key; + final _i37.Key? key; - final _i43.Course course; + final _i42.Course course; @override String toString() { @@ -900,13 +1232,35 @@ class CoursePaymentViewArguments { } } +class CourseCategoryViewArguments { + const CourseCategoryViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant CourseCategoryViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + class FailureViewArguments { const FailureViewArguments({ this.key, required this.label, }); - final _i39.Key? key; + final _i37.Key? key; final String label; @@ -933,9 +1287,9 @@ class CourseLessonViewArguments { required this.course, }); - final _i39.Key? key; + final _i37.Key? key; - final _i43.Course course; + final _i42.Course course; @override String toString() { @@ -960,9 +1314,9 @@ class CourseLessonDetailViewArguments { required this.lesson, }); - final _i39.Key? key; + final _i37.Key? key; - final _i44.CourseLesson lesson; + final _i43.CourseLesson lesson; @override String toString() { @@ -981,15 +1335,37 @@ class CourseLessonDetailViewArguments { } } +class DuolingoViewArguments { + const DuolingoViewArguments({this.key}); + + final _i37.Key? key; + + @override + String toString() { + return '{"key": "$key"}'; + } + + @override + bool operator ==(covariant DuolingoViewArguments other) { + if (identical(this, other)) return true; + return other.key == key; + } + + @override + int get hashCode { + return key.hashCode; + } +} + class CourseSubcategoryViewArguments { const CourseSubcategoryViewArguments({ this.key, required this.category, }); - final _i39.Key? key; + final _i37.Key? key; - final _i45.Category category; + final _i44.Category category; @override String toString() { @@ -1014,9 +1390,9 @@ class CourseViewArguments { required this.subcategory, }); - final _i39.Key? key; + final _i37.Key? key; - final _i46.Subcategory subcategory; + final _i45.Subcategory subcategory; @override String toString() { @@ -1041,7 +1417,7 @@ class CoursePracticeQuestionViewArguments { required this.id, }); - final _i39.Key? key; + final _i37.Key? key; final int id; @@ -1062,56 +1438,82 @@ class CoursePracticeQuestionViewArguments { } } -class LearnSubmoduleViewArguments { - const LearnSubmoduleViewArguments({ - this.key, - required this.module, - }); +class LearnProgramViewArguments { + const LearnProgramViewArguments({this.key}); - final _i39.Key? key; - - final _i47.Module module; + final _i37.Key? key; @override String toString() { - return '{"key": "$key", "module": "$module"}'; + return '{"key": "$key"}'; } @override - bool operator ==(covariant LearnSubmoduleViewArguments other) { + bool operator ==(covariant LearnProgramViewArguments other) { if (identical(this, other)) return true; - return other.key == key && other.module == module; + return other.key == key; } @override int get hashCode { - return key.hashCode ^ module.hashCode; + return key.hashCode; } } -extension NavigatorStateExtension on _i48.NavigationService { - Future navigateToHomeView([ +class LearnCourseViewArguments { + const LearnCourseViewArguments({ + this.key, + required this.id, + }); + + final _i37.Key? key; + + final int id; + + @override + String toString() { + return '{"key": "$key", "id": "$id"}'; + } + + @override + bool operator ==(covariant LearnCourseViewArguments other) { + if (identical(this, other)) return true; + return other.key == key && other.id == id; + } + + @override + int get hashCode { + return key.hashCode ^ id.hashCode; + } +} + +extension NavigatorStateExtension on _i46.NavigationService { + Future navigateToHomeView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.homeView, + arguments: HomeViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToOnboardingView([ + Future navigateToOnboardingView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.onboardingView, + arguments: OnboardingViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1119,7 +1521,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToStartupView({ - _i39.Key? key, + _i37.Key? key, String label = 'Loading', int? routerId, bool preventDuplicates = true, @@ -1135,216 +1537,208 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future navigateToProfileView([ + Future navigateToProfileView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.profileView, + arguments: ProfileViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToProfileDetailView([ + Future navigateToProfileDetailView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.profileDetailView, + arguments: ProfileDetailViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToDownloadsView([ + Future navigateToDownloadsView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.downloadsView, + arguments: DownloadsViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToProgressView([ + Future navigateToProgressView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.progressView, + arguments: ProgressViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToAccountPrivacyView([ + Future navigateToAccountPrivacyView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.accountPrivacyView, + arguments: AccountPrivacyViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToSupportView([ + Future navigateToSupportView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.supportView, + arguments: SupportViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToTelegramSupportView([ + Future navigateToTelegramSupportView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.telegramSupportView, + arguments: TelegramSupportViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToCallSupportView([ + Future navigateToCallSupportView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.callSupportView, + arguments: CallSupportViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToLanguageView([ + Future navigateToLanguageView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.languageView, + arguments: LanguageViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToPrivacyPolicyView([ + Future navigateToPrivacyPolicyView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.privacyPolicyView, + arguments: PrivacyPolicyViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToTermsAndConditionsView([ + Future navigateToTermsAndConditionsView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.termsAndConditionsView, + arguments: TermsAndConditionsViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToRegisterView([ + Future navigateToRegisterView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.registerView, + arguments: RegisterViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToLoginView([ + Future navigateToLoginView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.loginView, - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - - Future navigateToLearnView({ - _i39.Key? key, - required int id, - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - }) async { - return navigateTo(Routes.learnView, - arguments: LearnViewArguments(key: key, id: id), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - - Future navigateToLearnLevelView({ - _i39.Key? key, - required int id, - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - }) async { - return navigateTo(Routes.learnLevelView, - arguments: LearnLevelViewArguments(key: key, id: id), + arguments: LoginViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1352,8 +1746,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToLearnModuleView({ - _i39.Key? key, - required _i40.Level level, + _i37.Key? key, + required _i38.LearnCourse course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1361,21 +1755,23 @@ extension NavigatorStateExtension on _i48.NavigationService { transition, }) async { return navigateTo(Routes.learnModuleView, - arguments: LearnModuleViewArguments(key: key, level: level), + arguments: LearnModuleViewArguments(key: key, course: course), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToWelcomeView([ + Future navigateToWelcomeView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.welcomeView, + arguments: WelcomeViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1383,7 +1779,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToAssessmentView({ - _i39.Key? key, + _i37.Key? key, required Map data, int? routerId, bool preventDuplicates = true, @@ -1400,8 +1796,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToLearnLessonView({ - _i39.Key? key, - required _i41.Submodule submodule, + _i37.Key? key, + required _i39.LearnModule module, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1409,21 +1805,23 @@ extension NavigatorStateExtension on _i48.NavigationService { transition, }) async { return navigateTo(Routes.learnLessonView, - arguments: LearnLessonViewArguments(key: key, submodule: submodule), + arguments: LearnLessonViewArguments(key: key, module: module), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future navigateToForgetPasswordView([ + Future navigateToForgetPasswordView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.forgetPasswordView, + arguments: ForgetPasswordViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1431,8 +1829,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToLearnLessonDetailView({ - _i39.Key? key, - required _i42.Lesson lesson, + _i37.Key? key, + required _i40.LearnLesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1448,11 +1846,9 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToLearnPracticeView({ - _i39.Key? key, - required String title, - required String subtitle, - required List> practices, - required String buttonLabel, + _i37.Key? key, + required int id, + required _i41.LearnPractices practice, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1460,12 +1856,8 @@ extension NavigatorStateExtension on _i48.NavigationService { transition, }) async { return navigateTo(Routes.learnPracticeView, - arguments: LearnPracticeViewArguments( - key: key, - title: title, - subtitle: subtitle, - practices: practices, - buttonLabel: buttonLabel), + arguments: + LearnPracticeViewArguments(key: key, id: id, practice: practice), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1473,7 +1865,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToCoursePracticeView({ - _i39.Key? key, + _i37.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1490,8 +1882,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToCoursePaymentView({ - _i39.Key? key, - required _i43.Course course, + _i37.Key? key, + required _i42.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1506,14 +1898,16 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future navigateToCourseCategoryView([ + Future navigateToCourseCategoryView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.courseCategoryView, + arguments: CourseCategoryViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1521,7 +1915,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToFailureView({ - _i39.Key? key, + _i37.Key? key, required String label, int? routerId, bool preventDuplicates = true, @@ -1538,8 +1932,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToCourseLessonView({ - _i39.Key? key, - required _i43.Course course, + _i37.Key? key, + required _i42.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1555,8 +1949,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToCourseLessonDetailView({ - _i39.Key? key, - required _i44.CourseLesson lesson, + _i37.Key? key, + required _i43.CourseLesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1571,14 +1965,16 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future navigateToDuolingoView([ + Future navigateToDuolingoView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.duolingoView, + arguments: DuolingoViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1586,8 +1982,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToCourseSubcategoryView({ - _i39.Key? key, - required _i45.Category category, + _i37.Key? key, + required _i44.Category category, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1603,8 +1999,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToCourseView({ - _i39.Key? key, - required _i46.Subcategory subcategory, + _i37.Key? key, + required _i45.Subcategory subcategory, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1620,7 +2016,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future navigateToCoursePracticeQuestionView({ - _i39.Key? key, + _i37.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1636,59 +2032,65 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future navigateToLearnSubcategoryView([ - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - ]) async { - return navigateTo(Routes.learnSubcategoryView, - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - - Future navigateToLearnSubmoduleView({ - _i39.Key? key, - required _i47.Module module, + Future navigateToLearnProgramView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return navigateTo(Routes.learnSubmoduleView, - arguments: LearnSubmoduleViewArguments(key: key, module: module), + return navigateTo(Routes.learnProgramView, + arguments: LearnProgramViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithHomeView([ + Future navigateToLearnCourseView({ + _i37.Key? key, + required int id, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { + return navigateTo(Routes.learnCourseView, + arguments: LearnCourseViewArguments(key: key, id: id), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithHomeView({ + _i37.Key? key, + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { return replaceWith(Routes.homeView, + arguments: HomeViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithOnboardingView([ + Future replaceWithOnboardingView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.onboardingView, + arguments: OnboardingViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1696,7 +2098,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithStartupView({ - _i39.Key? key, + _i37.Key? key, String label = 'Loading', int? routerId, bool preventDuplicates = true, @@ -1712,216 +2114,208 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future replaceWithProfileView([ + Future replaceWithProfileView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.profileView, + arguments: ProfileViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithProfileDetailView([ + Future replaceWithProfileDetailView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.profileDetailView, + arguments: ProfileDetailViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithDownloadsView([ + Future replaceWithDownloadsView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.downloadsView, + arguments: DownloadsViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithProgressView([ + Future replaceWithProgressView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.progressView, + arguments: ProgressViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithAccountPrivacyView([ + Future replaceWithAccountPrivacyView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.accountPrivacyView, + arguments: AccountPrivacyViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithSupportView([ + Future replaceWithSupportView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.supportView, + arguments: SupportViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithTelegramSupportView([ + Future replaceWithTelegramSupportView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.telegramSupportView, + arguments: TelegramSupportViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithCallSupportView([ + Future replaceWithCallSupportView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.callSupportView, + arguments: CallSupportViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithLanguageView([ + Future replaceWithLanguageView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.languageView, + arguments: LanguageViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithPrivacyPolicyView([ + Future replaceWithPrivacyPolicyView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.privacyPolicyView, + arguments: PrivacyPolicyViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithTermsAndConditionsView([ + Future replaceWithTermsAndConditionsView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.termsAndConditionsView, + arguments: TermsAndConditionsViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithRegisterView([ + Future replaceWithRegisterView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.registerView, + arguments: RegisterViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithLoginView([ + Future replaceWithLoginView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.loginView, - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - - Future replaceWithLearnView({ - _i39.Key? key, - required int id, - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - }) async { - return replaceWith(Routes.learnView, - arguments: LearnViewArguments(key: key, id: id), - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - - Future replaceWithLearnLevelView({ - _i39.Key? key, - required int id, - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - }) async { - return replaceWith(Routes.learnLevelView, - arguments: LearnLevelViewArguments(key: key, id: id), + arguments: LoginViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1929,8 +2323,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithLearnModuleView({ - _i39.Key? key, - required _i40.Level level, + _i37.Key? key, + required _i38.LearnCourse course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1938,21 +2332,23 @@ extension NavigatorStateExtension on _i48.NavigationService { transition, }) async { return replaceWith(Routes.learnModuleView, - arguments: LearnModuleViewArguments(key: key, level: level), + arguments: LearnModuleViewArguments(key: key, course: course), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithWelcomeView([ + Future replaceWithWelcomeView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.welcomeView, + arguments: WelcomeViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1960,7 +2356,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithAssessmentView({ - _i39.Key? key, + _i37.Key? key, required Map data, int? routerId, bool preventDuplicates = true, @@ -1977,8 +2373,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithLearnLessonView({ - _i39.Key? key, - required _i41.Submodule submodule, + _i37.Key? key, + required _i39.LearnModule module, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1986,21 +2382,23 @@ extension NavigatorStateExtension on _i48.NavigationService { transition, }) async { return replaceWith(Routes.learnLessonView, - arguments: LearnLessonViewArguments(key: key, submodule: submodule), + arguments: LearnLessonViewArguments(key: key, module: module), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, transition: transition); } - Future replaceWithForgetPasswordView([ + Future replaceWithForgetPasswordView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.forgetPasswordView, + arguments: ForgetPasswordViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -2008,8 +2406,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithLearnLessonDetailView({ - _i39.Key? key, - required _i42.Lesson lesson, + _i37.Key? key, + required _i40.LearnLesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2025,11 +2423,9 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithLearnPracticeView({ - _i39.Key? key, - required String title, - required String subtitle, - required List> practices, - required String buttonLabel, + _i37.Key? key, + required int id, + required _i41.LearnPractices practice, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2037,12 +2433,8 @@ extension NavigatorStateExtension on _i48.NavigationService { transition, }) async { return replaceWith(Routes.learnPracticeView, - arguments: LearnPracticeViewArguments( - key: key, - title: title, - subtitle: subtitle, - practices: practices, - buttonLabel: buttonLabel), + arguments: + LearnPracticeViewArguments(key: key, id: id, practice: practice), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -2050,7 +2442,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithCoursePracticeView({ - _i39.Key? key, + _i37.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -2067,8 +2459,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithCoursePaymentView({ - _i39.Key? key, - required _i43.Course course, + _i37.Key? key, + required _i42.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2083,14 +2475,16 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future replaceWithCourseCategoryView([ + Future replaceWithCourseCategoryView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.courseCategoryView, + arguments: CourseCategoryViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -2098,7 +2492,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithFailureView({ - _i39.Key? key, + _i37.Key? key, required String label, int? routerId, bool preventDuplicates = true, @@ -2115,8 +2509,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithCourseLessonView({ - _i39.Key? key, - required _i43.Course course, + _i37.Key? key, + required _i42.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2132,8 +2526,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithCourseLessonDetailView({ - _i39.Key? key, - required _i44.CourseLesson lesson, + _i37.Key? key, + required _i43.CourseLesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2148,14 +2542,16 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future replaceWithDuolingoView([ + Future replaceWithDuolingoView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.duolingoView, + arguments: DuolingoViewArguments(key: key), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -2163,8 +2559,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithCourseSubcategoryView({ - _i39.Key? key, - required _i45.Category category, + _i37.Key? key, + required _i44.Category category, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2180,8 +2576,8 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithCourseView({ - _i39.Key? key, - required _i46.Subcategory subcategory, + _i37.Key? key, + required _i45.Subcategory subcategory, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2197,7 +2593,7 @@ extension NavigatorStateExtension on _i48.NavigationService { } Future replaceWithCoursePracticeQuestionView({ - _i39.Key? key, + _i37.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -2213,31 +2609,33 @@ extension NavigatorStateExtension on _i48.NavigationService { transition: transition); } - Future replaceWithLearnSubcategoryView([ - int? routerId, - bool preventDuplicates = true, - Map? parameters, - Widget Function(BuildContext, Animation, Animation, Widget)? - transition, - ]) async { - return replaceWith(Routes.learnSubcategoryView, - id: routerId, - preventDuplicates: preventDuplicates, - parameters: parameters, - transition: transition); - } - - Future replaceWithLearnSubmoduleView({ - _i39.Key? key, - required _i47.Module module, + Future replaceWithLearnProgramView({ + _i37.Key? key, int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, }) async { - return replaceWith(Routes.learnSubmoduleView, - arguments: LearnSubmoduleViewArguments(key: key, module: module), + return replaceWith(Routes.learnProgramView, + arguments: LearnProgramViewArguments(key: key), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithLearnCourseView({ + _i37.Key? key, + required int id, + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return replaceWith(Routes.learnCourseView, + arguments: LearnCourseViewArguments(key: key, id: id), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, diff --git a/lib/firebase_options.dart b/lib/firebase_options.dart index d638499..c80bdc9 100644 --- a/lib/firebase_options.dart +++ b/lib/firebase_options.dart @@ -64,7 +64,7 @@ class DefaultFirebaseOptions { projectId: 'yimaru-academy-5e7e2', storageBucket: 'yimaru-academy-5e7e2.firebasestorage.app', androidClientId: - '900714037062-ngc0gc426sfnnjjr494g4vni46ne5uqv.apps.googleusercontent.com', + '900714037062-4trqu7ln6en4kcm6gadk0uo01qijn1mk.apps.googleusercontent.com', iosClientId: '900714037062-35bg0hsou56hg37mbcbpiar9uti7tcku.apps.googleusercontent.com', iosBundleId: 'com.yimaru.lms.app', diff --git a/lib/models/access.dart b/lib/models/access.dart new file mode 100644 index 0000000..96725a9 --- /dev/null +++ b/lib/models/access.dart @@ -0,0 +1,35 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'access.g.dart'; + +@JsonSerializable() +class Access { + final String? reason; + + @JsonKey(name: 'total_count') + final int? totalCount; + + @JsonKey(name: 'is_completed') + final bool? isCompleted; + + @JsonKey(name: 'is_accessible') + final bool? isAccessible; + + @JsonKey(name: 'completed_count') + final int? completedCount; + + @JsonKey(name: 'progress_percent') + final int? progressPercent; + + const Access( + {this.reason, + this.totalCount, + this.isCompleted, + this.isAccessible, + this.completedCount, + this.progressPercent}); + + factory Access.fromJson(Map json) => _$AccessFromJson(json); + + Map toJson() => _$AccessToJson(this); +} diff --git a/lib/models/access.g.dart b/lib/models/access.g.dart new file mode 100644 index 0000000..01350af --- /dev/null +++ b/lib/models/access.g.dart @@ -0,0 +1,25 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'access.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Access _$AccessFromJson(Map json) => Access( + reason: json['reason'] as String?, + totalCount: (json['total_count'] as num?)?.toInt(), + isCompleted: json['is_completed'] as bool?, + isAccessible: json['is_accessible'] as bool?, + completedCount: (json['completed_count'] as num?)?.toInt(), + progressPercent: (json['progress_percent'] as num?)?.toInt(), + ); + +Map _$AccessToJson(Access instance) => { + 'reason': instance.reason, + 'total_count': instance.totalCount, + 'is_completed': instance.isCompleted, + 'is_accessible': instance.isAccessible, + 'completed_count': instance.completedCount, + 'progress_percent': instance.progressPercent, + }; diff --git a/lib/models/learn_course.dart b/lib/models/learn_course.dart new file mode 100644 index 0000000..4605a5a --- /dev/null +++ b/lib/models/learn_course.dart @@ -0,0 +1,34 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:yimaru_app/models/access.dart'; + +part 'learn_course.g.dart'; + +@JsonSerializable() +class LearnCourse { + final int? id; + + final String? name; + + final Access? access; + + final String? description; + + @JsonKey(name: 'sort_order') + final int? sortOrder; + + @JsonKey(name: 'program_id') + final int? programId; + + const LearnCourse( + {this.id, + this.name, + this.access, + this.programId, + this.sortOrder, + this.description}); + + factory LearnCourse.fromJson(Map json) => + _$LearnCourseFromJson(json); + + Map toJson() => _$LearnCourseToJson(this); +} diff --git a/lib/models/learn_course.g.dart b/lib/models/learn_course.g.dart new file mode 100644 index 0000000..e58fd26 --- /dev/null +++ b/lib/models/learn_course.g.dart @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'learn_course.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LearnCourse _$LearnCourseFromJson(Map json) => LearnCourse( + id: (json['id'] as num?)?.toInt(), + name: json['name'] as String?, + access: json['access'] == null + ? null + : Access.fromJson(json['access'] as Map), + programId: (json['program_id'] as num?)?.toInt(), + sortOrder: (json['sort_order'] as num?)?.toInt(), + description: json['description'] as String?, + ); + +Map _$LearnCourseToJson(LearnCourse instance) => + { + 'id': instance.id, + 'name': instance.name, + 'access': instance.access, + 'description': instance.description, + 'sort_order': instance.sortOrder, + 'program_id': instance.programId, + }; diff --git a/lib/models/learn_lesson.dart b/lib/models/learn_lesson.dart new file mode 100644 index 0000000..4728d9b --- /dev/null +++ b/lib/models/learn_lesson.dart @@ -0,0 +1,43 @@ +import 'package:json_annotation/json_annotation.dart'; + +import 'access.dart'; + +part 'learn_lesson.g.dart'; + +@JsonSerializable() +class LearnLesson { + final int? id; + + final String? title; + + final Access? access; + + final String? thumbnail; + + final String? description; + + @JsonKey(name: 'module_id') + final int? moduleId; + + @JsonKey(name: 'sort_order') + final int? sortOrder; + + @JsonKey(name: 'video_url') + final String? videoUrl; + + const LearnLesson({ + this.id, + this.title, + this.access, + this.videoUrl, + this.moduleId, + this.thumbnail, + this.sortOrder, + this.description, + }); + + factory LearnLesson.fromJson(Map json) => + _$LearnLessonFromJson(json); + + Map toJson() => _$LearnLessonToJson(this); +} diff --git a/lib/models/learn_lesson.g.dart b/lib/models/learn_lesson.g.dart new file mode 100644 index 0000000..faf92fd --- /dev/null +++ b/lib/models/learn_lesson.g.dart @@ -0,0 +1,32 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'learn_lesson.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LearnLesson _$LearnLessonFromJson(Map json) => LearnLesson( + id: (json['id'] as num?)?.toInt(), + title: json['title'] as String?, + access: json['access'] == null + ? null + : Access.fromJson(json['access'] as Map), + videoUrl: json['video_url'] as String?, + moduleId: (json['module_id'] as num?)?.toInt(), + thumbnail: json['thumbnail'] as String?, + sortOrder: (json['sort_order'] as num?)?.toInt(), + description: json['description'] as String?, + ); + +Map _$LearnLessonToJson(LearnLesson instance) => + { + 'id': instance.id, + 'title': instance.title, + 'access': instance.access, + 'thumbnail': instance.thumbnail, + 'description': instance.description, + 'module_id': instance.moduleId, + 'sort_order': instance.sortOrder, + 'video_url': instance.videoUrl, + }; diff --git a/lib/models/learn_module.dart b/lib/models/learn_module.dart new file mode 100644 index 0000000..b444229 --- /dev/null +++ b/lib/models/learn_module.dart @@ -0,0 +1,41 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:yimaru_app/models/access.dart'; + +part 'learn_module.g.dart'; + +@JsonSerializable() +class LearnModule { + final int? id; + + final String? icon; + + final String? name; + + final Access? access; + + final String? description; + + @JsonKey(name: 'program_id') + final int? programId; + + @JsonKey(name: 'course_id') + final int? courseId; + + @JsonKey(name: 'sort_order') + final int? sortOrder; + + const LearnModule( + {this.id, + this.icon, + this.name, + this.access, + this.courseId, + this.sortOrder, + this.programId, + this.description}); + + factory LearnModule.fromJson(Map json) => + _$LearnModuleFromJson(json); + + Map toJson() => _$LearnModuleToJson(this); +} diff --git a/lib/models/learn_module.g.dart b/lib/models/learn_module.g.dart new file mode 100644 index 0000000..2531f24 --- /dev/null +++ b/lib/models/learn_module.g.dart @@ -0,0 +1,32 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'learn_module.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LearnModule _$LearnModuleFromJson(Map json) => LearnModule( + id: (json['id'] as num?)?.toInt(), + icon: json['icon'] as String?, + name: json['name'] as String?, + access: json['access'] == null + ? null + : Access.fromJson(json['access'] as Map), + courseId: (json['course_id'] as num?)?.toInt(), + sortOrder: (json['sort_order'] as num?)?.toInt(), + programId: (json['program_id'] as num?)?.toInt(), + description: json['description'] as String?, + ); + +Map _$LearnModuleToJson(LearnModule instance) => + { + 'id': instance.id, + 'icon': instance.icon, + 'name': instance.name, + 'access': instance.access, + 'description': instance.description, + 'program_id': instance.programId, + 'course_id': instance.courseId, + 'sort_order': instance.sortOrder, + }; diff --git a/lib/models/learn_practice.dart b/lib/models/learn_practice.dart new file mode 100644 index 0000000..7ed50f0 --- /dev/null +++ b/lib/models/learn_practice.dart @@ -0,0 +1,43 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'learn_practice.g.dart'; + +@JsonSerializable() +class LearnPractice { + final int? id; + + final String? title; + + @JsonKey(name: 'parent_id') + final int? parentId; + + @JsonKey(name: 'quick_tips') + final String? quickTips; + + @JsonKey(name: 'story_image') + final String? storyImage; + + @JsonKey(name: 'parent_kind') + final String? parentKind; + + @JsonKey(name: 'question_set_id') + final int? questionSetId; + + @JsonKey(name: 'story_description') + final String? storyDescription; + + const LearnPractice( + {this.id, + this.title, + this.parentId, + this.quickTips, + this.storyImage, + this.parentKind, + this.questionSetId, + this.storyDescription}); + + factory LearnPractice.fromJson(Map json) => + _$LearnPracticeFromJson(json); + + Map toJson() => _$LearnPracticeToJson(this); +} diff --git a/lib/models/learn_practice.g.dart b/lib/models/learn_practice.g.dart new file mode 100644 index 0000000..272a573 --- /dev/null +++ b/lib/models/learn_practice.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'learn_practice.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LearnPractice _$LearnPracticeFromJson(Map json) => + LearnPractice( + id: (json['id'] as num?)?.toInt(), + title: json['title'] as String?, + parentId: (json['parent_id'] as num?)?.toInt(), + quickTips: json['quick_tips'] as String?, + storyImage: json['story_image'] as String?, + parentKind: json['parent_kind'] as String?, + questionSetId: (json['question_set_id'] as num?)?.toInt(), + storyDescription: json['story_description'] as String?, + ); + +Map _$LearnPracticeToJson(LearnPractice instance) => + { + 'id': instance.id, + 'title': instance.title, + 'parent_id': instance.parentId, + 'quick_tips': instance.quickTips, + 'story_image': instance.storyImage, + 'parent_kind': instance.parentKind, + 'question_set_id': instance.questionSetId, + 'story_description': instance.storyDescription, + }; diff --git a/lib/models/learn_program.dart b/lib/models/learn_program.dart new file mode 100644 index 0000000..bfe32f6 --- /dev/null +++ b/lib/models/learn_program.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:yimaru_app/models/access.dart'; + +part 'learn_program.g.dart'; + +@JsonSerializable() +class LearnProgram { + final int? id; + + final String? name; + + final Access? access; + + final String? description; + + @JsonKey(name: 'sort_order') + final int? sortOrder; + + const LearnProgram( + {this.id, this.name, this.access, this.sortOrder, this.description}); + + factory LearnProgram.fromJson(Map json) => + _$LearnProgramFromJson(json); + + Map toJson() => _$LearnProgramToJson(this); +} diff --git a/lib/models/learn_program.g.dart b/lib/models/learn_program.g.dart new file mode 100644 index 0000000..b0df28d --- /dev/null +++ b/lib/models/learn_program.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'learn_program.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LearnProgram _$LearnProgramFromJson(Map json) => LearnProgram( + id: (json['id'] as num?)?.toInt(), + name: json['name'] as String?, + access: json['access'] == null + ? null + : Access.fromJson(json['access'] as Map), + sortOrder: (json['sort_order'] as num?)?.toInt(), + description: json['description'] as String?, + ); + +Map _$LearnProgramToJson(LearnProgram instance) => + { + 'id': instance.id, + 'name': instance.name, + 'access': instance.access, + 'description': instance.description, + 'sort_order': instance.sortOrder, + }; diff --git a/lib/models/learn_question.dart b/lib/models/learn_question.dart new file mode 100644 index 0000000..3b8c0dc --- /dev/null +++ b/lib/models/learn_question.dart @@ -0,0 +1,56 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:yimaru_app/models/option.dart'; + +part 'learn_question.g.dart'; + +@JsonSerializable() +class LearnQuestion { + final int? id; + + final int? points; + + @JsonKey(name: 'set_id') + final int? setId; + + @JsonKey(name: 'question_id') + final int? questionId; + + @JsonKey(name: 'voice_prompt') + final String? voicePrompt; + + @JsonKey(name: 'question_text') + final String? questionText; + + @JsonKey(name: 'display_order') + final int? displayOrder; + + @JsonKey(name: 'question_type') + final String? questionType; + + @JsonKey(name: 'question_status') + final String? questionStatus; + + @JsonKey(name: 'audio_correct_answer_text') + final String? audioCorrectAnswerText; + + @JsonKey(name: 'sample_answer_voice_prompt') + final String? sampleAnswerVoicePrompt; + + const LearnQuestion( + {this.id, + this.setId, + this.points, + this.questionId, + this.voicePrompt, + this.questionText, + this.questionType, + this.displayOrder, + this.questionStatus, + this.audioCorrectAnswerText, + this.sampleAnswerVoicePrompt}); + + factory LearnQuestion.fromJson(Map json) => + _$LearnQuestionFromJson(json); + + Map toJson() => _$LearnQuestionToJson(this); +} diff --git a/lib/models/practice_question.g.dart b/lib/models/learn_question.g.dart similarity index 63% rename from lib/models/practice_question.g.dart rename to lib/models/learn_question.g.dart index 617286e..7f19da4 100644 --- a/lib/models/practice_question.g.dart +++ b/lib/models/learn_question.g.dart @@ -1,33 +1,37 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'practice_question.dart'; +part of 'learn_question.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** -PracticeQuestion _$PracticeQuestionFromJson(Map json) => - PracticeQuestion( +LearnQuestion _$LearnQuestionFromJson(Map json) => + LearnQuestion( id: (json['id'] as num?)?.toInt(), - tips: json['tips'] as String?, setId: (json['set_id'] as num?)?.toInt(), points: (json['points'] as num?)?.toInt(), questionId: (json['question_id'] as num?)?.toInt(), + voicePrompt: json['voice_prompt'] as String?, questionText: json['question_text'] as String?, questionType: json['question_type'] as String?, displayOrder: (json['display_order'] as num?)?.toInt(), questionStatus: json['question_status'] as String?, + audioCorrectAnswerText: json['audio_correct_answer_text'] as String?, + sampleAnswerVoicePrompt: json['sample_answer_voice_prompt'] as String?, ); -Map _$PracticeQuestionToJson(PracticeQuestion instance) => +Map _$LearnQuestionToJson(LearnQuestion instance) => { 'id': instance.id, 'points': instance.points, - 'tips': instance.tips, 'set_id': instance.setId, 'question_id': instance.questionId, - 'display_order': instance.displayOrder, + 'voice_prompt': instance.voicePrompt, 'question_text': instance.questionText, + 'display_order': instance.displayOrder, 'question_type': instance.questionType, 'question_status': instance.questionStatus, + 'audio_correct_answer_text': instance.audioCorrectAnswerText, + 'sample_answer_voice_prompt': instance.sampleAnswerVoicePrompt, }; diff --git a/lib/models/practice.dart b/lib/models/practice.dart index 54907d7..d1fd633 100644 --- a/lib/models/practice.dart +++ b/lib/models/practice.dart @@ -22,9 +22,15 @@ class Practice { @JsonKey(name: 'owner_type') final String? ownerType; + @JsonKey(name: 'intro_video_url') + final String? introVideoUrl; + @JsonKey(name: 'shuffle_questions') final bool? shuffleQuestions; + @JsonKey(name: 'time_limit_minutes') + final int? timeLimitMinutes; + const Practice( {this.id, this.title, @@ -34,7 +40,9 @@ class Practice { this.ownerId, this.ownerType, this.description, - this.shuffleQuestions}); + this.introVideoUrl, + this.shuffleQuestions, + this.timeLimitMinutes}); factory Practice.fromJson(Map json) => _$PracticeFromJson(json); diff --git a/lib/models/practice.g.dart b/lib/models/practice.g.dart index 7a0f915..dbb585c 100644 --- a/lib/models/practice.g.dart +++ b/lib/models/practice.g.dart @@ -15,7 +15,9 @@ Practice _$PracticeFromJson(Map json) => Practice( ownerId: (json['owner_id'] as num?)?.toInt(), ownerType: json['owner_type'] as String?, description: json['description'] as String?, + introVideoUrl: json['intro_video_url'] as String?, shuffleQuestions: json['shuffle_questions'] as bool?, + timeLimitMinutes: (json['time_limit_minutes'] as num?)?.toInt(), ); Map _$PracticeToJson(Practice instance) => { @@ -27,5 +29,7 @@ Map _$PracticeToJson(Practice instance) => { 'owner_id': instance.ownerId, 'set_type': instance.setType, 'owner_type': instance.ownerType, + 'intro_video_url': instance.introVideoUrl, 'shuffle_questions': instance.shuffleQuestions, + 'time_limit_minutes': instance.timeLimitMinutes, }; diff --git a/lib/models/practice_question.dart b/lib/models/practice_question.dart deleted file mode 100644 index 7c01af8..0000000 --- a/lib/models/practice_question.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'practice_question.g.dart'; - -@JsonSerializable() -class PracticeQuestion { - final int? id; - - final int? points; - - final String? tips; - - @JsonKey(name: 'set_id') - final int? setId; - - @JsonKey(name: 'question_id') - final int? questionId; - - @JsonKey(name: 'display_order') - final int? displayOrder; - - @JsonKey(name: 'question_text') - final String? questionText; - - @JsonKey(name: 'question_type') - final String? questionType; - - @JsonKey(name: 'question_status') - final String? questionStatus; - - const PracticeQuestion( - {this.id, - this.tips, - this.setId, - this.points, - this.questionId, - this.questionText, - this.questionType, - this.displayOrder, - this.questionStatus}); - - factory PracticeQuestion.fromJson(Map json) => - _$PracticeQuestionFromJson(json); - - Map toJson() => _$PracticeQuestionToJson(this); -} diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index 7dfce73..3952aca 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -1,4 +1,7 @@ import 'package:dio/dio.dart'; +import 'package:yimaru_app/models/learn_lesson.dart'; +import 'package:yimaru_app/models/learn_practice.dart'; +import 'package:yimaru_app/models/learn_program.dart'; import 'package:yimaru_app/models/level.dart'; import 'package:yimaru_app/models/question.dart'; import 'package:yimaru_app/models/subcategory.dart'; @@ -7,12 +10,14 @@ import 'package:yimaru_app/models/course_lesson.dart'; import 'package:yimaru_app/models/course_progress.dart'; import 'package:yimaru_app/models/course.dart'; import 'package:yimaru_app/models/practice.dart'; -import 'package:yimaru_app/models/practice_question.dart'; import 'package:yimaru_app/models/user.dart'; import 'package:yimaru_app/services/dio_service.dart'; import 'package:yimaru_app/ui/common/app_constants.dart'; import '../app/app.locator.dart'; +import '../models/learn_course.dart'; +import '../models/learn_module.dart'; +import '../models/learn_question.dart'; import '../models/lesson.dart'; import '../models/module.dart'; import '../models/submodule.dart'; @@ -215,7 +220,7 @@ class ApiService { } } - // GEt profile completion status + // Get profile completion status Future> getProfileStatus(User? user) async { try { Response response = await _service.dio.get( @@ -373,6 +378,201 @@ class ApiService { } } + // Learn learn programs + Future> getLearnPrograms() async { + try { + List learnPrograms = []; + + final Response response = + await _service.dio.get('$kBaseUrl/api/$kApiVersionUrl/$kProgramsUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data']['programs'] as List; + learnPrograms = decodedData.map( + (e) { + return LearnProgram.fromJson(e); + }, + ).toList(); + return learnPrograms; + } + return []; + } catch (e) { + return []; + } + } + + // Learn learn courses + Future> getLearnCourse(int id) async { + try { + List learnCourses = []; + + final Response response = await _service.dio + .get('$kBaseUrl/api/$kApiVersionUrl/$kProgramsUrl/$id/$kCoursesUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data']['courses'] as List; + learnCourses = decodedData.map( + (e) { + return LearnCourse.fromJson(e); + }, + ).toList(); + return learnCourses; + } + return []; + } catch (e) { + return []; + } + } + + // Learn course practices + Future> getLearnCoursePractices(int id) async { + try { + List practices = []; + + final Response response = await _service.dio + .get('$kBaseUrl/api/$kApiVersionUrl/$kCoursesUrl/$id/$kPracticesUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data']['practices'] as List; + practices = decodedData.map( + (e) { + return LearnPractice.fromJson(e); + }, + ).toList(); + return practices; + } + return []; + } catch (e) { + return []; + } + } + + // Get learn modules + Future> getLearnModules(int id) async { + try { + List modules = []; + + final Response response = await _service.dio + .get('$kBaseUrl/api/$kApiVersionUrl/$kCoursesUrl/$id/$kModulesUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data']['modules'] as List; + modules = decodedData.map( + (e) { + return LearnModule.fromJson(e); + }, + ).toList(); + return modules; + } + return []; + } catch (e) { + return []; + } + } + + // Learn module practices + Future> getLearnModulePractices(int id) async { + try { + List practices = []; + + final Response response = await _service.dio + .get('$kBaseUrl/api/$kApiVersionUrl/$kModulesUrl/$id/$kPracticesUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data'] as List; + practices = decodedData.map( + (e) { + return LearnPractice.fromJson(e); + }, + ).toList(); + return practices; + } + return []; + } catch (e) { + return []; + } + } + + // Get learn lessons + Future> getLearnLessons(int id) async { + try { + List lessons = []; + + final Response response = await _service.dio + .get('$kBaseUrl/api/$kApiVersionUrl/$kModulesUrl/$id/$kLessonsUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data']['lessons'] as List; + lessons = decodedData.map( + (e) { + return LearnLesson.fromJson(e); + }, + ).toList(); + return lessons; + } + return []; + } catch (e) { + return []; + } + } + + // Learn lesson practices + Future> getLearnLessonPractices(int id) async { + try { + List practices = []; + + final Response response = await _service.dio + .get('$kBaseUrl/api/$kApiVersionUrl/$kLessonsUrl/$id/$kPracticesUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data']['practices'] as List; + practices = decodedData.map( + (e) { + return LearnPractice.fromJson(e); + }, + ).toList(); + return practices; + } + return []; + } catch (e) { + return []; + } + } + + // Get learn questions + Future> getLearnQuestions(int id) async { + try { + List questions = []; + print('Here'); + + final Response response = await _service.dio.get( + '$kBaseUrl/api/$kApiVersionUrl/$kQuestionSetsUrl/$id/$kQuestionsUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data'] as List; + questions = decodedData.map( + (e) { + return LearnQuestion.fromJson(e); + }, + ).toList(); + return questions; + } + return []; + } catch (e) { + return []; + } + } + + /* TO BE MODIFIED*/ + // Get categories Future> getCategories() async { try { @@ -541,9 +741,9 @@ class ApiService { } // Get course practic questions - Future> getCoursePracticeQuestions(int id) async { + Future> getCoursePracticeQuestions(int id) async { try { - List coursePracticeQuestions = []; + List coursePracticeQuestions = []; final Response response = await _service.dio .get('$kBaseUrl/$kPracticeBaseUrl/$id/$kCoursePracticeQuestions'); @@ -553,7 +753,7 @@ class ApiService { var decodedData = data['data'] as List; coursePracticeQuestions = decodedData.map( (e) { - return PracticeQuestion.fromJson(e); + return Question.fromJson(e); }, ).toList(); return coursePracticeQuestions; @@ -724,4 +924,52 @@ class ApiService { return []; } } + + // Practices + Future> getPractices(int id) async { + try { + List coursePractices = []; + + final Response response = await _service.dio.get( + '$kBaseUrl/$kPracticeBaseUrl/$kCoursePractice?owner_type=SUB_MODULE&owner_id=$id'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data'] as List; + coursePractices = decodedData.map( + (e) { + return Practice.fromJson(e); + }, + ).toList(); + return coursePractices; + } + return []; + } catch (e) { + return []; + } + } + + // Questions + Future> getQuestions(int id) async { + try { + List questions = []; + + final Response response = await _service.dio.get( + '$kBaseUrl/api/$kApiVersionUrl/$kQuestionSetsUrl/$id/$kQuestionsUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data'] as List; + questions = decodedData.map( + (e) { + return Question.fromJson(e); + }, + ).toList(); + return questions; + } + return []; + } catch (e) { + return []; + } + } } diff --git a/lib/services/audio_player_service.dart b/lib/services/audio_player_service.dart index b290236..b0b352d 100644 --- a/lib/services/audio_player_service.dart +++ b/lib/services/audio_player_service.dart @@ -21,7 +21,7 @@ class AudioPlayerService with ListenableServiceMixin { Stream get stateStream => _player.onPlayerStateChanged; Future playUrl(String url) async { - final playableUrl = getPlayableUrl(url); + final playableUrl = getReadableUrl(url); if (playableUrl == null) { throw Exception("Invalid audio URL"); diff --git a/lib/services/in_app_update_service.dart b/lib/services/in_app_update_service.dart new file mode 100644 index 0000000..0b5dd28 --- /dev/null +++ b/lib/services/in_app_update_service.dart @@ -0,0 +1,54 @@ +import 'package:battery_plus/battery_plus.dart'; +import 'package:flutter/services.dart'; +import 'package:in_app_update/in_app_update.dart'; +import 'package:storage_info/storage_info.dart'; + +class InAppUpdateService { + Future getBatteryLevel() async { + final battery = Battery(); + final batteryLevel = await battery.batteryLevel; + return batteryLevel; + } + + Future getAvailableStorage() async { + try { + final availableStorage = + await StorageInfo().getStorageFreeSpace(SpaceUnit.Bytes); + return availableStorage.toInt(); // Convert GB to bytes + } catch (e) { + return 0; + } + } + + Future checkForUpdate() async { + const requiredStorage = 500 * 1024 * 1024; + + final batteryLevel = + await getBatteryLevel(); // Implement getBatteryLevel function + final int storageAvailable = + await getAvailableStorage(); // Implement getAvailableStorage + if (batteryLevel < 20 || storageAvailable < requiredStorage) { + if (batteryLevel < 20 || storageAvailable < requiredStorage) { + // KewedeConst().showErrorToast( + // 'Unable to update app, please charge your phone & free up space.'); + } else if (batteryLevel < 20) { + // KewedeConst() + // .showErrorToast('Unable to update app, please charge your phone.'); + } else if (storageAvailable < requiredStorage) { + // KewedeConst() + // .showErrorToast('Unable to update app, please free up space.'); + } + // Show user-friendly message explaining why update failed and suggesting solutions (e.g., charge device, free up space) + } + try { + final info = await InAppUpdate.checkForUpdate(); + if (info.updateAvailability == UpdateAvailability.updateAvailable) { + await InAppUpdate.completeFlexibleUpdate(); + } + + // ... rest of your update logic ... + } on PlatformException { + // Handle specific error code for better user experience and potentially different error messages for each issue + } + } +} diff --git a/lib/services/status_checker_service.dart b/lib/services/status_checker_service.dart index 180c212..7ff004e 100644 --- a/lib/services/status_checker_service.dart +++ b/lib/services/status_checker_service.dart @@ -1,8 +1,4 @@ -import 'package:battery_plus/battery_plus.dart'; -import 'package:flutter/services.dart'; -import 'package:in_app_update/in_app_update.dart'; import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart'; -import 'package:storage_info/storage_info.dart'; import 'package:yimaru_app/services/secure_storage_service.dart'; import '../app/app.locator.dart'; @@ -16,13 +12,6 @@ class StatusCheckerService { bool get previousConnection => _previousConnection; - // Get phone battery level - Future getBatteryLevel() async { - final battery = Battery(); - final batteryLevel = await battery.batteryLevel; - return batteryLevel; - } - // Check internet connection Future checkConnection() async { if (await InternetConnection().hasInternetAccess) { @@ -36,45 +25,4 @@ class StatusCheckerService { return false; } } - - // Check phone available storage - Future getAvailableStorage() async { - try { - final availableStorage = - await StorageInfo().getStorageFreeSpace(SpaceUnit.Bytes); - return availableStorage.toInt(); // Convert GB to bytes - } catch (e) { - return 0; - } - } - - // Check for latest update - Future checkAndUpdate() async { - const requiredStorage = 500 * 1024 * 1024; - - final batteryLevel = - await getBatteryLevel(); // Implement getBatteryLevel function - final int storageAvailable = - await getAvailableStorage(); // Implement getAvailableStorage - if (batteryLevel < 20 || storageAvailable < requiredStorage) { - if (batteryLevel < 20 || storageAvailable < requiredStorage) { - // 'Unable to update app, please charge your phone & free up space.'); - } else if (batteryLevel < 20) { - // .showErrorToast('Unable to update app, please charge your phone.'); - } else if (storageAvailable < requiredStorage) { - // .showErrorToast('Unable to update app, please free up space.'); - } - return; // Prevent update from starting - } - try { - if (await checkConnection()) { - await InAppUpdate - .checkForUpdate(); // Continue update only if sufficient resources available - } - - // ... rest of your update logic ... - } on PlatformException { - // Handle specific error code for better user experience and potentially different error messages for each issue - } - } } diff --git a/lib/services/voice_recorder_service.dart b/lib/services/voice_recorder_service.dart index 56218a1..64bfca6 100644 --- a/lib/services/voice_recorder_service.dart +++ b/lib/services/voice_recorder_service.dart @@ -14,6 +14,12 @@ class VoiceRecorderService with ListenableServiceMixin { WaveformRecorderController get waveController => _waveController; + + bool _isRecording = false; + + bool get isRecording => _isRecording; + + // Start voice recording Future startRecording() async { await _waveController.startRecording(); @@ -35,4 +41,5 @@ class VoiceRecorderService with ListenableServiceMixin { if (file == null) return null; return file.path; } + } diff --git a/lib/ui/common/app_constants.dart b/lib/ui/common/app_constants.dart index da5fcfb..3b58b84 100644 --- a/lib/ui/common/app_constants.dart +++ b/lib/ui/common/app_constants.dart @@ -12,8 +12,14 @@ String kModulesUrl = 'modules'; String kLessonsUrl = 'lessons'; +String kProgramsUrl = 'programs'; + String kRegisterUrl = 'register'; +String kPracticesUrl = 'practices'; + +String kQuestionsUrl = 'questions'; + String kCategoryUrl = 'categories'; String kCoursePractice = 'by-owner'; @@ -34,6 +40,8 @@ String kCompleteLessonUrl = 'complete'; String kResetPassword = 'resetPassword'; +String kQuestionSetsUrl = 'question-sets'; + String kRequestResetCode = 'sendResetCode'; String kSubcategoriesUrl = 'sub-categories'; diff --git a/lib/ui/common/enmus.dart b/lib/ui/common/enmus.dart index f56f05d..b9c3241 100644 --- a/lib/ui/common/enmus.dart +++ b/lib/ui/common/enmus.dart @@ -1,3 +1,6 @@ +// Practice voice +enum Voice { sample, recorded } + // Response status enum ResponseStatus { success, failure } @@ -7,6 +10,9 @@ enum LoginMethod { phone, email, google } // Sign-up method enum SignUpMethod { phone, email, google } +// Learn practice +enum LearnPractices { course, module, lesson } + // Voice recording state enum VoiceRecordingState { pending, recording } @@ -16,8 +22,8 @@ enum ProficiencyLevels { a1, a2, b1, b2, none } // Progress status enum ProgressStatuses { pending, started, completed } -// Duolingo assessment types -enum DuolingoAssessmentType { speaking, reading, writing, listening } +// Duolingo types +enum DuolingoAssessments { speaking, reading, writing, listening } // State object enum StateObjects { @@ -27,17 +33,18 @@ enum StateObjects { register, verifyOtp, resendOtp, - learnLevels, learnLessons, learnModules, learnCourses, profileImage, + learnPrograms, courseLessons, profileUpdate, resetPassword, subcategories, loginWithEmail, coursePractice, + learnPractices, loginWithGoogle, loadLessonVideo, loadCourseVideo, @@ -46,7 +53,6 @@ enum StateObjects { courseCategories, profileCompletion, registerWithGoogle, - learnSubcategories, learnPracticeSample, learnPracticeAnswer, loginWithPhoneNumber, diff --git a/lib/ui/common/helper_functions.dart b/lib/ui/common/helper_functions.dart index eac0293..b132ff2 100644 --- a/lib/ui/common/helper_functions.dart +++ b/lib/ui/common/helper_functions.dart @@ -46,7 +46,7 @@ Color getColor() { } // Get playable url -String? getPlayableUrl(String url) { +String? getReadableUrl(String url) { try { // Case 1: /file/d/FILE_ID/view final fileIdRegex = RegExp(r'/file/d/([a-zA-Z0-9_-]+)'); diff --git a/lib/ui/views/course_practice_question/course_practice_question_view.form.dart b/lib/ui/views/course_practice_question/course_practice_question_view.form.dart index c47bf09..039ff64 100644 --- a/lib/ui/views/course_practice_question/course_practice_question_view.form.dart +++ b/lib/ui/views/course_practice_question/course_practice_question_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -145,7 +146,7 @@ extension ValueProperties on FormStateHelper { } extension Methods on FormStateHelper { - setAnswerValidationMessage(String? validationMessage) => + void setAnswerValidationMessage(String? validationMessage) => this.fieldsValidationMessages[AnswerValueKey] = validationMessage; /// Clears text input fields on the Form @@ -167,7 +168,7 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _CoursePracticeQuestionViewTextEditingControllers[key]!.text, + _CoursePracticeQuestionViewTextEditingControllers[key]?.text, ); return validationMessageForKey; diff --git a/lib/ui/views/course_practice_question/course_practice_question_viewmodel.dart b/lib/ui/views/course_practice_question/course_practice_question_viewmodel.dart index 67cce1b..db08193 100644 --- a/lib/ui/views/course_practice_question/course_practice_question_viewmodel.dart +++ b/lib/ui/views/course_practice_question/course_practice_question_viewmodel.dart @@ -1,7 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; -import 'package:yimaru_app/models/practice_question.dart'; import '../../../app/app.locator.dart'; import '../../../models/option.dart'; @@ -43,10 +42,9 @@ class CoursePracticeQuestionViewModel extends FormViewModel { Question? get currentQuestion => _currentQuestion; - List _coursePracticeQuestions = []; + List _coursePracticeQuestions = []; - List get coursePracticeQuestions => - _coursePracticeQuestions; + List get coursePracticeQuestions => _coursePracticeQuestions; int _currentQuestionIndex = 0; @@ -184,8 +182,8 @@ class CoursePracticeQuestionViewModel extends FormViewModel { _coursePracticeQuestions = await _apiService.getCoursePracticeQuestions(id); if (_coursePracticeQuestions.isNotEmpty) { - _currentQuestion = await _apiService.getCoursePracticeQuestion( - coursePracticeQuestions.first.questionId ?? 0); + _currentQuestion = await _apiService + .getCoursePracticeQuestion(coursePracticeQuestions.first.id ?? 0); } } } diff --git a/lib/ui/views/duolingo/duolingo_view.form.dart b/lib/ui/views/duolingo/duolingo_view.form.dart index de325c5..df5a2cf 100644 --- a/lib/ui/views/duolingo/duolingo_view.form.dart +++ b/lib/ui/views/duolingo/duolingo_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -143,7 +144,7 @@ extension ValueProperties on FormStateHelper { } extension Methods on FormStateHelper { - setAssessmentValidationMessage(String? validationMessage) => + void setAssessmentValidationMessage(String? validationMessage) => this.fieldsValidationMessages[AssessmentValueKey] = validationMessage; /// Clears text input fields on the Form @@ -165,7 +166,7 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _DuolingoViewTextEditingControllers[key]!.text, + _DuolingoViewTextEditingControllers[key]?.text, ); return validationMessageForKey; diff --git a/lib/ui/views/duolingo/duolingo_viewmodel.dart b/lib/ui/views/duolingo/duolingo_viewmodel.dart index d5d08b8..af4983c 100644 --- a/lib/ui/views/duolingo/duolingo_viewmodel.dart +++ b/lib/ui/views/duolingo/duolingo_viewmodel.dart @@ -26,7 +26,7 @@ class DuolingoViewModel extends FormViewModel { Map _selectedAssessment = { 'label': 'Speaking 01', 'intro_title': 'Speak About the Photo', - 'type': DuolingoAssessmentType.speaking, + 'type': DuolingoAssessments.speaking, 'outro_title': 'Speaking Practice Completed', 'outro_subtitle': 'You’ve finished this speaking session. Great work!', 'intro_subtitle': @@ -40,7 +40,7 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Speaking 01', 'intro_title': 'Speak About the Photo', - 'type': DuolingoAssessmentType.speaking, + 'type': DuolingoAssessments.speaking, 'outro_title': 'Speaking Practice Completed', 'outro_subtitle': 'You’ve finished this speaking session. Great work!', 'intro_subtitle': @@ -49,7 +49,7 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Speaking 02', 'intro_title': 'Read, Then Speak', - 'type': DuolingoAssessmentType.speaking, + 'type': DuolingoAssessments.speaking, 'outro_title': 'Speaking Practice Completed', 'intro_subtitle': 'You will speak about the given topic', 'outro_subtitle': 'You’ve finished this speaking session. Great work!', @@ -57,7 +57,7 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Speaking 03', 'intro_title': 'Speaking Sample', - 'type': DuolingoAssessmentType.speaking, + 'type': DuolingoAssessments.speaking, 'outro_title': 'Speaking Practice Completed', 'intro_subtitle': 'You’ll speak for 1–3 minutes about a given topic.', 'outro_subtitle': 'You’ve finished this speaking session. Great work!', @@ -65,7 +65,7 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Speaking 04', 'intro_title': 'Interactive Speaking', - 'type': DuolingoAssessmentType.speaking, + 'type': DuolingoAssessments.speaking, 'outro_title': 'Speaking Practice Completed', 'intro_subtitle': ' You’ll answer a series of short questions.', 'outro_subtitle': 'You’ve finished this speaking session. Great work!', @@ -73,7 +73,7 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Writing 05', 'intro_title': 'Write About the Photo', - 'type': DuolingoAssessmentType.writing, + 'type': DuolingoAssessments.writing, 'outro_title': 'Writing Practice Completed', 'outro_subtitle': 'You’ve finished this writing session. Great work!', 'intro_subtitle': @@ -82,7 +82,7 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Writing 06', 'intro_title': 'Writing Sample', - 'type': DuolingoAssessmentType.writing, + 'type': DuolingoAssessments.writing, 'outro_title': 'Writing Practice Completed', 'outro_subtitle': 'You’ve finished this writing session. Great work!', 'intro_subtitle': @@ -90,7 +90,7 @@ class DuolingoViewModel extends FormViewModel { }, { 'label': 'Writing 07', - 'type': DuolingoAssessmentType.writing, + 'type': DuolingoAssessments.writing, 'outro_title': 'Writing Practice Completed', 'intro_title': 'Interactive Writing Part 1', 'outro_subtitle': 'You’ve finished this writing session. Great work!', @@ -99,7 +99,7 @@ class DuolingoViewModel extends FormViewModel { }, { 'label': 'Writing 08', - 'type': DuolingoAssessmentType.writing, + 'type': DuolingoAssessments.writing, 'intro_title': 'Interactive Writing Part 2', 'outro_title': 'Writing Practice Completed', 'outro_subtitle': 'You’ve finished this writing session. Great work!', @@ -109,7 +109,7 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Listening 09', 'intro_title': 'Listen and Type', - 'type': DuolingoAssessmentType.listening, + 'type': DuolingoAssessments.listening, 'outro_title': 'Listening Practice Completed', 'intro_subtitle': 'You will hear a short audio clip. Type exactly what you hear.', @@ -117,7 +117,7 @@ class DuolingoViewModel extends FormViewModel { }, { 'label': 'Listening 10', - 'type': DuolingoAssessmentType.listening, + 'type': DuolingoAssessments.listening, 'outro_title': 'Listening Practice Completed', 'intro_title': 'Interactive Listening - Part 1', 'intro_subtitle': ' Listen carefully and complete the missing words.', @@ -125,7 +125,7 @@ class DuolingoViewModel extends FormViewModel { }, { 'label': 'Listening 11', - 'type': DuolingoAssessmentType.listening, + 'type': DuolingoAssessments.listening, 'outro_title': 'Listening Practice Completed', 'intro_title': 'Interactive Listening - Part 2', 'intro_subtitle': 'Listen and choose the correct option.', @@ -133,7 +133,7 @@ class DuolingoViewModel extends FormViewModel { }, { 'label': 'Assessment 12', - 'type': DuolingoAssessmentType.listening, + 'type': DuolingoAssessments.listening, 'title': 'Interactive Listening - Part 3', 'outro_title': 'Listening Practice Completed', 'subtitle': 'Write a summary of the conversation you just had', @@ -142,14 +142,14 @@ class DuolingoViewModel extends FormViewModel { { 'label': 'Reading 13', 'intro_title': 'Read and Select', - 'type': DuolingoAssessmentType.reading, + 'type': DuolingoAssessments.reading, 'intro_subtitle': 'Read the sentence and select the option that correctly completes the meaning.' }, { 'label': 'Reading 14', 'intro_title': 'Fill in the blank', - 'type': DuolingoAssessmentType.reading, + 'type': DuolingoAssessments.reading, 'intro_subtitle': 'Complete the sentences by filling in the missing words' }, ]; diff --git a/lib/ui/views/duolingo/screens/duolingo_intro_screen.dart b/lib/ui/views/duolingo/screens/duolingo_intro_screen.dart index 258722f..2a977ac 100644 --- a/lib/ui/views/duolingo/screens/duolingo_intro_screen.dart +++ b/lib/ui/views/duolingo/screens/duolingo_intro_screen.dart @@ -13,7 +13,7 @@ import '../../../widgets/wave_wrapper.dart'; class DuolingoIntroScreen extends ViewModelWidget { final String title; final String subtitle; - final DuolingoAssessmentType type; + final DuolingoAssessments type; const DuolingoIntroScreen( {super.key, @@ -22,11 +22,11 @@ class DuolingoIntroScreen extends ViewModelWidget { required this.subtitle}); IconData _getIcon() { - if (type == DuolingoAssessmentType.speaking) { + if (type == DuolingoAssessments.speaking) { return Icons.waves; - } else if (type == DuolingoAssessmentType.writing) { + } else if (type == DuolingoAssessments.writing) { return Iconsax.pen_add; - } else if (type == DuolingoAssessmentType.listening) { + } else if (type == DuolingoAssessments.listening) { return Icons.hearing; } else { return Icons.book; diff --git a/lib/ui/views/forget_password/forget_password_view.form.dart b/lib/ui/views/forget_password/forget_password_view.form.dart index 0780f96..a7ede5d 100644 --- a/lib/ui/views/forget_password/forget_password_view.form.dart +++ b/lib/ui/views/forget_password/forget_password_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -230,13 +231,13 @@ extension ValueProperties on FormStateHelper { } extension Methods on FormStateHelper { - setPasswordValidationMessage(String? validationMessage) => + void setPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PasswordValueKey] = validationMessage; - setResetCodeValidationMessage(String? validationMessage) => + void setResetCodeValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ResetCodeValueKey] = validationMessage; - setEmailValidationMessage(String? validationMessage) => + void setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - setConfirmPasswordValidationMessage(String? validationMessage) => + void setConfirmPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ConfirmPasswordValueKey] = validationMessage; @@ -265,7 +266,7 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _ForgetPasswordViewTextEditingControllers[key]!.text, + _ForgetPasswordViewTextEditingControllers[key]?.text, ); return validationMessageForKey; diff --git a/lib/ui/views/home/home_view.dart b/lib/ui/views/home/home_view.dart index 3235d78..f7343f8 100644 --- a/lib/ui/views/home/home_view.dart +++ b/lib/ui/views/home/home_view.dart @@ -3,9 +3,10 @@ import 'package:stacked/stacked.dart'; import 'package:yimaru_app/ui/common/app_colors.dart'; import 'package:yimaru_app/ui/common/enmus.dart'; import 'package:yimaru_app/ui/views/course_category/course_category_view.dart'; -import 'package:yimaru_app/ui/views/learn_subcategory/learn_subcategory_view.dart'; +import 'package:yimaru_app/ui/views/learn_program/learn_program_view.dart'; import 'package:yimaru_app/ui/views/profile/profile_view.dart'; import 'package:yimaru_app/ui/views/startup/startup_view.dart'; +import 'package:yimaru_app/ui/widgets/coming_soon.dart'; import 'home_viewmodel.dart'; @@ -18,7 +19,6 @@ class HomeView extends StackedView { @override void onViewModelReady(HomeViewModel viewModel) async { // Removable - print('HERE'); await _init(viewModel); super.onViewModelReady(viewModel); } @@ -83,9 +83,9 @@ Widget _buildProfileIcon() => const Icon(Icons.person); Widget getViewForIndex(int index) { switch (index) { case 0: - return const LearnSubcategoryView(); + return const LearnProgramView(); case 1: - return const CourseCategoryView(); + return const ComingSoon(); default: return const ProfileView(); diff --git a/lib/ui/views/learn/learn_view.dart b/lib/ui/views/learn/learn_view.dart deleted file mode 100644 index 6651270..0000000 --- a/lib/ui/views/learn/learn_view.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/ui/widgets/learn_tile.dart'; - -import '../../../models/course.dart'; -import '../../common/app_colors.dart'; -import '../../common/enmus.dart'; -import '../../common/ui_helpers.dart'; -import '../../widgets/custom_circular_progress_indicator.dart'; -import '../../widgets/small_app_bar.dart'; -import 'learn_viewmodel.dart'; - -class LearnView extends StackedView { - final int id; - - const LearnView({Key? key, required this.id}) : super(key: key); - - @override - void onViewModelReady(LearnViewModel viewModel) async { - await viewModel.getCourses(id); - super.onViewModelReady(viewModel); - } - - @override - LearnViewModel viewModelBuilder(BuildContext context) => LearnViewModel(); - - @override - Widget builder( - BuildContext context, - LearnViewModel viewModel, - Widget? child, - ) => - _buildScaffoldWrapper(viewModel); - - Widget _buildScaffoldWrapper(LearnViewModel viewModel) => Scaffold( - backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), - ); - - Widget _buildScaffold(LearnViewModel viewModel) => - SafeArea(child: _buildBody(viewModel)); - - Widget _buildBody(LearnViewModel viewModel) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), - ); - - Widget _buildColumn(LearnViewModel viewModel) => Column( - children: [ - verticalSpaceMedium, - _buildAppBar(viewModel), - verticalSpaceMedium, - _buildLearnColumnWrapper(viewModel) - ], - ); - - Widget _buildAppBar(LearnViewModel viewModel) => SmallAppBar( - onTap: viewModel.pop, - showBackButton: true, - ); - - Widget _buildLearnColumnWrapper(LearnViewModel viewModel) => - Expanded(child: _buildLearnColumnScrollView(viewModel)); - - Widget _buildLearnColumnScrollView(LearnViewModel viewModel) => - SingleChildScrollView( - child: _buildListViewBuilder(viewModel), - ); - - Widget _buildListViewBuilder(LearnViewModel viewModel) => - viewModel.busy(StateObjects.learnCourses) - ? _buildProgressIndicator() - : _buildListView(viewModel); - - Widget _buildProgressIndicator() => const Center( - child: CustomCircularProgressIndicator(color: kcPrimaryColor), - ); - - Widget _buildListView(LearnViewModel viewModel) => ListView.separated( - shrinkWrap: true, - itemCount: viewModel.courses.length, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (context, index) => verticalSpaceSmall, - itemBuilder: (context, index) => _buildTile( - course: viewModel.courses[index], - onTap: () async => await viewModel - .navigateToLearnLevel(viewModel.courses[index].id ?? 0), - ), - ); - - Widget _buildTile({ - required Course course, - required GestureTapCallback onTap, - }) => - LearnTile( - onTap: onTap, - course: course, - ); -} diff --git a/lib/ui/views/learn/learn_viewmodel.dart b/lib/ui/views/learn/learn_viewmodel.dart deleted file mode 100644 index 0b890bd..0000000 --- a/lib/ui/views/learn/learn_viewmodel.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:stacked/stacked.dart'; -import 'package:stacked_services/stacked_services.dart'; -import 'package:yimaru_app/app/app.router.dart'; -import 'package:yimaru_app/models/course.dart'; -import 'package:yimaru_app/ui/common/enmus.dart'; - -import '../../../app/app.locator.dart'; -import '../../../services/api_service.dart'; -import '../../../services/status_checker_service.dart'; - -class LearnViewModel extends BaseViewModel { - // Dependency injection - final _apiService = locator(); - - final _statusChecker = locator(); - - final _navigationService = locator(); - - // Learn courses - List _courses = []; - - List get courses => _courses; - - // Navigation - void pop() => _navigationService.back(); - - Future navigateToLearnLevel(int id) async => - _navigationService.navigateToLearnLevelView(id: id); - - // Remote api call - - // Learn courses - Future getCourses(int id) async => await runBusyFuture(_getCourses(id), - busyObject: StateObjects.learnCourses); - - Future _getCourses(int id) async { - if (_courses.isEmpty) { - if (await _statusChecker.checkConnection()) { - _courses = await _apiService.getCourses(id); - } - } - } -} diff --git a/lib/ui/views/learn_course/learn_course_view.dart b/lib/ui/views/learn_course/learn_course_view.dart new file mode 100644 index 0000000..6625bbc --- /dev/null +++ b/lib/ui/views/learn_course/learn_course_view.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/learn_course.dart'; + +import '../../common/app_colors.dart'; +import '../../common/enmus.dart'; +import '../../common/ui_helpers.dart'; +import '../../widgets/custom_circular_progress_indicator.dart'; +import '../../widgets/learn_course_tile.dart'; +import '../../widgets/small_app_bar.dart'; +import 'learn_course_viewmodel.dart'; + +class LearnCourseView extends StackedView { + final int id; + const LearnCourseView({Key? key, required this.id}) : super(key: key); + + @override + void onViewModelReady(LearnCourseViewModel viewModel) async { + await viewModel.getLearnCourses(id); + super.onViewModelReady(viewModel); + } + + @override + LearnCourseViewModel viewModelBuilder(BuildContext context) => + LearnCourseViewModel(); + + @override + Widget builder( + BuildContext context, + LearnCourseViewModel viewModel, + Widget? child, + ) => + _buildScaffoldWrapper(viewModel); + + Widget _buildScaffoldWrapper(LearnCourseViewModel viewModel) => Scaffold( + backgroundColor: kcBackgroundColor, + body: _buildScaffold(viewModel), + ); + + Widget _buildScaffold(LearnCourseViewModel viewModel) => + SafeArea(child: _buildBody(viewModel)); + + Widget _buildBody(LearnCourseViewModel viewModel) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: _buildColumn(viewModel), + ); + + Widget _buildColumn(LearnCourseViewModel viewModel) => Column( + children: [ + verticalSpaceMedium, + _buildAppBar(viewModel), + verticalSpaceMedium, + _buildCoursesColumnWrapper(viewModel) + ], + ); + + Widget _buildAppBar(LearnCourseViewModel viewModel) => SmallAppBar( + onTap: viewModel.pop, + showBackButton: true, + ); + + Widget _buildCoursesColumnWrapper(LearnCourseViewModel viewModel) => + Expanded(child: _buildLevelsColumnScrollView(viewModel)); + + Widget _buildLevelsColumnScrollView(LearnCourseViewModel viewModel) => + SingleChildScrollView( + child: _buildListViewBuilder(viewModel), + ); + + Widget _buildListViewBuilder(LearnCourseViewModel viewModel) => + viewModel.busy(StateObjects.learnCourses) + ? _buildProgressIndicator() + : _buildListView(viewModel); + + Widget _buildProgressIndicator() => const Center( + child: CustomCircularProgressIndicator(color: kcPrimaryColor), + ); + + Widget _buildListView(LearnCourseViewModel viewModel) => ListView.separated( + shrinkWrap: true, + itemCount: viewModel.learnCourses.length, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (context, index) => _buildTile( + course: viewModel.learnCourses[index], + onViewTap: () async => await viewModel + .navigateToLearnModule(viewModel.learnCourses[index]), + onPracticeTap: () async => await viewModel + .navigateToLearnPractice(viewModel.learnCourses[index].id ?? 0), + ), + separatorBuilder: (context, index) => verticalSpaceSmall, + ); + + Widget _buildTile({ + required LearnCourse course, + required GestureTapCallback onViewTap, + required GestureTapCallback onPracticeTap, + }) => + LearnCourseTile( + course: course, + onViewTap: onViewTap, + onPracticeTap: onPracticeTap, + ); +} diff --git a/lib/ui/views/learn_course/learn_course_viewmodel.dart b/lib/ui/views/learn_course/learn_course_viewmodel.dart new file mode 100644 index 0000000..c27c5b6 --- /dev/null +++ b/lib/ui/views/learn_course/learn_course_viewmodel.dart @@ -0,0 +1,49 @@ +import 'package:stacked/stacked.dart'; +import 'package:stacked_services/stacked_services.dart'; +import 'package:yimaru_app/app/app.router.dart'; + +import '../../../app/app.locator.dart'; +import '../../../models/learn_course.dart'; +import '../../../services/api_service.dart'; +import '../../../services/status_checker_service.dart'; +import '../../common/enmus.dart'; + +class LearnCourseViewModel extends BaseViewModel { + // Dependency injection + final _apiService = locator(); + + final _statusChecker = locator(); + + final _navigationService = locator(); + + // Learn courses + List _learnCourses = []; + + List get learnCourses => _learnCourses; + + // Navigation + void pop() => _navigationService.back(); + + Future navigateToLearnModule(LearnCourse course) async => + _navigationService.navigateToLearnModuleView(course: course); + + Future navigateToLearnPractice(int id) async => await _navigationService + .navigateToLearnPracticeView(id: id, practice: LearnPractices.course); + + // Remote api call + + // Learn courses + Future getLearnCourses(int id) async => + await runBusyFuture(_getLearnCourses(id), + busyObject: StateObjects.learnCourses); + + Future _getLearnCourses(int id) async { + if (_learnCourses.isEmpty) { + if (await _statusChecker.checkConnection()) { + _learnCourses = await _apiService.getLearnCourse(id); + _learnCourses + .sort((a, b) => (a.sortOrder ?? 0).compareTo(b.sortOrder ?? 0)); + } + } + } +} diff --git a/lib/ui/views/learn_lesson/learn_lesson_view.dart b/lib/ui/views/learn_lesson/learn_lesson_view.dart index 7d324f0..de667d0 100644 --- a/lib/ui/views/learn_lesson/learn_lesson_view.dart +++ b/lib/ui/views/learn_lesson/learn_lesson_view.dart @@ -1,12 +1,12 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/models/submodule.dart'; +import 'package:yimaru_app/models/learn_lesson.dart'; +import 'package:yimaru_app/models/learn_module.dart'; import 'package:yimaru_app/ui/common/enmus.dart'; import 'package:yimaru_app/ui/widgets/learn_lesson_tile.dart'; import 'package:yimaru_app/ui/widgets/module_progress.dart'; import 'package:yimaru_app/ui/widgets/motivation_card.dart'; -import '../../../models/lesson.dart'; import '../../common/app_colors.dart'; import '../../common/ui_helpers.dart'; import '../../widgets/custom_circular_progress_indicator.dart'; @@ -14,18 +14,16 @@ import '../../widgets/small_app_bar.dart'; import 'learn_lesson_viewmodel.dart'; class LearnLessonView extends StackedView { - final Submodule submodule; - - const LearnLessonView({Key? key, required this.submodule}) : super(key: key); + final LearnModule module; + const LearnLessonView({Key? key, required this.module}) : super(key: key); @override void onViewModelReady(LearnLessonViewModel viewModel) async { - await viewModel.getLessons(submodule.id ?? 0); + await viewModel.getLessons(module.id ?? 0); super.onViewModelReady(viewModel); } - Widget getPadding(context) { double half = screenHeight(context) / 2; return SizedBox( @@ -116,10 +114,8 @@ class LearnLessonView extends StackedView { verticalSpaceTiny, _buildSubtitle(), verticalSpaceSmall, - verticalSpaceSmall, _buildModuleProgress(), verticalSpaceMedium, - verticalSpaceMedium, _buildMotivationCard(), verticalSpaceMedium, _buildHeader(), @@ -128,13 +124,13 @@ class LearnLessonView extends StackedView { ]; Widget _buildTitle() => Text( - submodule.title ?? '', + module.name ?? '', style: style16DG600, ); Widget _buildSubtitle() => Text( - submodule.description ?? '', - style: style14DG600, + module.description ?? '', + style: style14DG500, ); Widget _buildModuleProgress() => const ModuleProgress(); @@ -146,16 +142,14 @@ class LearnLessonView extends StackedView { style: style18DG700, ); - Widget _buildListViewBuilder(LearnLessonViewModel viewModel) => viewModel.busy(StateObjects.learnLessons) ? _buildProgressIndicator() : _buildListView(viewModel); Widget _buildProgressIndicator() => const Center( - child: CustomCircularProgressIndicator(color: kcPrimaryColor), - ); - + child: CustomCircularProgressIndicator(color: kcPrimaryColor), + ); Widget _buildListView(LearnLessonViewModel viewModel) => ListView.builder( shrinkWrap: true, @@ -163,16 +157,21 @@ class LearnLessonView extends StackedView { physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _buildTile( lesson: viewModel.lessons[index], - onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(viewModel.lessons[index]), + onLessonTap: () async => await viewModel + .navigateToLearnLessonDetail(viewModel.lessons[index]), + onPracticeTap: () async => await viewModel + .navigateToLearnPractice(viewModel.lessons[index].id ?? 0), ), ); Widget _buildTile({ - required Lesson lesson, + required LearnLesson lesson, required GestureTapCallback? onLessonTap, + required GestureTapCallback? onPracticeTap, }) => LearnLessonTile( lesson: lesson, onLessonTap: onLessonTap, + onPracticeTap: onPracticeTap, ); } diff --git a/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart b/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart index b3cc5e6..b909469 100644 --- a/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart +++ b/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart @@ -1,10 +1,10 @@ import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; import 'package:yimaru_app/app/app.router.dart'; +import 'package:yimaru_app/models/learn_lesson.dart'; import 'package:yimaru_app/ui/common/enmus.dart'; import '../../../app/app.locator.dart'; -import '../../../models/lesson.dart'; import '../../../services/api_service.dart'; import '../../../services/status_checker_service.dart'; @@ -17,28 +17,30 @@ class LearnLessonViewModel extends BaseViewModel { final _navigationService = locator(); // Learn lessons - List _lessons = []; + List _lessons = []; - List get lessons => _lessons; + List get lessons => _lessons; // Navigation void pop() => _navigationService.back(); - Future navigateToLearnLessonDetail(Lesson lesson) async => + Future navigateToLearnPractice(int id) async => await _navigationService + .navigateToLearnPracticeView(id: id, practice: LearnPractices.lesson); + + Future navigateToLearnLessonDetail(LearnLesson lesson) async => await _navigationService.navigateToLearnLessonDetailView(lesson: lesson); // Remote api call - // Learn modules + // Learn lessons Future getLessons(int id) async => await runBusyFuture(_getLessons(id), busyObject: StateObjects.learnLessons); Future _getLessons(int id) async { if (_lessons.isEmpty) { if (await _statusChecker.checkConnection()) { - _lessons = await _apiService.getLessons(id); - _lessons.sort( - (a, b) => (a.displayOrder ?? 0).compareTo(b.displayOrder ?? 0)); + _lessons = await _apiService.getLearnLessons(id); + _lessons.sort((a, b) => (a.sortOrder ?? 0).compareTo(b.sortOrder ?? 0)); } } } diff --git a/lib/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart b/lib/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart index d6e8bcc..eee89dc 100644 --- a/lib/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart +++ b/lib/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart @@ -1,30 +1,27 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; import 'package:vimeo_video_player/vimeo_video_player.dart'; -import 'package:yimaru_app/ui/widgets/empty_video_player.dart'; +import 'package:yimaru_app/models/learn_lesson.dart'; -import '../../../models/lesson.dart'; import '../../common/app_colors.dart'; -import '../../common/enmus.dart'; import '../../common/ui_helpers.dart'; import '../../widgets/custom_elevated_button.dart'; import '../../widgets/small_app_bar.dart'; import 'learn_lesson_detail_viewmodel.dart'; class LearnLessonDetailView extends StackedView { - final Lesson lesson; + final LearnLesson lesson; const LearnLessonDetailView({Key? key, required this.lesson}) : super(key: key); Future _navigate(LearnLessonDetailViewModel viewModel) async { await viewModel.pause(); - // await viewModel.navigateToLearnPractice(practices); + await viewModel.navigateToLearnPractice(); } @override void onDispose(LearnLessonDetailViewModel viewModel) { - print('DISPOSED'); viewModel.close(); super.onDispose(viewModel); } @@ -126,8 +123,6 @@ class LearnLessonDetailView extends StackedView { child: _buildVideoPlayer(viewModel), ); - - Widget _buildVideoPlayer(LearnLessonDetailViewModel viewModel) => _buildVimeoPlayer(viewModel); @@ -136,11 +131,9 @@ class LearnLessonDetailView extends StackedView { isAutoPlay: true, onInAppWebViewCreated: (controller) => viewModel.initializePlayer(controller), - videoId: lesson.teachingVideoUrl?.split('/').last ?? '', + videoId: lesson.videoUrl?.split('/').last ?? '', ); - Widget _buildEmptyVideoPlayer() => const EmptyVideoPlayer(); - Widget _buildDescriptionWrapper() => Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: _buildDescription(), @@ -148,7 +141,7 @@ class LearnLessonDetailView extends StackedView { Widget _buildDescription() => Text( lesson.description ?? '', - style: style14DG600, + style: style14DG400, ); Widget _buildContinueButtonWrapper(LearnLessonDetailViewModel viewModel) => @@ -164,8 +157,8 @@ class LearnLessonDetailView extends StackedView { Widget _buildContinueButton(LearnLessonDetailViewModel viewModel) => CustomElevatedButton( height: 55, - text: 'Lessons', borderRadius: 12, + text: 'Practices', foregroundColor: kcWhite, backgroundColor: kcPrimaryColor, onTap: () async => await _navigate(viewModel), diff --git a/lib/ui/views/learn_lesson_detail/learn_lesson_detail_viewmodel.dart b/lib/ui/views/learn_lesson_detail/learn_lesson_detail_viewmodel.dart index 1a54d3c..bb7e5e2 100644 --- a/lib/ui/views/learn_lesson_detail/learn_lesson_detail_viewmodel.dart +++ b/lib/ui/views/learn_lesson_detail/learn_lesson_detail_viewmodel.dart @@ -1,8 +1,6 @@ -import 'package:chewie/chewie.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; -import 'package:video_player/video_player.dart'; import 'package:yimaru_app/app/app.router.dart'; import 'package:yimaru_app/ui/common/enmus.dart'; @@ -10,34 +8,26 @@ import '../../../app/app.locator.dart'; import '../../../services/status_checker_service.dart'; class LearnLessonDetailViewModel extends BaseViewModel { + // Dependency injection final _statusChecker = locator(); final _navigationService = locator(); // Video player config - ChewieController? _chewieController; - - ChewieController? get chewieController => _chewieController; - InAppWebViewController? _webViewController; InAppWebViewController? get webViewController => _webViewController; - VideoPlayerController? _videoPlayerController; - - VideoPlayerController? get videoPlayerController => _videoPlayerController; - // Video player void close() { - _videoPlayerController?.dispose(); - _chewieController?.dispose(); + webViewController?.dispose(); } Future pause() async { - await _chewieController?.pause(); + await webViewController?.pause(); } - void initializePlayer(InAppWebViewController controller){ + void initializePlayer(InAppWebViewController controller) { _webViewController = controller; rebuildUi(); } @@ -52,17 +42,9 @@ class LearnLessonDetailViewModel extends BaseViewModel { rebuildUi(); } - // Navigation void pop() => _navigationService.back(); - Future navigateToLearnPractice( - List> practices) async => - await _navigationService.navigateToLearnPracticeView( - practices: practices, - buttonLabel: 'Start Practice', - title: 'Let \'s practice what you just learnt!', - subtitle: - 'I’ll ask you a few questions, and you can respond naturally.', - ); + Future navigateToLearnPractice() async {} + // await _navigationService.navigateToLearnPracticeView(); } diff --git a/lib/ui/views/learn_level/learn_level_view.dart b/lib/ui/views/learn_level/learn_level_view.dart deleted file mode 100644 index 81076c6..0000000 --- a/lib/ui/views/learn_level/learn_level_view.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/ui/widgets/learn_level_tile.dart'; -import 'package:yimaru_app/ui/widgets/small_app_bar.dart'; - -import '../../../models/level.dart'; -import '../../common/app_colors.dart'; -import '../../common/enmus.dart'; -import '../../common/ui_helpers.dart'; -import '../../widgets/custom_circular_progress_indicator.dart'; -import 'learn_level_viewmodel.dart'; - -class LearnLevelView extends StackedView { - final int id; - const LearnLevelView({Key? key, required this.id}) : super(key: key); - - @override - void onViewModelReady(LearnLevelViewModel viewModel) async { - await viewModel.getLevels(id); - super.onViewModelReady(viewModel); - } - - @override - LearnLevelViewModel viewModelBuilder(BuildContext context) => - LearnLevelViewModel(); - - @override - Widget builder( - BuildContext context, - LearnLevelViewModel viewModel, - Widget? child, - ) => - _buildScaffoldWrapper(viewModel); - - Widget _buildScaffoldWrapper(LearnLevelViewModel viewModel) => Scaffold( - backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), - ); - - Widget _buildScaffold(LearnLevelViewModel viewModel) => - SafeArea(child: _buildBody(viewModel)); - - Widget _buildBody(LearnLevelViewModel viewModel) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), - ); - - Widget _buildColumn(LearnLevelViewModel viewModel) => Column( - children: [ - verticalSpaceMedium, - _buildAppBar(viewModel), - verticalSpaceMedium, - _buildLevelsColumnWrapper(viewModel) - ], - ); - - Widget _buildAppBar(LearnLevelViewModel viewModel) => SmallAppBar( - title: 'Levels', - onTap: viewModel.pop, - showBackButton: true, - ); - - Widget _buildLevelsColumnWrapper(LearnLevelViewModel viewModel) => - Expanded(child: _buildLevelsColumnScrollView(viewModel)); - - Widget _buildLevelsColumnScrollView(LearnLevelViewModel viewModel) => - SingleChildScrollView( - child: _buildListViewBuilder(viewModel), - ); - - Widget _buildListViewBuilder(LearnLevelViewModel viewModel) => - viewModel.busy(StateObjects.learnLevels) - ? _buildProgressIndicator() - : _buildListView(viewModel); - - Widget _buildProgressIndicator() => const Center( - child: CustomCircularProgressIndicator(color: kcPrimaryColor), - ); - - Widget _buildListView(LearnLevelViewModel viewModel) => ListView.separated( - shrinkWrap: true, - itemCount: viewModel.levels.length, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _buildTile( - level: viewModel.levels[index], - onTap: () async => - await viewModel.navigateToModule(viewModel.levels[index]), - ), - separatorBuilder: (context, index) => verticalSpaceSmall, - ); - - Widget _buildTile({ - required Level level, - required GestureTapCallback onTap, - }) => - LearnLevelTile( - onTap: onTap, - level: level, - ); -} diff --git a/lib/ui/views/learn_level/learn_level_viewmodel.dart b/lib/ui/views/learn_level/learn_level_viewmodel.dart deleted file mode 100644 index cbda49d..0000000 --- a/lib/ui/views/learn_level/learn_level_viewmodel.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:stacked/stacked.dart'; -import 'package:stacked_services/stacked_services.dart'; -import 'package:yimaru_app/app/app.router.dart'; - -import '../../../app/app.locator.dart'; -import '../../../models/level.dart'; -import '../../../services/api_service.dart'; -import '../../../services/status_checker_service.dart'; -import '../../common/enmus.dart'; - -class LearnLevelViewModel extends BaseViewModel { - // Dependency injection - final _apiService = locator(); - - final _statusChecker = locator(); - - final _navigationService = locator(); - - // Learn levels - List _levels = []; - - List get levels => _levels; - - // Navigation - void pop() => _navigationService.back(); - - Future navigateToModule(Level level) async => - _navigationService.navigateToLearnModuleView(level: level); - - // Remote api call - - // Learn levels - Future getLevels(int id) async => - await runBusyFuture(_getLevels(id), busyObject: StateObjects.learnLevels); - - Future _getLevels(int id) async { - if (_levels.isEmpty) { - if (await _statusChecker.checkConnection()) { - _levels = await _apiService.getLevels(id); - _levels.sort( - (a, b) => (a.displayOrder ?? 0).compareTo(b.displayOrder ?? 0)); - } - } - } -} diff --git a/lib/ui/views/learn_module/learn_module_view.dart b/lib/ui/views/learn_module/learn_module_view.dart index 4713fec..d1e33d9 100644 --- a/lib/ui/views/learn_module/learn_module_view.dart +++ b/lib/ui/views/learn_module/learn_module_view.dart @@ -1,10 +1,10 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/models/level.dart'; +import 'package:yimaru_app/models/learn_module.dart'; import 'package:yimaru_app/ui/widgets/learn_module_tile.dart'; import 'package:yimaru_app/ui/widgets/overall_learn_progress.dart'; -import '../../../models/module.dart'; +import '../../../models/learn_course.dart'; import '../../common/app_colors.dart'; import '../../common/enmus.dart'; import '../../common/ui_helpers.dart'; @@ -13,13 +13,13 @@ import '../../widgets/small_app_bar.dart'; import 'learn_module_viewmodel.dart'; class LearnModuleView extends StackedView { - final Level level; + final LearnCourse course; - const LearnModuleView({Key? key, required this.level}) : super(key: key); + const LearnModuleView({Key? key, required this.course}) : super(key: key); @override void onViewModelReady(LearnModuleViewModel viewModel) async { - await viewModel.getModules(level.id ?? 0); + await viewModel.getLearnModules(1); super.onViewModelReady(viewModel); } @@ -58,7 +58,6 @@ class LearnModuleView extends StackedView { ); Widget _buildAppBar(LearnModuleViewModel viewModel) => SmallAppBar( - title: 'Modules', onTap: viewModel.pop, showBackButton: true, ); @@ -78,27 +77,28 @@ class LearnModuleView extends StackedView { ); List _buildLevelsColumnChildren(LearnModuleViewModel viewModel) => [ - verticalSpaceMedium, + verticalSpaceSmall, _buildTitle(), _buildSubtitle(), - verticalSpaceLarge, + verticalSpaceMedium, _buildOverallProgress(), verticalSpaceMedium, _buildListViewBuilder(viewModel) ]; Widget _buildTitle() => Text( - level.title ?? '', + course.name ?? '', style: style18P600, ); Widget _buildSubtitle() => Text( 'Your Current Level', - style: style14DG400, + style: style14P400, ); Widget _buildOverallProgress() => OverallLearnProgress( - color: kcPrimaryColor.withOpacity(0.1), + indicatorBackgroundColor: kcWhite, + backgroundColor: kcPrimaryColor.withOpacity(0.1), ); Widget _buildListViewBuilder(LearnModuleViewModel viewModel) => @@ -116,17 +116,20 @@ class LearnModuleView extends StackedView { physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _buildTile( module: viewModel.modules[index], - onModuleTap: () async => await viewModel - .navigateToLearnSubmodule(viewModel.modules[index]), + onModuleTap: () async => + await viewModel.navigateToLearnLesson(viewModel.modules[index]), + onPracticeTap: () async => await viewModel + .navigateToLearnPractice(viewModel.modules[index].id ?? 0), ), ); Widget _buildTile({ - required Module module, + required LearnModule module, required GestureTapCallback onModuleTap, + required GestureTapCallback onPracticeTap, }) => LearnModuleTile( - module: module, - onModuleTap: onModuleTap, - ); + module: module, + onModuleTap: onModuleTap, + onPracticeTap: onPracticeTap); } diff --git a/lib/ui/views/learn_module/learn_module_viewmodel.dart b/lib/ui/views/learn_module/learn_module_viewmodel.dart index 348830a..f350174 100644 --- a/lib/ui/views/learn_module/learn_module_viewmodel.dart +++ b/lib/ui/views/learn_module/learn_module_viewmodel.dart @@ -1,7 +1,7 @@ import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; import 'package:yimaru_app/app/app.router.dart'; -import 'package:yimaru_app/models/module.dart'; +import 'package:yimaru_app/models/learn_module.dart'; import '../../../app/app.locator.dart'; import '../../../services/api_service.dart'; @@ -17,28 +17,31 @@ class LearnModuleViewModel extends BaseViewModel { final _navigationService = locator(); // Learn module - List _modules = []; + List _modules = []; - List get modules => _modules; + List get modules => _modules; // Navigation void pop() => _navigationService.back(); - Future navigateToLearnSubmodule(Module module) async => - await _navigationService.navigateToLearnSubmoduleView(module: module); + Future navigateToLearnLesson(LearnModule module) async => + await _navigationService.navigateToLearnLessonView(module: module); + + Future navigateToLearnPractice(int id) async => await _navigationService + .navigateToLearnPracticeView(id: id, practice: LearnPractices.module); // Remote api call // Learn modules - Future getModules(int id) async => await runBusyFuture(_getModules(id), - busyObject: StateObjects.learnModules); + Future getLearnModules(int id) async => + await runBusyFuture(_getLearnModules(id), + busyObject: StateObjects.learnModules); - Future _getModules(int id) async { + Future _getLearnModules(int id) async { if (_modules.isEmpty) { if (await _statusChecker.checkConnection()) { - _modules = await _apiService.getModules(id); - _modules.sort( - (a, b) => (a.displayOrder ?? 0).compareTo(b.displayOrder ?? 0)); + _modules = await _apiService.getLearnModules(id); + _modules.sort((a, b) => (a.sortOrder ?? 0).compareTo(b.sortOrder ?? 0)); } } } diff --git a/lib/ui/views/learn_practice/learn_practice_view.dart b/lib/ui/views/learn_practice/learn_practice_view.dart index 80393fc..040b35a 100644 --- a/lib/ui/views/learn_practice/learn_practice_view.dart +++ b/lib/ui/views/learn_practice/learn_practice_view.dart @@ -1,47 +1,30 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/ui/common/enmus.dart'; import 'package:yimaru_app/ui/views/learn_practice/screens/finish_learn_practice_screen.dart'; import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practice_completion_screen.dart'; import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practice_result_screen.dart'; -import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practices_screen.dart'; +import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practice_questions_screen.dart'; import 'package:yimaru_app/ui/views/learn_practice/screens/interact_learn_practice_screen.dart'; import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practice_intro_screen.dart'; import 'package:yimaru_app/ui/views/learn_practice/screens/start_learn_practice_screen.dart'; +import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart'; import '../../common/app_colors.dart'; import '../../widgets/cancel_learn_practice_sheet.dart'; import 'learn_practice_viewmodel.dart'; class LearnPracticeView extends StackedView { - final String title; - final String subtitle; - final String buttonLabel; - final List> practices; + final int id; + final LearnPractices practice; - const LearnPracticeView( - {Key? key, - required this.title, - required this.subtitle, - required this.practices, - required this.buttonLabel}) + const LearnPracticeView({Key? key, required this.id, required this.practice}) : super(key: key); Future _cancel(LearnPracticeViewModel viewModel) async { viewModel.pop(); - viewModel.goTo(0); viewModel.stopRecording(); - } - - Future _pop( - {required BuildContext context, - required LearnPracticeViewModel viewModel}) async { - { - if (viewModel.currentPage == 3) { - await _showSheet(context: context, viewModel: viewModel); - } else { - viewModel.goBack(); - } - } + viewModel.pop(); } Future _showSheet( @@ -54,6 +37,12 @@ class LearnPracticeView extends StackedView { builder: (_) => _buildSheet(viewModel), ); + @override + void onViewModelReady(LearnPracticeViewModel viewModel) async { + await viewModel.getLearnPractices(id: id, practice: practice); + super.onViewModelReady(viewModel); + } + @override LearnPracticeViewModel viewModelBuilder(BuildContext context) => LearnPracticeViewModel(); @@ -70,50 +59,45 @@ class LearnPracticeView extends StackedView { {required BuildContext context, required LearnPracticeViewModel viewModel}) => PopScope( - canPop: viewModel.currentPage == 0 ? true : false, - onPopInvokedWithResult: (value, data) async => - await _pop(context: context, viewModel: viewModel), + canPop: false, + onPopInvokedWithResult: (value, data) + async=>await _showSheet(context: context, viewModel: viewModel), child: _buildScaffoldWrapper(viewModel)); Widget _buildSheet(LearnPracticeViewModel viewModel) => CancelLearnPracticeSheet( onClose: viewModel.pop, onContinue: viewModel.pop, + user: viewModel.user?.firstName ?? '', onCancel: () async => await _cancel(viewModel), ); Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold( backgroundColor: kcBackgroundColor, - body: _buildBody(viewModel), + body: _buildBodyState(viewModel), ); - Widget _buildBody(LearnPracticeViewModel viewModel) => - IndexedStack(index: viewModel.currentPage, children: _buildScreens()); + Widget _buildBodyState(LearnPracticeViewModel viewModel) => + viewModel.busy(StateObjects.learnPractices) + ? const PageLoadingIndicator() + : _buildBody(viewModel); - List _buildScreens() => [ - _buildLearnPracticesScreen(), - _buildLearnPracticeIntroScreen(), - _buildStartLearnPracticeScreen(), - _buildInteractLearnPracticeScreen(), + Widget _buildBody(LearnPracticeViewModel viewModel) => IndexedStack( + index: viewModel.currentPage, children: _buildScreens(viewModel)); + + List _buildScreens(LearnPracticeViewModel viewModel) => [ + _buildLearnPracticeIntroScreen(viewModel), + _buildLearnPracticeQuestionsScreen(viewModel), _buildFinishLearnPracticeScreen(), _buildLearnPracticeResultScreen(), _buildLearnPracticeCompletionScreen() ]; - Widget _buildLearnPracticesScreen() => LearnPracticesScreen( - practices: practices, - ); + Widget _buildLearnPracticeIntroScreen(LearnPracticeViewModel viewModel) => + const LearnPracticeIntroScreen(); - Widget _buildLearnPracticeIntroScreen() => LearnPracticeIntroScreen( - title: title, - subtitle: subtitle, - buttonLabel: buttonLabel, - ); - - Widget _buildStartLearnPracticeScreen() => const StartLearnPracticeScreen(); - - Widget _buildInteractLearnPracticeScreen() => - const InteractLearnPracticeScreen(); + Widget _buildLearnPracticeQuestionsScreen(LearnPracticeViewModel viewModel) => + const LearnPracticeQuestionsScreen(); Widget _buildFinishLearnPracticeScreen() => const FinishLearnPracticeScreen(); diff --git a/lib/ui/views/learn_practice/learn_practice_viewmodel.dart b/lib/ui/views/learn_practice/learn_practice_viewmodel.dart index fe79e90..eb4934c 100644 --- a/lib/ui/views/learn_practice/learn_practice_viewmodel.dart +++ b/lib/ui/views/learn_practice/learn_practice_viewmodel.dart @@ -1,20 +1,30 @@ import 'package:audioplayers/audioplayers.dart'; +import 'package:flutter/cupertino.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; import 'package:waveform_recorder/waveform_recorder.dart'; +import 'package:yimaru_app/models/learn_practice.dart'; import 'package:yimaru_app/models/user.dart'; import 'package:yimaru_app/services/authentication_service.dart'; import 'package:yimaru_app/services/voice_recorder_service.dart'; import 'package:yimaru_app/ui/common/enmus.dart'; import '../../../app/app.locator.dart'; +import '../../../models/learn_question.dart'; +import '../../../models/question.dart'; +import '../../../services/api_service.dart'; import '../../../services/audio_player_service.dart'; +import '../../../services/status_checker_service.dart'; import '../../common/app_colors.dart'; class LearnPracticeViewModel extends ReactiveViewModel { // Dependency injection + final _apiService = locator(); + final _dialogService = locator(); + final _statusChecker = locator(); + final _navigationService = locator(); final _audioPlayerService = locator(); @@ -67,23 +77,48 @@ class LearnPracticeViewModel extends ReactiveViewModel { VoiceRecordingState get recordingState => _recordingState; // Busy object - StateObjects _busyObject = StateObjects.none; + String? _busyObject; - StateObjects get busyObject => _busyObject; + String? get busyObject => _busyObject; + + Voice? _playing; + + Voice? get playing =>_playing; + + // Learn practices + List _practices = []; + + List get practices => _practices; + + // Practice questions + List _questions = []; + + List get questions => _questions; + + // Practice answers + List> _answers = []; + + List> get answers => _answers; // In-app navigation int _currentPage = 0; int get currentPage => _currentPage; - // Practice - Map _selectedPractice = {}; + final PageController _questionSetController = PageController(); - Map get selectedPractice => _selectedPractice; + PageController get questionSetController => _questionSetController; + + final PageController _questionController = PageController(); + + PageController get questionController => _questionController; // Voice recorder - Future stopRecording() async => + Future stopRecording() async { + if (_voiceRecorderService.waveController.isRecording) { await _voiceRecorderService.stopRecording(); + } + } Future startRecording() async => await runBusyFuture(_startRecording(), busyObject: StateObjects.recordLearnPracticeAnswer); @@ -91,24 +126,6 @@ class LearnPracticeViewModel extends ReactiveViewModel { Future _startRecording() async => await _voiceRecorderService.startRecording(); - // Sample audio - Future playSampleAudio() async => - await runBusyFuture(_playSampleAudio(), - busyObject: StateObjects.learnPracticeSample); - - Future _playSampleAudio() async { - setBusyObject(StateObjects.learnPracticeSample); - await _audioPlayerService.playUrl(_selectedPractice['sample_answer']); - } - - Future pauseSampleAudio() async => - await runBusyFuture(_pauseSampleAudio(), - busyObject: StateObjects.learnPracticeSample); - - Future _pauseSampleAudio() async { - setBusyObject(StateObjects.learnPracticeSample); - await _audioPlayerService.pause(); - } // Play practice audio void _listenToAudio() { @@ -125,46 +142,53 @@ class LearnPracticeViewModel extends ReactiveViewModel { }); } - Future playQuestionAudio() async => - await runBusyFuture(_playQuestionAudio(), + Future playVoicePrompt(LearnQuestion question) async => + await runBusyFuture(_playVoicePrompt(question), busyObject: StateObjects.learnPracticeQuestion); - Future _playQuestionAudio() async { - goTo(3); - await _audioPlayerService.playUrl(_selectedPractice['question_audio_url']); + Future _playVoicePrompt(LearnQuestion question) async { + _questionController.jumpToPage(1); + await _audioPlayerService.playUrl(question.voicePrompt ?? ''); } - // Recorded audio - Future playRecordedAudio() async => - await runBusyFuture(_playRecordedAudio(), - busyObject: StateObjects.learnPracticeAnswer); - - Future _playRecordedAudio() async { - setBusyObject(StateObjects.learnPracticeAnswer); - await _audioPlayerService - .playLocal(await _voiceRecorderService.getRecordedAudio() ?? ''); + Future playResult({required Map answer,required Voice voice})async{ + setBusyObject( + playing: voice, + object: answer['busy_object']); + await playAudio(voice: voice,answer: answer); } - Future pauseRecordedAudio() async => - await runBusyFuture(_pauseRecordedAudio(), - busyObject: StateObjects.learnPracticeAnswer); + Future playAudio({required Map answer,required Voice voice}) async => + await runBusyFuture(_playAudio(voice:voice,answer:answer), + busyObject: answer['busy_object']); - Future _pauseRecordedAudio() async { - setBusyObject(StateObjects.learnPracticeAnswer); + Future _playAudio({required Map answer,required Voice voice}) async { + + + if(voice == Voice.recorded){ + await _audioPlayerService + .playLocal(answer['recorded_voice_answer']); + }else{ + await _audioPlayerService.playUrl(answer['sample_voice_answer']); + + } + + + } + + + Future pauseAudio() async { await _audioPlayerService.pause(); } // Set busy object - void setBusyObject(StateObjects object) { + void setBusyObject({required String object,required Voice playing}) { + _playing = playing; _busyObject = object; - notifyListeners(); + rebuildUi(); } - // Practice - void setPractice(Map practice) { - _selectedPractice = practice; - goTo(1); - } + // Dialogue Future showAbortDialog() async { @@ -195,6 +219,53 @@ class LearnPracticeViewModel extends ReactiveViewModel { } } + Future nextQuestion({required int index,required LearnQuestion question}) async { + await stopRecording(); + _answers.add({ + 'busy_object': question.id.toString(), + 'sample_text_answer': question.audioCorrectAnswerText, + 'sample_voice_answer': question.sampleAnswerVoicePrompt, + 'recorded_voice_answer' : _voiceRecorderService.getRecordedAudio() , + }); + if (index != _questions.length) { + _questionSetController.nextPage( + duration: const Duration(milliseconds: 350), + curve: Curves.easeInOutCubic); + } else { + goTo(3); + } + } + // Navigation void pop() => _navigationService.back(); + + // Remote api call + + // Learn practice + Future getLearnPractices( + {required int id, required LearnPractices practice}) async => + await runBusyFuture(_getLearnPractices(id: id, practice: practice), + busyObject: StateObjects.learnPractices); + + Future _getLearnPractices( + {required int id, required LearnPractices practice}) async { + if (await _statusChecker.checkConnection()) { + if (practice == LearnPractices.course) { + _practices = await _apiService.getLearnCoursePractices(id); + await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); + } else if (practice == LearnPractices.module) { + _practices = await _apiService.getLearnModulePractices(id); + await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); + } else { + _practices = await _apiService.getLearnLessonPractices(id); + print('PRACTICE LENGTH: ${_practices.length}'); + await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); + } + } + } + + Future _getLearnPracticeQuestions(int id) async { + _questions = await _apiService.getLearnQuestions(id); + + } } diff --git a/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart b/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart index f4d3acc..1d11264 100644 --- a/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart +++ b/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart @@ -9,6 +9,7 @@ import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart'; import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart'; import 'package:yimaru_app/ui/widgets/wave_wrapper.dart'; +import '../../../../models/learn_question.dart'; import '../../../common/app_colors.dart'; import '../../../common/enmus.dart'; import '../../../common/ui_helpers.dart'; @@ -17,22 +18,24 @@ import '../../../widgets/small_app_bar.dart'; class InteractLearnPracticeScreen extends ViewModelWidget { - const InteractLearnPracticeScreen({super.key}); + final int index; + final LearnQuestion question; + + const InteractLearnPracticeScreen( + {super.key, required this.index, required this.question}); Future _cancel(LearnPracticeViewModel viewModel) async { viewModel.pop(); - viewModel.goTo(0); + viewModel.pop(); viewModel.stopRecording(); } - void _start(LearnPracticeViewModel viewModel) { - viewModel.playQuestionAudio(); - } + void _start(LearnPracticeViewModel viewModel) => + viewModel.playVoicePrompt(question); - Future _stop(LearnPracticeViewModel viewModel) async { - await viewModel.stopRecording(); - viewModel.goTo(4); - } + + Future _stop(LearnPracticeViewModel viewModel) async => + await viewModel.nextQuestion(index: index,question: question); Future _showSheet( {required BuildContext context, @@ -41,7 +44,7 @@ class InteractLearnPracticeScreen context: context, isScrollControlled: true, backgroundColor: kcTransparent, - builder: (_) => _buildSheet(viewModel), + builder: (cxt) => _buildSheet(viewModel), ); @override @@ -68,17 +71,10 @@ class InteractLearnPracticeScreen children: [ _buildBodyColumnWrapper(context: context, viewModel: viewModel), _buildProgressIndicatorState(viewModel), - _buildSpeakerState(context: context, viewModel: viewModel) + _buildPageLoadingIndicatorState(viewModel) ], ); - Widget _buildSpeakerState( - {required BuildContext context, - required LearnPracticeViewModel viewModel}) => - viewModel.busy(StateObjects.learnPracticeQuestion) - ? const PageLoadingIndicator() - : Container(); - Widget _buildBodyColumnWrapper( {required BuildContext context, required LearnPracticeViewModel viewModel}) => @@ -100,24 +96,25 @@ class InteractLearnPracticeScreen {required BuildContext context, required LearnPracticeViewModel viewModel}) => [ - _buildAppBarWrapper(viewModel), + _buildAppBarWrapper(context: context,viewModel: viewModel), _buildSpeakingIndicatorWrapper(viewModel), _buildLowerButtonsSectionWrapper(context: context, viewModel: viewModel) ]; - Widget _buildAppBarWrapper(LearnPracticeViewModel viewModel) => Column( + Widget _buildAppBarWrapper( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Column( children: [ verticalSpaceMedium, - _buildAppBar(viewModel), + _buildAppBar(context: context,viewModel: viewModel), verticalSpaceMedium, ], ); - Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar( + Widget _buildAppBar( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => SmallAppBar( showBackButton: true, - title: 'Practice Speaking', - onTap: () async => await _cancel(viewModel), - ); + onTap: () async => await _showSheet(context: context,viewModel: viewModel), + title: 'Practice Speaking ($index/${viewModel.questions.length})'); Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) => Column( @@ -328,6 +325,7 @@ class InteractLearnPracticeScreen CancelLearnPracticeSheet( onClose: viewModel.pop, onContinue: viewModel.pop, + user: viewModel.user?.firstName ?? '', onCancel: () async => await _cancel(viewModel), ); @@ -355,4 +353,9 @@ class InteractLearnPracticeScreen activeColor: kcPrimaryColor, progress: viewModel.progress, backgroundColor: kcVeryLightGrey); + + Widget _buildPageLoadingIndicatorState(LearnPracticeViewModel viewModel) => + viewModel.busy(StateObjects.learnPracticeQuestion) + ? const PageLoadingIndicator() + : Container(); } diff --git a/lib/ui/views/learn_practice/screens/learn_practice_completion_screen.dart b/lib/ui/views/learn_practice/screens/learn_practice_completion_screen.dart index b8495e8..0e29b1f 100644 --- a/lib/ui/views/learn_practice/screens/learn_practice_completion_screen.dart +++ b/lib/ui/views/learn_practice/screens/learn_practice_completion_screen.dart @@ -76,8 +76,8 @@ class LearnPracticeCompletionScreen height: 55, borderRadius: 12, text: 'Continue', + onTap: viewModel.pop, foregroundColor: kcWhite, - onTap: () => viewModel.goTo(0), backgroundColor: kcPrimaryColor, ); } diff --git a/lib/ui/views/learn_practice/screens/learn_practice_intro_screen.dart b/lib/ui/views/learn_practice/screens/learn_practice_intro_screen.dart index dc09648..4a82299 100644 --- a/lib/ui/views/learn_practice/screens/learn_practice_intro_screen.dart +++ b/lib/ui/views/learn_practice/screens/learn_practice_intro_screen.dart @@ -1,54 +1,79 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/learn_practice.dart'; import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart'; import '../../../common/app_colors.dart'; import '../../../common/ui_helpers.dart'; +import '../../../widgets/cancel_learn_practice_sheet.dart'; import '../../../widgets/custom_elevated_button.dart'; import '../../../widgets/small_app_bar.dart'; import '../../../widgets/speaking_partner_image.dart'; class LearnPracticeIntroScreen extends ViewModelWidget { - final String title; - final String subtitle; - final String buttonLabel; + const LearnPracticeIntroScreen({super.key}); - const LearnPracticeIntroScreen( - {super.key, - required this.title, - required this.subtitle, - required this.buttonLabel}); + Future _cancel(LearnPracticeViewModel viewModel) async { + viewModel.pop(); + viewModel.pop(); + viewModel.stopRecording(); + + } + + Future _showSheet( + {required BuildContext context, + required LearnPracticeViewModel viewModel}) async => + await showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: kcTransparent, + builder: (cxt) => _buildSheet(viewModel), + ); @override Widget build(BuildContext context, LearnPracticeViewModel viewModel) => - _buildScaffoldWrapper(viewModel); + _buildScaffoldWrapper(context: context,viewModel: viewModel); - Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold( + Widget _buildScaffoldWrapper( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Scaffold( backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), + body: _buildScaffold(context: context,viewModel: viewModel), ); - Widget _buildScaffold(LearnPracticeViewModel viewModel) => - SafeArea(child: _buildColumnWrapper(viewModel)); + Widget _buildScaffold( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => + SafeArea(child: _buildColumnWrapper(context: context,viewModel: viewModel)); - Widget _buildColumnWrapper(LearnPracticeViewModel viewModel) => Padding( + Widget _buildColumnWrapper( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), + child: _buildColumn(context: context,viewModel: viewModel), ); - Widget _buildColumn(LearnPracticeViewModel viewModel) => Column( + Widget _buildColumn( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Column( children: [ verticalSpaceMedium, - _buildAppBar(viewModel), + _buildAppBar(context: context,viewModel: viewModel), verticalSpaceMedium, _buildBodyColumnWrapper(viewModel), ], ); - Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar( + Widget _buildAppBar( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => SmallAppBar( showBackButton: true, - onTap: viewModel.goBack, title: 'Practice Speaking', + onTap: () async => await _showSheet(context: context,viewModel: viewModel), + + ); + + Widget _buildSheet(LearnPracticeViewModel viewModel) => + CancelLearnPracticeSheet( + onClose: viewModel.pop, + onContinue: viewModel.pop, + user: viewModel.user?.firstName ?? '', + onCancel: () async => await _cancel(viewModel), ); Widget _buildBodyColumnWrapper(LearnPracticeViewModel viewModel) => Expanded( @@ -96,7 +121,7 @@ class LearnPracticeIntroScreen extends ViewModelWidget { ); Widget _buildPartnerName() => Text.rich( - TextSpan(text: 'Daniel', style: style14DG600, children: [ + TextSpan(text: 'Dawit', style: style14DG600, children: [ TextSpan( text: ' - Your Speaking Partner', style: style14MG400, @@ -105,13 +130,14 @@ class LearnPracticeIntroScreen extends ViewModelWidget { ); Widget _buildTitle() => Text( - title, + 'Let\'s practice what you just learnt!', style: style25DG600, textAlign: TextAlign.center, ); Widget _buildSubtitle() => Text( - subtitle, + 'I’ll ask you a few questions, and you can respond naturally.', + maxLines: 1, style: style14DG400, textAlign: TextAlign.center, ); @@ -126,9 +152,9 @@ class LearnPracticeIntroScreen extends ViewModelWidget { CustomElevatedButton( height: 55, borderRadius: 12, - text: buttonLabel, + text: 'Practice', foregroundColor: kcWhite, - onTap: () => viewModel.goTo(2), + onTap: () => viewModel.goTo(1), backgroundColor: kcPrimaryColor, ); } diff --git a/lib/ui/views/learn_practice/screens/learn_practice_questions_screen.dart b/lib/ui/views/learn_practice/screens/learn_practice_questions_screen.dart new file mode 100644 index 0000000..425f71a --- /dev/null +++ b/lib/ui/views/learn_practice/screens/learn_practice_questions_screen.dart @@ -0,0 +1,65 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_carousel_widget/flutter_carousel_widget.dart'; +import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/learn_question.dart'; +import 'package:yimaru_app/models/practice.dart'; +import 'package:yimaru_app/ui/views/learn_practice/screens/start_learn_practice_screen.dart'; +import 'package:yimaru_app/ui/widgets/learn_practice_card.dart'; + +import '../../../common/app_colors.dart'; +import '../../../common/ui_helpers.dart'; +import '../../../widgets/small_app_bar.dart'; +import '../learn_practice_viewmodel.dart'; +import 'interact_learn_practice_screen.dart'; + +class LearnPracticeQuestionsScreen + extends ViewModelWidget { + const LearnPracticeQuestionsScreen({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, LearnPracticeViewModel viewModel) => + _buildQuestionSetView(viewModel); + + Widget _buildQuestionSetView(LearnPracticeViewModel viewModel) => + PageView.builder( + itemCount: viewModel.questions.length, + controller: viewModel.questionSetController, + physics: const NeverScrollableScrollPhysics(), + itemBuilder: (cotext, index) => _buildQuestionView( + index: index + 1, + viewModel: viewModel, + question: viewModel.questions[index]), + ); + + Widget _buildQuestionView( + {required int index, + required LearnQuestion question, + required LearnPracticeViewModel viewModel}) => + PageView( + controller: viewModel.questionController, + physics: const NeverScrollableScrollPhysics(), + children: _buildScreens(index:index,question: question), + ); + + List _buildScreens({ + required int index, + required LearnQuestion question, + }) => + [ + _buildStartLearnPracticeScreen(index:index,question: question), + _buildInteractLearnPracticeScreen(index:index,question: question) + ]; + + Widget _buildStartLearnPracticeScreen({ + required int index, + required LearnQuestion question,} + ) => StartLearnPracticeScreen( + index: index, + question: question, + ); + + Widget _buildInteractLearnPracticeScreen({ + required int index, + required LearnQuestion question,}) => + InteractLearnPracticeScreen(index: index,question: question,); +} diff --git a/lib/ui/views/learn_practice/screens/learn_practice_result_screen.dart b/lib/ui/views/learn_practice/screens/learn_practice_result_screen.dart index 5eaa76b..68c1c64 100644 --- a/lib/ui/views/learn_practice/screens/learn_practice_result_screen.dart +++ b/lib/ui/views/learn_practice/screens/learn_practice_result_screen.dart @@ -6,45 +6,84 @@ import 'package:yimaru_app/ui/widgets/learn_practice_results_wrapper.dart'; import '../../../common/app_colors.dart'; import '../../../common/ui_helpers.dart'; +import '../../../widgets/cancel_learn_practice_sheet.dart'; import '../../../widgets/custom_elevated_button.dart'; import '../../../widgets/small_app_bar.dart'; class LearnPracticeResultScreen extends ViewModelWidget { + const LearnPracticeResultScreen({super.key}); + + void _navigate(LearnPracticeViewModel viewModel){ + viewModel.questionSetController.jumpToPage(0); + viewModel.goTo(0); + } + + Future _cancel(LearnPracticeViewModel viewModel) async { + viewModel.pop(); + viewModel.pop(); + viewModel.stopRecording(); + + } + + Future _showSheet( + {required BuildContext context, + required LearnPracticeViewModel viewModel}) async => + await showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: kcTransparent, + builder: (cxt) => _buildSheet(viewModel), + ); + @override Widget build(BuildContext context, LearnPracticeViewModel viewModel) => - _buildScaffoldWrapper(viewModel); + _buildScaffoldWrapper(context: context,viewModel: viewModel); - Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold( + Widget _buildScaffoldWrapper({required BuildContext context, + required LearnPracticeViewModel viewModel}) => Scaffold( backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), + body: _buildScaffold(context: context,viewModel: viewModel), ); - Widget _buildScaffold(LearnPracticeViewModel viewModel) => - SafeArea(child: _buildBodyColumnWrapper(viewModel)); + Widget _buildScaffold({required BuildContext context, + required LearnPracticeViewModel viewModel}) => + SafeArea(child: _buildBodyColumnWrapper(context: context,viewModel: viewModel)); - Widget _buildBodyColumnWrapper(LearnPracticeViewModel viewModel) => Padding( + Widget _buildBodyColumnWrapper({required BuildContext context, + required LearnPracticeViewModel viewModel}) => Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildBodyColumn(viewModel), + child: _buildBodyColumn(context: context,viewModel: viewModel), ); - Widget _buildBodyColumn(viewModel) => Column( - children: _buildBodyColumnChildren(viewModel), + Widget _buildBodyColumn({required BuildContext context, + required LearnPracticeViewModel viewModel}) => Column( + children: _buildBodyColumnChildren(context: context,viewModel: viewModel), ); - List _buildBodyColumnChildren(LearnPracticeViewModel viewModel) => [ + List _buildBodyColumnChildren({required BuildContext context, + required LearnPracticeViewModel viewModel}) => [ verticalSpaceMedium, - _buildAppBar(viewModel), + _buildAppBar(context: context,viewModel: viewModel), verticalSpaceMedium, _buildBodyWrapper(viewModel) ]; - Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar( + Widget _buildAppBar({required BuildContext context, + required LearnPracticeViewModel viewModel}) => SmallAppBar( title: 'Result', showBackButton: true, - onTap: viewModel.goBack, + onTap: () async => await _showSheet(context: context,viewModel: viewModel), + ); + + Widget _buildSheet(LearnPracticeViewModel viewModel) => + CancelLearnPracticeSheet( + onClose: viewModel.pop, + onContinue: viewModel.pop, + user: viewModel.user?.firstName ?? '', + onCancel: () async => await _cancel(viewModel), ); Widget _buildBodyWrapper(LearnPracticeViewModel viewMode) => Expanded( @@ -71,9 +110,9 @@ class LearnPracticeResultScreen ]; Widget _buildResultsSection(LearnPracticeViewModel viewModel) => - LearnPracticeResultsWrapper(data: viewModel.selectedPractice); + const LearnPracticeResultsWrapper(); - Widget _buildLearnPracticeTipSection() => const LearnPracticeTipSection(); + Widget _buildLearnPracticeTipSection() => const LearnPracticeTipSection(); Widget _buildLowerButtonsSection(LearnPracticeViewModel viewModel) => Column( mainAxisSize: MainAxisSize.min, @@ -96,7 +135,7 @@ class LearnPracticeResultScreen text: 'Continue', borderRadius: 12, foregroundColor: kcWhite, - onTap: () => viewModel.goTo(6), + onTap: () => viewModel.goTo(4), backgroundColor: kcPrimaryColor, ); @@ -107,7 +146,8 @@ class LearnPracticeResultScreen borderRadius: 12, backgroundColor: kcWhite, borderColor: kcPrimaryColor, - onTap: () => viewModel.goTo(1), foregroundColor: kcPrimaryColor, + onTap: () => _navigate(viewModel), + ); } diff --git a/lib/ui/views/learn_practice/screens/learn_practices_screen.dart b/lib/ui/views/learn_practice/screens/learn_practices_screen.dart deleted file mode 100644 index 8ebd3cf..0000000 --- a/lib/ui/views/learn_practice/screens/learn_practices_screen.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/ui/widgets/learn_practice_card.dart'; - -import '../../../common/app_colors.dart'; -import '../../../common/ui_helpers.dart'; -import '../../../widgets/small_app_bar.dart'; -import '../learn_practice_viewmodel.dart'; - -class LearnPracticesScreen extends ViewModelWidget { - final List> practices; - - const LearnPracticesScreen({Key? key, required this.practices}) - : super(key: key); - - @override - Widget build(BuildContext context, LearnPracticeViewModel viewModel) => - _buildScaffoldWrapper(viewModel); - - Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold( - backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), - ); - - Widget _buildScaffold(LearnPracticeViewModel viewModel) => - SafeArea(child: _buildBody(viewModel)); - - Widget _buildBody(LearnPracticeViewModel viewModel) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), - ); - - Widget _buildColumn(LearnPracticeViewModel viewModel) => Column( - children: [ - verticalSpaceMedium, - _buildAppBar(viewModel), - verticalSpaceMedium, - _buildPracticeColumnWrapper(viewModel), - ], - ); - - Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar( - onTap: viewModel.pop, - showBackButton: true, - ); - - Widget _buildPracticeColumnWrapper(LearnPracticeViewModel viewModel) => - Expanded(child: _buildPracticeColumnScrollView(viewModel)); - - Widget _buildPracticeColumnScrollView(LearnPracticeViewModel viewModel) => - SingleChildScrollView( - child: _buildPracticeColumn(viewModel), - ); - - Widget _buildPracticeColumn(LearnPracticeViewModel viewModel) => Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: _buildPracticeColumnChildren(viewModel), - ); - - List _buildPracticeColumnChildren(LearnPracticeViewModel viewModel) => - [ - verticalSpaceMedium, - _buildTitle(), - _buildSubtitle(), - verticalSpaceMedium, - _buildListView(viewModel) - ]; - - Widget _buildTitle() => Text( - 'Learn Practices', - style: style18DG700, - ); - - Widget _buildSubtitle() => Text( - 'Select a practice test your progress', - style: style14DG400, - ); - - Widget _buildListView(LearnPracticeViewModel viewModel) => GridView.builder( - shrinkWrap: true, - itemCount: practices.length, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => - _buildCard(index: index, practice: practices[index]), - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - mainAxisSpacing: 15, - crossAxisSpacing: 15, - childAspectRatio: 1.45, - ), - ); - - Widget _buildCard( - {required int index, required Map practice}) => - LearnPracticeCard( - index: index + 1, - practice: practice, - ); -} diff --git a/lib/ui/views/learn_practice/screens/start_learn_practice_screen.dart b/lib/ui/views/learn_practice/screens/start_learn_practice_screen.dart index 4521b10..32e8963 100644 --- a/lib/ui/views/learn_practice/screens/start_learn_practice_screen.dart +++ b/lib/ui/views/learn_practice/screens/start_learn_practice_screen.dart @@ -3,57 +3,92 @@ import 'package:stacked/stacked.dart'; import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart'; import 'package:yimaru_app/ui/widgets/custom_column_button.dart'; +import '../../../../models/learn_question.dart'; import '../../../common/app_colors.dart'; import '../../../common/ui_helpers.dart'; +import '../../../widgets/cancel_learn_practice_sheet.dart'; import '../../../widgets/small_app_bar.dart'; class StartLearnPracticeScreen extends ViewModelWidget { - const StartLearnPracticeScreen({super.key}); + final int index; + final LearnQuestion question; + + const StartLearnPracticeScreen({super.key,required this.index,required this.question}); + + Future _cancel(LearnPracticeViewModel viewModel) async { + viewModel.pop(); + viewModel.pop(); + viewModel.stopRecording(); + } void _start(LearnPracticeViewModel viewModel) { - viewModel.playQuestionAudio(); + viewModel.playVoicePrompt(question); } + Future _showSheet( + {required BuildContext context, + required LearnPracticeViewModel viewModel}) async => + await showModalBottomSheet( + context: context, + isScrollControlled: true, + backgroundColor: kcTransparent, + builder: (cxt) => _buildSheet(viewModel), + ); + @override Widget build(BuildContext context, LearnPracticeViewModel viewModel) => - _buildScaffoldWrapper(viewModel); + _buildScaffoldWrapper(context: context,viewModel: viewModel); - Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold( + Widget _buildScaffoldWrapper( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Scaffold( backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), + body: _buildScaffold(context: context,viewModel: viewModel), ); - Widget _buildScaffold(LearnPracticeViewModel viewModel) => - SafeArea(child: _buildBodyColumnWrapper(viewModel)); + Widget _buildScaffold( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => + SafeArea(child: _buildBodyColumnWrapper(context: context,viewModel: viewModel)); - Widget _buildBodyColumnWrapper(LearnPracticeViewModel viewModel) => Padding( + Widget _buildBodyColumnWrapper( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildBodyColumn(viewModel), + child: _buildBodyColumn(context: context,viewModel: viewModel), ); - Widget _buildBodyColumn(LearnPracticeViewModel viewModel) => Column( + Widget _buildBodyColumn( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: _buildBodyColumnChildren(viewModel), + children: _buildBodyColumnChildren(context: context,viewModel: viewModel), ); - List _buildBodyColumnChildren(LearnPracticeViewModel viewModel) => [ - _buildAppBarWrapper(viewModel), + List _buildBodyColumnChildren( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => [ + _buildAppBarWrapper(context: context,viewModel: viewModel), _buildStartButtonWrapper(viewModel), _buildLowerButtonsSectionWrapper(viewModel) ]; - Widget _buildAppBarWrapper(LearnPracticeViewModel viewModel) => Column( + Widget _buildAppBarWrapper( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => Column( children: [ verticalSpaceMedium, - _buildAppBar(viewModel), + _buildAppBar(context: context,viewModel: viewModel), verticalSpaceMedium, ], ); - Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar( - showBackButton: true, - onTap: viewModel.goBack, - title: 'Practice Speaking', + Widget _buildAppBar( {required BuildContext context, + required LearnPracticeViewModel viewModel}) => SmallAppBar( + showBackButton: true, + onTap: () async => await _showSheet(context: context,viewModel: viewModel), + title: 'Practice Speaking ($index/${viewModel.questions.length})'); + + Widget _buildSheet(LearnPracticeViewModel viewModel) => + CancelLearnPracticeSheet( + onClose: viewModel.pop, + onContinue: viewModel.pop, + user: viewModel.user?.firstName ?? '', + onCancel: () async => await _cancel(viewModel), ); Widget _buildStartButtonWrapper(LearnPracticeViewModel viewModel) => Expanded( diff --git a/lib/ui/views/learn_program/learn_program_view.dart b/lib/ui/views/learn_program/learn_program_view.dart new file mode 100644 index 0000000..7a7e93d --- /dev/null +++ b/lib/ui/views/learn_program/learn_program_view.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/learn_program.dart'; + +import '../../common/app_colors.dart'; +import '../../common/enmus.dart'; +import '../../common/ui_helpers.dart'; +import '../../widgets/custom_circular_progress_indicator.dart'; +import '../../widgets/profile_app_bar.dart'; +import '../../widgets/learn_program_tile.dart'; +import 'learn_program_viewmodel.dart'; + +class LearnProgramView extends StackedView { + const LearnProgramView({Key? key}) : super(key: key); + + @override + void onViewModelReady(LearnProgramViewModel viewModel) async { + await viewModel.getLearnPrograms(); + super.onViewModelReady(viewModel); + } + + @override + LearnProgramViewModel viewModelBuilder(BuildContext context) => + LearnProgramViewModel(); + + @override + Widget builder( + BuildContext context, + LearnProgramViewModel viewModel, + Widget? child, + ) => + _buildScaffoldWrapper(viewModel); + + Widget _buildScaffoldWrapper(LearnProgramViewModel viewModel) => Scaffold( + backgroundColor: kcBackgroundColor, + body: _buildScaffold(viewModel), + ); + + Widget _buildScaffold(LearnProgramViewModel viewModel) => + SafeArea(child: _buildBody(viewModel)); + + Widget _buildBody(LearnProgramViewModel viewModel) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: _buildColumn(viewModel), + ); + + Widget _buildColumn(LearnProgramViewModel viewModel) => Column( + children: [ + verticalSpaceMedium, + _buildAppBar(viewModel), + verticalSpaceMedium, + _buildProgramsColumnWrapper(viewModel) + ], + ); + + Widget _buildAppBar(LearnProgramViewModel viewModel) => ProfileAppBar( + name: viewModel.user?.firstName, + profileImage: viewModel.user?.profilePicture, + ); + + Widget _buildProgramsColumnWrapper(LearnProgramViewModel viewModel) => + Expanded(child: _buildProgramsColumnScrollView(viewModel)); + + Widget _buildProgramsColumnScrollView(LearnProgramViewModel viewModel) => + SingleChildScrollView( + child: _buildListViewBuilder(viewModel), + ); + + Widget _buildListViewBuilder(LearnProgramViewModel viewModel) => + viewModel.busy(StateObjects.learnPrograms) + ? _buildProgressIndicator() + : _buildListView(viewModel); + + Widget _buildProgressIndicator() => const Center( + child: CustomCircularProgressIndicator(color: kcPrimaryColor), + ); + + Widget _buildListView(LearnProgramViewModel viewModel) => ListView.separated( + shrinkWrap: true, + itemCount: viewModel.learnPrograms.length, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (context, index) => verticalSpaceSmall, + itemBuilder: (context, index) => _buildTile( + program: viewModel.learnPrograms[index], + onTap: () async => await viewModel + .navigateToLearnCourse(viewModel.learnPrograms[index].id ?? 0), + ), + ); + + Widget _buildTile({ + required LearnProgram program, + required GestureTapCallback onTap, + }) => + LearnProgramTile(onTap: onTap, program: program); +} diff --git a/lib/ui/views/learn_subcategory/learn_subcategory_viewmodel.dart b/lib/ui/views/learn_program/learn_program_viewmodel.dart similarity index 54% rename from lib/ui/views/learn_subcategory/learn_subcategory_viewmodel.dart rename to lib/ui/views/learn_program/learn_program_viewmodel.dart index 73b81ed..d8e5198 100644 --- a/lib/ui/views/learn_subcategory/learn_subcategory_viewmodel.dart +++ b/lib/ui/views/learn_program/learn_program_viewmodel.dart @@ -1,16 +1,16 @@ import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; +import 'package:yimaru_app/app/app.router.dart'; +import 'package:yimaru_app/models/learn_program.dart'; import '../../../app/app.locator.dart'; -import '../../../app/app.router.dart'; -import '../../../models/subcategory.dart'; import '../../../models/user.dart'; import '../../../services/api_service.dart'; import '../../../services/authentication_service.dart'; import '../../../services/status_checker_service.dart'; import '../../common/enmus.dart'; -class LearnSubcategoryViewModel extends ReactiveViewModel { +class LearnProgramViewModel extends ReactiveViewModel { // Dependency injection final _apiService = locator(); @@ -29,26 +29,28 @@ class LearnSubcategoryViewModel extends ReactiveViewModel { User? get user => _user; - // Learn subcategories - List _subcategories = []; + // Learn programs + List _learnPrograms = []; - List get subcategories => _subcategories; + List get learnPrograms => _learnPrograms; // Navigation - Future navigateToLearn(int id) async => - _navigationService.navigateToLearnView(id: id); + Future navigateToLearnCourse(int id) async => + _navigationService.navigateToLearnCourseView(id: id); // Remote api call - // Learn subcategories - Future getLearnSubcategories() async => - await runBusyFuture(_getLearnSubcategories(), - busyObject: StateObjects.learnSubcategories); + // Learn programs + Future getLearnPrograms() async => + await runBusyFuture(_getLearnPrograms(), + busyObject: StateObjects.learnPrograms); - Future _getLearnSubcategories() async { - if (_subcategories.isEmpty) { + Future _getLearnPrograms() async { + if (_learnPrograms.isEmpty) { if (await _statusChecker.checkConnection()) { - _subcategories = await _apiService.getLearnSubcategories(); + _learnPrograms = await _apiService.getLearnPrograms(); + _learnPrograms + .sort((a, b) => (a.sortOrder ?? 0).compareTo(b.sortOrder ?? 0)); } } } diff --git a/lib/ui/views/learn_subcategory/learn_subcategory_view.dart b/lib/ui/views/learn_subcategory/learn_subcategory_view.dart deleted file mode 100644 index af1cf52..0000000 --- a/lib/ui/views/learn_subcategory/learn_subcategory_view.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/ui/widgets/learn_subcategory_card.dart'; - -import '../../../models/subcategory.dart'; -import '../../common/app_colors.dart'; -import '../../common/enmus.dart'; -import '../../common/ui_helpers.dart'; -import '../../widgets/custom_circular_progress_indicator.dart'; -import '../../widgets/profile_app_bar.dart'; -import 'learn_subcategory_viewmodel.dart'; - -class LearnSubcategoryView extends StackedView { - const LearnSubcategoryView({Key? key}) : super(key: key); - - @override - void onViewModelReady(LearnSubcategoryViewModel viewModel) async { - await viewModel.getLearnSubcategories(); - super.onViewModelReady(viewModel); - } - - @override - LearnSubcategoryViewModel viewModelBuilder(BuildContext context) => - LearnSubcategoryViewModel(); - - @override - Widget builder( - BuildContext context, - LearnSubcategoryViewModel viewModel, - Widget? child, - ) => - _buildScaffoldWrapper(viewModel); - - Widget _buildScaffoldWrapper(LearnSubcategoryViewModel viewModel) => Scaffold( - backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), - ); - - Widget _buildScaffold(LearnSubcategoryViewModel viewModel) => - SafeArea(child: _buildBody(viewModel)); - - Widget _buildBody(LearnSubcategoryViewModel viewModel) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), - ); - - Widget _buildColumn(LearnSubcategoryViewModel viewModel) => Column( - children: [ - verticalSpaceMedium, - _buildAppBar(viewModel), - verticalSpaceMedium, - _buildSubcategoryColumnWrapper(viewModel) - ], - ); - - Widget _buildAppBar(LearnSubcategoryViewModel viewModel) => ProfileAppBar( - name: viewModel.user?.firstName, - profileImage: viewModel.user?.profilePicture, - ); - - Widget _buildSubcategoryColumnWrapper(LearnSubcategoryViewModel viewModel) => - Expanded(child: _buildSubcategoryColumnScrollView(viewModel)); - - Widget _buildSubcategoryColumnScrollView( - LearnSubcategoryViewModel viewModel) => - SingleChildScrollView( - child: _buildListViewBuilder(viewModel), - ); - - Widget _buildListViewBuilder(LearnSubcategoryViewModel viewModel) => - viewModel.busy(StateObjects.learnSubcategories) - ? _buildProgressIndicator() - : _buildListView(viewModel); - - Widget _buildProgressIndicator() => const Center( - child: CustomCircularProgressIndicator(color: kcPrimaryColor), - ); - - Widget _buildListView(LearnSubcategoryViewModel viewModel) => - ListView.separated( - shrinkWrap: true, - itemCount: viewModel.subcategories.length, - physics: const NeverScrollableScrollPhysics(), - separatorBuilder: (context, index) => verticalSpaceSmall, - itemBuilder: (context, index) => _buildTile( - subcategory: viewModel.subcategories[index], - onTap: () async => await viewModel - .navigateToLearn(viewModel.subcategories[index].id ?? 0), - ), - ); - - Widget _buildTile({ - required Subcategory subcategory, - required GestureTapCallback onTap, - }) => - LearnSubcategoryCard( - onTap: onTap, - subcategory: subcategory, - ); -} diff --git a/lib/ui/views/learn_submodule/learn_submodule_view.dart b/lib/ui/views/learn_submodule/learn_submodule_view.dart deleted file mode 100644 index e394e9c..0000000 --- a/lib/ui/views/learn_submodule/learn_submodule_view.dart +++ /dev/null @@ -1,146 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/models/module.dart'; -import 'package:yimaru_app/models/submodule.dart'; -import 'package:yimaru_app/ui/widgets/course_module_banner.dart'; -import 'package:yimaru_app/ui/widgets/learn_submodule_tile.dart'; - -import '../../common/app_colors.dart'; -import '../../common/enmus.dart'; -import '../../common/ui_helpers.dart'; -import '../../widgets/custom_circular_progress_indicator.dart'; -import '../../widgets/custom_elevated_button.dart'; -import '../../widgets/overall_learn_progress.dart'; -import '../../widgets/small_app_bar.dart'; -import 'learn_submodule_viewmodel.dart'; - -class LearnSubmoduleView extends StackedView { - final Module module; - - @override - void onViewModelReady(LearnSubmoduleViewModel viewModel) async { - await viewModel.getSubmodules(module.id ?? 0); - super.onViewModelReady(viewModel); - } - - const LearnSubmoduleView({Key? key, required this.module}) : super(key: key); - - @override - LearnSubmoduleViewModel viewModelBuilder(BuildContext context) => - LearnSubmoduleViewModel(); - - @override - Widget builder( - BuildContext context, - LearnSubmoduleViewModel viewModel, - Widget? child, - ) => - _buildScaffoldWrapper(viewModel); - - Widget _buildScaffoldWrapper(LearnSubmoduleViewModel viewModel) => Scaffold( - backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), - ); - - Widget _buildScaffold(LearnSubmoduleViewModel viewModel) => - SafeArea(child: _buildBody(viewModel)); - - Widget _buildBody(LearnSubmoduleViewModel viewModel) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), - ); - - Widget _buildColumn(LearnSubmoduleViewModel viewModel) => Column( - children: [ - verticalSpaceMedium, - _buildAppBar(viewModel), - verticalSpaceMedium, - _buildModulesColumnWrapper(viewModel), - ], - ); - - Widget _buildAppBar(LearnSubmoduleViewModel viewModel) => SmallAppBar( - title: 'Submodules', - onTap: viewModel.pop, - showBackButton: true, - ); - - Widget _buildModulesColumnWrapper(LearnSubmoduleViewModel viewModel) => - Expanded(child: _buildLevelsColumnScrollView(viewModel)); - - Widget _buildLevelsColumnScrollView(LearnSubmoduleViewModel viewModel) => - SingleChildScrollView( - child: _buildLevelsColumn(viewModel), - ); - - Widget _buildLevelsColumn(LearnSubmoduleViewModel viewModel) => Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: _buildLevelsColumnChildren(viewModel), - ); - - List _buildLevelsColumnChildren(LearnSubmoduleViewModel viewModel) => - [ - verticalSpaceMedium, - _buildTitle(), - verticalSpaceMedium, - _buildCourseModuleBanner(), - verticalSpaceMedium, - _buildOverallProgress(), - verticalSpaceTiny, - _buildContinueButton(viewModel), - verticalSpaceMedium, - _buildListViewBuilder(viewModel) - ]; - - Widget _buildTitle() => Text( - module.title ?? '', - style: style18P600, - ); - - Widget _buildCourseModuleBanner() => const CourseModuleBanner(); - - Widget _buildOverallProgress() => const OverallLearnProgress( - color: Colors.transparent, - ); - - Widget _buildContinueButton(LearnSubmoduleViewModel viewModel) => - const CustomElevatedButton( - height: 55, - borderRadius: 12, - foregroundColor: kcWhite, - text: 'Continue Submodule', - backgroundColor: kcPrimaryColor); - - Widget _buildListViewBuilder(LearnSubmoduleViewModel viewModel) => - viewModel.busy(StateObjects.learnSubmodules) - ? _buildProgressIndicator() - : _buildListView(viewModel); - - Widget _buildProgressIndicator() => const Center( - child: CustomCircularProgressIndicator(color: kcPrimaryColor), - ); - - Widget _buildListView(LearnSubmoduleViewModel viewModel) => ListView.builder( - shrinkWrap: true, - itemCount: viewModel.submodules.length, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _buildTile( - submodule: viewModel.submodules[index], - onPracticeTap: () {}, - onLessonTap: () async => await viewModel - .navigateToLearnLessons(viewModel.submodules[index]), - ), - ); - - Widget _buildTile({ - required Submodule submodule, - required GestureTapCallback onLessonTap, - required GestureTapCallback onPracticeTap, - }) => - LearnSubmoduleTile( - submodule: submodule, - onLessonTap: onLessonTap, - onPracticeTap: onPracticeTap, - ); -} diff --git a/lib/ui/views/learn_submodule/learn_submodule_viewmodel.dart b/lib/ui/views/learn_submodule/learn_submodule_viewmodel.dart deleted file mode 100644 index 9b00dac..0000000 --- a/lib/ui/views/learn_submodule/learn_submodule_viewmodel.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:stacked/stacked.dart'; -import 'package:stacked_services/stacked_services.dart'; -import 'package:yimaru_app/app/app.router.dart'; - -import '../../../app/app.locator.dart'; -import '../../../models/submodule.dart'; -import '../../../services/api_service.dart'; -import '../../../services/status_checker_service.dart'; -import '../../common/enmus.dart'; - -class LearnSubmoduleViewModel extends BaseViewModel { - // Dependency injection - final _apiService = locator(); - - final _statusChecker = locator(); - - final _navigationService = locator(); - - // Learn submodule - List _submodules = []; - - List get submodules => _submodules; - - // Navigation - void pop() => _navigationService.back(); - - Future navigateToLearnLessons(Submodule submodule) async => - await _navigationService.navigateToLearnLessonView(submodule: submodule); - - // Remote api call - - // Learn modules - Future getSubmodules(int id) async => - await runBusyFuture(_getSubmodules(id), - busyObject: StateObjects.learnSubmodules); - - Future _getSubmodules(int id) async { - if (_submodules.isEmpty) { - if (await _statusChecker.checkConnection()) { - _submodules = await _apiService.getSubmodules(id); - _submodules.sort( - (a, b) => (a.displayOrder ?? 0).compareTo(b.displayOrder ?? 0)); - } - } - } -} diff --git a/lib/ui/views/login/login_view.form.dart b/lib/ui/views/login/login_view.form.dart index b809a41..4f8d889 100644 --- a/lib/ui/views/login/login_view.form.dart +++ b/lib/ui/views/login/login_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -219,13 +220,13 @@ extension ValueProperties on FormStateHelper { } extension Methods on FormStateHelper { - setOtpValidationMessage(String? validationMessage) => + void setOtpValidationMessage(String? validationMessage) => this.fieldsValidationMessages[OtpValueKey] = validationMessage; - setPasswordValidationMessage(String? validationMessage) => + void setPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PasswordValueKey] = validationMessage; - setEmailValidationMessage(String? validationMessage) => + void setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - setPhoneNumberValidationMessage(String? validationMessage) => + void setPhoneNumberValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PhoneNumberValueKey] = validationMessage; /// Clears text input fields on the Form @@ -253,7 +254,7 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _LoginViewTextEditingControllers[key]!.text, + _LoginViewTextEditingControllers[key]?.text, ); return validationMessageForKey; diff --git a/lib/ui/views/onboarding/onboarding_view.form.dart b/lib/ui/views/onboarding/onboarding_view.form.dart index 35cadf7..df81d46 100644 --- a/lib/ui/views/onboarding/onboarding_view.form.dart +++ b/lib/ui/views/onboarding/onboarding_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -253,15 +254,15 @@ extension ValueProperties on FormStateHelper { } extension Methods on FormStateHelper { - setTopicValidationMessage(String? validationMessage) => + void setTopicValidationMessage(String? validationMessage) => this.fieldsValidationMessages[TopicValueKey] = validationMessage; - setFullNameValidationMessage(String? validationMessage) => + void setFullNameValidationMessage(String? validationMessage) => this.fieldsValidationMessages[FullNameValueKey] = validationMessage; - setChallengeValidationMessage(String? validationMessage) => + void setChallengeValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ChallengeValueKey] = validationMessage; - setOccupationValidationMessage(String? validationMessage) => + void setOccupationValidationMessage(String? validationMessage) => this.fieldsValidationMessages[OccupationValueKey] = validationMessage; - setLanguageGoalValidationMessage(String? validationMessage) => + void setLanguageGoalValidationMessage(String? validationMessage) => this.fieldsValidationMessages[LanguageGoalValueKey] = validationMessage; /// Clears text input fields on the Form @@ -291,7 +292,7 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _OnboardingViewTextEditingControllers[key]!.text, + _OnboardingViewTextEditingControllers[key]?.text, ); return validationMessageForKey; diff --git a/lib/ui/views/profile_detail/profile_detail_view.form.dart b/lib/ui/views/profile_detail/profile_detail_view.form.dart index 33e5d66..3c52f19 100644 --- a/lib/ui/views/profile_detail/profile_detail_view.form.dart +++ b/lib/ui/views/profile_detail/profile_detail_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -257,15 +258,15 @@ extension ValueProperties on FormStateHelper { } extension Methods on FormStateHelper { - setEmailValidationMessage(String? validationMessage) => + void setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - setPhoneNumberValidationMessage(String? validationMessage) => + void setPhoneNumberValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PhoneNumberValueKey] = validationMessage; - setLastNameValidationMessage(String? validationMessage) => + void setLastNameValidationMessage(String? validationMessage) => this.fieldsValidationMessages[LastNameValueKey] = validationMessage; - setFirstNameValidationMessage(String? validationMessage) => + void setFirstNameValidationMessage(String? validationMessage) => this.fieldsValidationMessages[FirstNameValueKey] = validationMessage; - setOccupationValidationMessage(String? validationMessage) => + void setOccupationValidationMessage(String? validationMessage) => this.fieldsValidationMessages[OccupationValueKey] = validationMessage; /// Clears text input fields on the Form @@ -295,7 +296,7 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _ProfileDetailViewTextEditingControllers[key]!.text, + _ProfileDetailViewTextEditingControllers[key]?.text, ); return validationMessageForKey; diff --git a/lib/ui/views/register/register_view.form.dart b/lib/ui/views/register/register_view.form.dart index 0fe3029..543c227 100644 --- a/lib/ui/views/register/register_view.form.dart +++ b/lib/ui/views/register/register_view.form.dart @@ -1,4 +1,5 @@ // GENERATED CODE - DO NOT MODIFY BY HAND +// dart format width=80 // ************************************************************************** // StackedFormGenerator @@ -252,15 +253,15 @@ extension ValueProperties on FormStateHelper { } extension Methods on FormStateHelper { - setOtpValidationMessage(String? validationMessage) => + void setOtpValidationMessage(String? validationMessage) => this.fieldsValidationMessages[OtpValueKey] = validationMessage; - setEmailValidationMessage(String? validationMessage) => + void setEmailValidationMessage(String? validationMessage) => this.fieldsValidationMessages[EmailValueKey] = validationMessage; - setPasswordValidationMessage(String? validationMessage) => + void setPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PasswordValueKey] = validationMessage; - setPhoneNumberValidationMessage(String? validationMessage) => + void setPhoneNumberValidationMessage(String? validationMessage) => this.fieldsValidationMessages[PhoneNumberValueKey] = validationMessage; - setConfirmPasswordValidationMessage(String? validationMessage) => + void setConfirmPasswordValidationMessage(String? validationMessage) => this.fieldsValidationMessages[ConfirmPasswordValueKey] = validationMessage; @@ -291,7 +292,7 @@ String? getValidationMessage(String key) { if (validatorForKey == null) return null; String? validationMessageForKey = validatorForKey( - _RegisterViewTextEditingControllers[key]!.text, + _RegisterViewTextEditingControllers[key]?.text, ); return validationMessageForKey; diff --git a/lib/ui/views/startup/startup_viewmodel.dart b/lib/ui/views/startup/startup_viewmodel.dart index 69daff5..2bde2b5 100644 --- a/lib/ui/views/startup/startup_viewmodel.dart +++ b/lib/ui/views/startup/startup_viewmodel.dart @@ -1,19 +1,27 @@ import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; import 'package:yimaru_app/services/authentication_service.dart'; +import 'package:yimaru_app/services/in_app_update_service.dart'; import '../../../app/app.locator.dart'; import '../../../app/app.router.dart'; +import '../../../services/status_checker_service.dart'; class StartupViewModel extends BaseViewModel { + // Dependency injection + final _statusChecker = locator(); final _navigationService = locator(); + final _inAppUpdateService = locator(); final _authenticationService = locator(); // Place anything here that needs to happen before we get into the application Future runStartupLogic() async { final loggedIn = await _authenticationService.userLoggedIn(); + final firstTimeInstall = await _authenticationService.isFirstTimeInstall(); + await _inAppUpdate(); + if (firstTimeInstall) { await _navigationService.replaceWithWelcomeView(); } else { @@ -26,4 +34,10 @@ class StartupViewModel extends BaseViewModel { } } } + + Future _inAppUpdate() async { + if (await _statusChecker.checkConnection()) { + await _inAppUpdateService.checkForUpdate(); + } + } } diff --git a/lib/ui/views/welcome/welcome_viewmodel.dart b/lib/ui/views/welcome/welcome_viewmodel.dart index a5e887c..c8dfc1b 100644 --- a/lib/ui/views/welcome/welcome_viewmodel.dart +++ b/lib/ui/views/welcome/welcome_viewmodel.dart @@ -7,25 +7,17 @@ import '../../../app/app.locator.dart'; import '../../../services/status_checker_service.dart'; class WelcomeViewModel extends BaseViewModel { + // Dependency Injection final _navigationService = locator(); final _statusChecker = locator(); final _authenticationService = locator(); - int _currentPage = 0; - - int get currentPage => _currentPage; - // Navigation Future navigateToLogin() async => await _navigationService.navigateToLoginView(); - void next() { - _currentPage++; - rebuildUi(); - } - // Remote api call // First time install @@ -34,9 +26,7 @@ class WelcomeViewModel extends BaseViewModel { } Future _setFirstTimeInstall() async { - if (await _statusChecker.checkConnection()) { - await _authenticationService.setFirstTimeInstall(false); - await navigateToLogin(); - } + await _authenticationService.setFirstTimeInstall(false); + await navigateToLogin(); } } diff --git a/lib/ui/widgets/cancel_learn_practice_sheet.dart b/lib/ui/widgets/cancel_learn_practice_sheet.dart index 40f033f..a3c5de3 100644 --- a/lib/ui/widgets/cancel_learn_practice_sheet.dart +++ b/lib/ui/widgets/cancel_learn_practice_sheet.dart @@ -8,37 +8,38 @@ import '../common/ui_helpers.dart'; import 'custom_bottom_sheet.dart'; import 'custom_elevated_button.dart'; -class CancelLearnPracticeSheet extends ViewModelWidget { +class CancelLearnPracticeSheet extends StatelessWidget { + final String user; final GestureTapCallback? onClose; final GestureTapCallback? onCancel; final GestureTapCallback? onContinue; const CancelLearnPracticeSheet( - {super.key, this.onClose, this.onCancel, this.onContinue}); + {super.key, this.onClose, this.onCancel, this.onContinue,required this.user}); @override - Widget build(BuildContext context, LearnPracticeViewModel viewModel) => - _buildSheetWrapper(viewModel); + Widget build(BuildContext context) => + _buildSheetWrapper(); - Widget _buildSheetWrapper(LearnPracticeViewModel viewModel) => + Widget _buildSheetWrapper() => CustomBottomSheet( - height: 500, onTap: onClose, child: _buildColumnWrapper(viewModel)); + height: 500, onTap: onClose, child: _buildColumnWrapper()); - Widget _buildColumnWrapper(LearnPracticeViewModel viewModel) => Padding( + Widget _buildColumnWrapper() => Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), + child: _buildColumn(), ); - Widget _buildColumn(LearnPracticeViewModel viewModel) => Column( + Widget _buildColumn() => Column( crossAxisAlignment: CrossAxisAlignment.center, - children: _buildSheetChildren(viewModel), + children: _buildSheetChildren(), ); - List _buildSheetChildren(LearnPracticeViewModel viewModel) => [ + List _buildSheetChildren() => [ verticalSpaceLarge, _buildImage(), verticalSpaceMedium, - _buildMessage(viewModel), + _buildMessage(), _buildSubtitle(), verticalSpaceLarge, _buildContinueButton(), @@ -49,10 +50,10 @@ class CancelLearnPracticeSheet extends ViewModelWidget { radius: 45, ); - Widget _buildMessage(LearnPracticeViewModel viewModel) => Text.rich( + Widget _buildMessage() => Text.rich( TextSpan(text: 'You’re almost there,', style: style18DG700, children: [ TextSpan( - text: ' ${viewModel.user?.firstName ?? ''}!', + text: ' $user', style: style18P600, ) ]), diff --git a/lib/ui/widgets/learn_course_tile.dart b/lib/ui/widgets/learn_course_tile.dart new file mode 100644 index 0000000..6947a94 --- /dev/null +++ b/lib/ui/widgets/learn_course_tile.dart @@ -0,0 +1,166 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/ui/widgets/progress_status.dart'; + +import '../../models/learn_course.dart'; +import '../common/app_colors.dart'; +import '../common/ui_helpers.dart'; +import '../views/learn_course/learn_course_viewmodel.dart'; +import 'custom_elevated_button.dart'; + +class LearnCourseTile extends ViewModelWidget { + final LearnCourse course; + final GestureTapCallback? onViewTap; + final GestureTapCallback? onPracticeTap; + + const LearnCourseTile({ + super.key, + this.onViewTap, + this.onPracticeTap, + required this.course, + }); + + @override + Widget build(BuildContext context, LearnCourseViewModel viewModel) => + _buildExpansionTileCard(viewModel); + + Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container( + margin: const EdgeInsets.only(bottom: 15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + border: Border.all(color: kcPrimaryColor.withOpacity(0.1)), + ), + child: _buildExpansionTile(viewModel), + ); + + Widget _buildExpansionTile(LearnCourseViewModel viewModel) => ExpansionTile( + textColor: kcDarkGrey, + subtitle: _buildContent(), + title: _buildTitleWrapper(), + collapsedIconColor: kcDarkGrey, + collapsedTextColor: kcDarkGrey, + shape: Border.all(color: kcTransparent), + expandedAlignment: Alignment.centerLeft, + enabled: (course.access?.isAccessible ?? false), + backgroundColor: kcPrimaryColor.withOpacity(0.1), + controlAffinity: ListTileControlAffinity.trailing, + tilePadding: const EdgeInsets.fromLTRB(15, 0, 15, 5), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + showTrailingIcon: (course.access?.isAccessible ?? false), + initiallyExpanded: (course.access?.isAccessible ?? false), + collapsedBackgroundColor: (course.access?.isAccessible ?? false) + ? kcPrimaryColor.withOpacity(0.1) + : kcBackgroundColor, + children: _buildExpansionTileChildren(viewModel), + ); + + List _buildExpansionTileChildren(LearnCourseViewModel viewModel) => [ + _buildDivider(), + verticalSpaceSmall, + _buildActionButtonsWrapper(viewModel), + verticalSpaceSmall, + ]; + + Widget _buildTitleWrapper() => Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: _buildTitleState(), + ); + + Widget _buildTitleState() => (course.access?.isAccessible ?? false) + ? _buildActiveTitleWrapper() + : _buildInactiveTitleWrapper(); + + Widget _buildInactiveTitleWrapper() => Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: _buildInactiveTitleChildren(), + ); + + List _buildInactiveTitleChildren() => [ + _buildLockIcon(), + verticalSpaceSmall, + _buildTitle(), + ]; + + Widget _buildLockIcon() => const Icon( + Icons.lock_outline_rounded, + color: kcLightGrey, + ); + + Widget _buildActiveTitleWrapper() => Row( + mainAxisSize: MainAxisSize.min, + children: _buildActiveTitleChildren(), + ); + + List _buildActiveTitleChildren() => + [_buildTitle(), horizontalSpaceSmall, _buildProgressStatusState()]; + + Widget _buildTitle() => Text( + course.name ?? '', + style: + (course.access?.isAccessible ?? false) ? style16P600 : style16DG600, + ); + + Widget _buildProgressStatusState() => + !(course.access?.isCompleted ?? false) && + course.access?.progressPercent != 0 + ? _buildProgressStatus() + : Container(); + + Widget _buildProgressStatus() => const ProgressStatus( + color: kcPrimaryColor, + status: 'Current Level', + ); + + Widget _buildContent() => Text( + course.description ?? '', + style: style14DG400, + ); + + Widget _buildDivider() => const Divider(color: kcVeryLightGrey); + + Widget _buildActionButtonsWrapper(LearnCourseViewModel viewModel) => + Container( + height: 40, + margin: const EdgeInsets.symmetric(horizontal: 15), + child: _buildActionButtons(viewModel), + ); + + Widget _buildActionButtons(LearnCourseViewModel viewModel) => Row( + children: [ + _buildViewButtonWrapper(viewModel), + horizontalSpaceSmall, + _buildPracticeButtonWrapper(viewModel) + ], + ); + + Widget _buildViewButtonWrapper(LearnCourseViewModel viewModel) => Expanded( + child: _buildModuleButton(viewModel), + ); + + Widget _buildModuleButton(LearnCourseViewModel viewModel) => + CustomElevatedButton( + height: 15, + borderRadius: 12, + onTap: onViewTap, + text: 'View Courses', + foregroundColor: kcWhite, + backgroundColor: kcPrimaryColor, + ); + + Widget _buildPracticeButtonWrapper(LearnCourseViewModel viewModel) => + Expanded( + child: _buildPracticeButton(viewModel), + ); + + Widget _buildPracticeButton(LearnCourseViewModel viewModel) => + CustomElevatedButton( + height: 15, + borderRadius: 12, + onTap: onPracticeTap, + text: 'View Practices', + backgroundColor: kcWhite, + borderColor: kcPrimaryColor, + foregroundColor: kcPrimaryColor, + ); +} diff --git a/lib/ui/widgets/learn_lesson_tile.dart b/lib/ui/widgets/learn_lesson_tile.dart index b5ed843..ace314c 100644 --- a/lib/ui/widgets/learn_lesson_tile.dart +++ b/lib/ui/widgets/learn_lesson_tile.dart @@ -1,22 +1,28 @@ import 'package:flutter/material.dart'; -import 'package:yimaru_app/models/lesson.dart'; +import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/learn_lesson.dart'; +import 'package:yimaru_app/ui/views/learn_lesson/learn_lesson_viewmodel.dart'; import 'package:yimaru_app/ui/widgets/mini_thumbnail.dart'; import '../common/app_colors.dart'; +import '../common/helper_functions.dart'; import '../common/ui_helpers.dart'; import 'custom_elevated_button.dart'; import 'custom_linear_progress_indicator.dart'; -class LearnLessonTile extends StatelessWidget { - final Lesson lesson; +class LearnLessonTile extends ViewModelWidget { + final LearnLesson lesson; final GestureTapCallback? onLessonTap; + final GestureTapCallback? onPracticeTap; - const LearnLessonTile({super.key, this.onLessonTap, required this.lesson}); + const LearnLessonTile( + {super.key, this.onLessonTap, this.onPracticeTap, required this.lesson}); @override - Widget build(BuildContext context) => _buildContainer(); + Widget build(BuildContext context, LearnLessonViewModel viewModel) => + _buildContainer(viewModel); - Widget _buildContainer() => Container( + Widget _buildContainer(LearnLessonViewModel viewModel) => Container( width: double.maxFinite, margin: const EdgeInsets.only(bottom: 15), decoration: BoxDecoration( @@ -28,27 +34,27 @@ class LearnLessonTile extends StatelessWidget { // : kcGreen.withOpacity(0.1), ), ), - child: _buildExpansionTile(), + child: _buildExpansionTile(viewModel), ); - Widget _buildExpansionTile() => ExpansionTile( + Widget _buildExpansionTile(LearnLessonViewModel viewModel) => ExpansionTile( enabled: true, title: _buildTitle(), textColor: kcDarkGrey, showTrailingIcon: true, - initiallyExpanded: true, + initiallyExpanded: false, trailing: _buildPendingIcon(), collapsedIconColor: kcDarkGrey, collapsedTextColor: kcDarkGrey, leading: _buildLeadingWrapper(), shape: Border.all(color: kcTransparent), expandedAlignment: Alignment.centerLeft, - backgroundColor: kcGreen.withOpacity(0.1), + backgroundColor: kcPrimaryColor.withOpacity(0.1), controlAffinity: ListTileControlAffinity.trailing, + tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 0), expandedCrossAxisAlignment: CrossAxisAlignment.start, collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1), - childrenPadding: const EdgeInsets.fromLTRB(15, 15, 15, 15), - tilePadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), + childrenPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15), // enabled: status != ProgressStatuses.pending, // backgroundColor: ProgressStatuses.pending == status // ? kcPrimaryColor.withOpacity(0.1) @@ -57,14 +63,18 @@ class LearnLessonTile extends StatelessWidget { // ? kcPrimaryColor.withOpacity(0.1) // : kcGreen.withOpacity(0.1), // initiallyExpanded: status != ProgressStatuses.completed ? true : false, - children: _buildExpansionTileChildren(), + children: _buildExpansionTileChildren(viewModel), ); - Widget _buildLeadingWrapper() => - MiniThumbnail(thumbnail: lesson.thumbnail ?? 'assets/images/image_1.png'); + Widget _buildLeadingWrapper() => MiniThumbnail( + thumbnail: + getReadableUrl(lesson.thumbnail ?? 'assets/images/image_1.png') ?? + 'assets/images/image_1.png'); Widget _buildTitle() => Text( lesson.title ?? '', + maxLines: 1, + softWrap: false, style: style16DG600, ); @@ -82,20 +92,23 @@ class LearnLessonTile extends StatelessWidget { color: kcPrimaryColor, ); - List _buildExpansionTileChildren() => [_buildExpansionTileItem()]; + List _buildExpansionTileChildren(LearnLessonViewModel viewModel) => + [_buildExpansionTileItem(viewModel)]; - Widget _buildExpansionTileItem() => Column( + Widget _buildExpansionTileItem(LearnLessonViewModel viewModel) => Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: _buildExpansionTileItemChildren(), + children: _buildExpansionTileItemChildren(viewModel), ); - List _buildExpansionTileItemChildren() => [ + List _buildExpansionTileItemChildren( + LearnLessonViewModel viewModel) => + [ _buildProgress(), horizontalSpaceSmall, - // _buildProgressText(), - // verticalSpaceSmall, - _buildActionButtonWrapper() + _buildProgressText(), + verticalSpaceSmall, + _buildActionButtonWrapper(viewModel) ]; Widget _buildProgress() => const CustomLinearProgressIndicator( @@ -104,17 +117,53 @@ class LearnLessonTile extends StatelessWidget { backgroundColor: kcVeryLightGrey, ); - // Widget _buildProgressText() => Text( - // ProgressStatuses.completed == status ? 'Completed' : 'In Progress', - // style: style14P400, - // ); - - Widget _buildActionButtonWrapper() => SizedBox( - height: 50, - child: _buildLessonButton(), + Widget _buildProgressText() => Text( + 'In Progress', + style: style14P600, ); - Widget _buildLessonButton() => CustomElevatedButton( + Widget _buildActionButtonWrapper(LearnLessonViewModel viewModel) => SizedBox( + height: 40, + child: _buildActionButtons(viewModel), + ); + + Widget _buildActionButtons(LearnLessonViewModel viewModel) => Row( + mainAxisAlignment: MainAxisAlignment.end, + children: __buildActionButtonChildren(viewModel), + ); + + List __buildActionButtonChildren(LearnLessonViewModel viewModel) => [ + _buildPracticeButtonWrapper(viewModel), + horizontalSpaceSmall, + _buildLessonButtonWrapper(viewModel) + ]; + + Widget _buildPracticeButtonWrapper(LearnLessonViewModel viewModel) => + SizedBox( + width: 125, + child: _buildPracticeButton(viewModel), + ); + + Widget _buildPracticeButton(LearnLessonViewModel viewModel) => + CustomElevatedButton( + height: 15, + text: 'Practice', + borderRadius: 12, + onTap: onPracticeTap, + trailingIcon: Icons.mic, + width: double.maxFinite, + backgroundColor: kcWhite, + borderColor: kcPrimaryColor, + foregroundColor: kcPrimaryColor, + ); + + Widget _buildLessonButtonWrapper(LearnLessonViewModel viewModel) => SizedBox( + width: 125, + child: _buildLessonButton(viewModel), + ); + + Widget _buildLessonButton(LearnLessonViewModel viewModel) => + CustomElevatedButton( height: 15, text: 'Start', borderRadius: 12, diff --git a/lib/ui/widgets/learn_level_tile.dart b/lib/ui/widgets/learn_level_tile.dart deleted file mode 100644 index 8c811ff..0000000 --- a/lib/ui/widgets/learn_level_tile.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/ui/views/learn_level/learn_level_viewmodel.dart'; -import 'package:yimaru_app/ui/widgets/progress_status.dart'; - -import '../../models/level.dart'; -import '../common/app_colors.dart'; -import '../common/ui_helpers.dart'; -import 'custom_elevated_button.dart'; - -class LearnLevelTile extends ViewModelWidget { - final Level level; - final GestureTapCallback? onTap; - - const LearnLevelTile({ - super.key, - this.onTap, - required this.level, - }); - - @override - Widget build(BuildContext context, LearnLevelViewModel viewModel) => - _buildExpansionTileCard(viewModel); - - Widget _buildExpansionTileCard(LearnLevelViewModel viewModel) => Container( - margin: const EdgeInsets.only(bottom: 15), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - border: Border.all( - color: kcPrimaryColor.withOpacity(0.2), - // color: - // current ? kcPrimaryColor.withOpacity(0.2) : kcVeryLightGrey, - ), - ), - child: _buildExpansionTile(viewModel), - ); - - Widget _buildExpansionTile(LearnLevelViewModel viewModel) => ExpansionTile( - enabled: true, - textColor: kcDarkGrey, - showTrailingIcon: true, - title: _buildTitleRow(), - initiallyExpanded: false, - collapsedIconColor: kcDarkGrey, - collapsedTextColor: kcDarkGrey, - shape: Border.all(color: kcTransparent), - expandedAlignment: Alignment.centerLeft, - backgroundColor: kcPrimaryColor.withOpacity(0.1), - controlAffinity: ListTileControlAffinity.trailing, - expandedCrossAxisAlignment: CrossAxisAlignment.start, - tilePadding: const EdgeInsets.symmetric(horizontal: 15), - collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1), - childrenPadding: const EdgeInsets.only(left: 15, right: 15, bottom: 15), - - //enabled: current, - // showTrailingIcon: current, - //initiallyExpanded: current, - // collapsedBackgroundColor: - // current ? kcPrimaryColor.withOpacity(0.1) : kcBackgroundColor, - // backgroundColor: - // current ? kcPrimaryColor.withOpacity(0.1) : kcBackgroundColor, - children: _buildExpansionTileChildren(viewModel), - ); - - List _buildExpansionTileChildren(LearnLevelViewModel viewModel) => - [_buildViewButton(viewModel)]; - - Widget _buildTitleRow() => Row( - mainAxisSize: MainAxisSize.min, - children: _buildTitleChildren(), - ); - - List _buildTitleChildren() => [ - _buildTitle(), - // if (current) horizontalSpaceSmall, - // if (current) _buildProgressStatus() - ]; - - Widget _buildTitle() => Text( - level.title ?? '', - style: style16P600, - ); - - Widget _buildProgressStatus() => const ProgressStatus( - color: kcPrimaryColor, - status: 'Current Level', - ); - - Widget _buildViewButton(LearnLevelViewModel viewModel) => - CustomElevatedButton( - height: 15, - onTap: onTap, - borderRadius: 12, - text: 'View Level', - foregroundColor: kcWhite, - backgroundColor: kcPrimaryColor, - ); -} diff --git a/lib/ui/widgets/learn_module_tile.dart b/lib/ui/widgets/learn_module_tile.dart index be883e7..1aa28c8 100644 --- a/lib/ui/widgets/learn_module_tile.dart +++ b/lib/ui/widgets/learn_module_tile.dart @@ -1,19 +1,21 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/learn_module.dart'; import 'package:yimaru_app/ui/views/learn_module/learn_module_viewmodel.dart'; import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart'; import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart'; -import '../../models/module.dart'; import '../common/app_colors.dart'; import '../common/ui_helpers.dart'; import 'custom_elevated_button.dart'; class LearnModuleTile extends ViewModelWidget { - final Module module; + final LearnModule module; final GestureTapCallback? onModuleTap; + final GestureTapCallback? onPracticeTap; - const LearnModuleTile({super.key, this.onModuleTap, required this.module}); + const LearnModuleTile( + {super.key, this.onModuleTap, this.onPracticeTap, required this.module}); Future _showSheet( {required BuildContext context, @@ -35,7 +37,7 @@ class LearnModuleTile extends ViewModelWidget { margin: const EdgeInsets.only(bottom: 15), decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), - border: Border.all(color: kcVeryLightGrey), + border: Border.all(color: kcPrimaryColor.withOpacity(0.1)), ), child: _buildTileStack(context: context, viewModel: viewModel), ); @@ -55,11 +57,11 @@ class LearnModuleTile extends ViewModelWidget { required LearnModuleViewModel viewModel}) => ExpansionTile( enabled: true, - title: _buildTitle(), textColor: kcDarkGrey, showTrailingIcon: true, initiallyExpanded: true, subtitle: _buildContent(), + title: _buildTitleWrapper(), leading: _buildIconWrapper(), collapsedIconColor: kcDarkGrey, collapsedTextColor: kcDarkGrey, @@ -70,8 +72,8 @@ class LearnModuleTile extends ViewModelWidget { controlAffinity: ListTileControlAffinity.trailing, expandedCrossAxisAlignment: CrossAxisAlignment.start, tilePadding: const EdgeInsets.symmetric(horizontal: 15), - childrenPadding: const EdgeInsets.fromLTRB(70, 15, 15, 15), - // enabled: status != ProgressStatuses.pending, + childrenPadding: const EdgeInsets.fromLTRB(70, 0, 15, 15), + // enabled:(module.access?.isAccessible ?? false) , // showTrailingIcon: status != ProgressStatuses.pending ? true : false, //initiallyExpanded: status == ProgressStatuses.started ? true : false, children: @@ -88,8 +90,13 @@ class LearnModuleTile extends ViewModelWidget { color: kcPrimaryColor, ); + Widget _buildTitleWrapper() => Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: _buildTitle(), + ); + Widget _buildTitle() => Text( - module.title ?? '', + module.name ?? '', maxLines: 1, softWrap: false, style: style16P600, @@ -123,8 +130,8 @@ class LearnModuleTile extends ViewModelWidget { {required BuildContext context, required LearnModuleViewModel viewModel}) => [ - // _buildProgressRow(), - // verticalSpaceSmall, + _buildProgressRow(), + verticalSpaceSmall, _buildActionButtonWrapper(context: context, viewModel: viewModel) ]; @@ -141,12 +148,12 @@ class LearnModuleTile extends ViewModelWidget { ); Widget _buildProgressStatus() => const CustomLinearProgressIndicator( - progress: 0.75, + progress: 0, activeColor: kcPrimaryColor, - backgroundColor: kcVeryLightGrey); + backgroundColor: kcPrimaryColorLight); Widget _buildProgress() => const Text( - '2/3', + '0/0', style: TextStyle(color: kcDarkGrey), ); @@ -155,17 +162,14 @@ class LearnModuleTile extends ViewModelWidget { required LearnModuleViewModel viewModel}) => SizedBox( height: 40, - child: _buildModuleButton(viewModel), + child: _buildActionButtons(viewModel), ); - Widget _buildActionButtons( - {required BuildContext context, - required LearnModuleViewModel viewModel}) => - Row( + Widget _buildActionButtons(LearnModuleViewModel viewModel) => Row( children: [ _buildModuleButtonWrapper(viewModel), horizontalSpaceSmall, - _buildPracticeButtonWrapper(context: context, viewModel: viewModel) + _buildPracticeButtonWrapper(viewModel) ], ); @@ -183,23 +187,21 @@ class LearnModuleTile extends ViewModelWidget { backgroundColor: kcPrimaryColor, ); - Widget _buildPracticeButtonWrapper( - {required BuildContext context, - required LearnModuleViewModel viewModel}) => + Widget _buildPracticeButtonWrapper(LearnModuleViewModel viewModel) => Expanded( - child: Container(), + child: _buildPracticeButton(viewModel), ); - Widget _buildPracticeButton( - {required BuildContext context, - required LearnModuleViewModel viewModel}) => - const CustomElevatedButton( + Widget _buildPracticeButton(LearnModuleViewModel viewModel) => + CustomElevatedButton( height: 15, borderRadius: 12, - text: 'View Practices', + onTap: onPracticeTap, + text: 'Take Practices', backgroundColor: kcWhite, borderColor: kcPrimaryColor, foregroundColor: kcPrimaryColor, + // onTap: () async => await viewModel.navigateToLearnPractice(practices), ); diff --git a/lib/ui/widgets/learn_practice_answer_card.dart b/lib/ui/widgets/learn_practice_answer_card.dart index fe60aca..92d5321 100644 --- a/lib/ui/widgets/learn_practice_answer_card.dart +++ b/lib/ui/widgets/learn_practice_answer_card.dart @@ -8,11 +8,15 @@ import '../common/ui_helpers.dart'; import '../views/learn_practice/learn_practice_viewmodel.dart'; class LearnPracticeAnswerCard extends ViewModelWidget { + final Voice voice; final String title; - final StateObjects object; + final Map answer; const LearnPracticeAnswerCard( - {super.key, required this.title, required this.object}); + {super.key, + required this.voice, + required this.title, + required this.answer}); @override Widget build(BuildContext context, LearnPracticeViewModel viewModel) => @@ -38,25 +42,20 @@ class LearnPracticeAnswerCard extends ViewModelWidget { shadowColor: WidgetStatePropertyAll(kcPrimaryColor), backgroundColor: WidgetStatePropertyAll(kcPrimaryColor), ), - onPressed: () async => viewModel.player.state == PlayerState.playing - ? viewModel.busyObject == StateObjects.learnPracticeSample - ? await viewModel.pauseSampleAudio() - : await viewModel.pauseRecordedAudio() - : object == StateObjects.learnPracticeSample - ? await viewModel.playSampleAudio() - : await viewModel.playRecordedAudio(), + onPressed: () async => viewModel.busyObject == answer['busy_object'] && + viewModel.player.state == PlayerState.playing + ? await viewModel.pauseAudio() + : await viewModel.playResult(answer: answer, voice: voice), child: _buildButtonState(viewModel), ); Widget _buildButtonState(LearnPracticeViewModel viewModel) => - viewModel.busy(object) - ? viewModel.busyObject == object - ? _buildPauseIcon() - : _buildPlayIcon() - : viewModel.busyObject == object && - viewModel.player.state == PlayerState.playing - ? _buildPauseIcon() - : _buildPlayIcon(); + (viewModel.busy(answer['busy_object']) && viewModel.playing == voice) || + (viewModel.busyObject == answer['busy_object'] && + viewModel.playing == voice && + viewModel.player.state == PlayerState.playing) + ? _buildPauseIcon() + : _buildPlayIcon(); Widget _buildPlayIcon() => const Icon( Icons.play_arrow_rounded, diff --git a/lib/ui/widgets/learn_practice_card.dart b/lib/ui/widgets/learn_practice_card.dart index 866bd61..aa39805 100644 --- a/lib/ui/widgets/learn_practice_card.dart +++ b/lib/ui/widgets/learn_practice_card.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/practice.dart'; import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart'; import '../common/app_colors.dart'; @@ -8,8 +9,8 @@ import 'custom_elevated_button.dart'; class LearnPracticeCard extends ViewModelWidget { final int index; + final Practice practice; final GestureTapCallback? onTap; - final Map practice; const LearnPracticeCard( {super.key, this.onTap, required this.index, required this.practice}); @@ -57,6 +58,6 @@ class LearnPracticeCard extends ViewModelWidget { text: 'Practice', foregroundColor: kcWhite, backgroundColor: kcPrimaryColor, - onTap: () => viewModel.setPractice(practice), + // onTap: () => viewModel.setPractice(practice), ); } diff --git a/lib/ui/widgets/learn_practice_result_card.dart b/lib/ui/widgets/learn_practice_result_card.dart index 0def5bd..b2fba0a 100644 --- a/lib/ui/widgets/learn_practice_result_card.dart +++ b/lib/ui/widgets/learn_practice_result_card.dart @@ -6,30 +6,31 @@ import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart import 'package:yimaru_app/ui/widgets/learn_practice_answer_card.dart'; class LearnPracticeResultCard extends ViewModelWidget { - final Map data; - const LearnPracticeResultCard({super.key, required this.data}); + final Map answer; + + const LearnPracticeResultCard({super.key, required this.answer}); @override Widget build(BuildContext context, LearnPracticeViewModel viewModel) => - _buildColumnWrapper(); + _buildColumnWrapper(viewModel); - Widget _buildColumnWrapper() => SizedBox( + Widget _buildColumnWrapper(LearnPracticeViewModel viewModel) => SizedBox( height: 100, width: double.maxFinite, - child: _buildColumn(), + child: _buildColumn(viewModel), ); - Widget _buildColumn() => Column( + Widget _buildColumn(LearnPracticeViewModel viewModel) => Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: _buildColumnChildren(), + children: _buildColumnChildren(viewModel), ); - List _buildColumnChildren() => - [_buildQuestion(), verticalSpaceSmall, _buildRow()]; + List _buildColumnChildren(LearnPracticeViewModel viewModel) => + [_buildQuestion(viewModel), verticalSpaceSmall, _buildRow()]; - Widget _buildQuestion() => Text( - data['question_text'], + Widget _buildQuestion(LearnPracticeViewModel viewModel) => Text( + answer['sample_text_answer'], style: style14DG400, ); @@ -46,16 +47,18 @@ class LearnPracticeResultCard extends ViewModelWidget { Widget _buildSampleResponseWrapper() => Expanded(child: _buildSampleResponse()); - Widget _buildSampleResponse() => const LearnPracticeAnswerCard( + Widget _buildSampleResponse() => LearnPracticeAnswerCard( + answer: answer, + voice: Voice.sample, title: 'Sample Answer', - object: StateObjects.learnPracticeSample, ); Widget _buildActualResponseWrapper() => Expanded(child: _buildActualResponse()); - Widget _buildActualResponse() => const LearnPracticeAnswerCard( + Widget _buildActualResponse() => LearnPracticeAnswerCard( + answer: answer, title: 'Your Answer', - object: StateObjects.learnPracticeAnswer, + voice: Voice.recorded, ); } diff --git a/lib/ui/widgets/learn_practice_results_wrapper.dart b/lib/ui/widgets/learn_practice_results_wrapper.dart index 5447abb..b9ea64c 100644 --- a/lib/ui/widgets/learn_practice_results_wrapper.dart +++ b/lib/ui/widgets/learn_practice_results_wrapper.dart @@ -1,34 +1,39 @@ import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart'; +import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart'; import 'package:yimaru_app/ui/widgets/learn_practice_result_card.dart'; import '../common/app_colors.dart'; -class LearnPracticeResultsWrapper extends StatelessWidget { - final Map data; - - const LearnPracticeResultsWrapper({super.key, required this.data}); +class LearnPracticeResultsWrapper + extends ViewModelWidget { + const LearnPracticeResultsWrapper({super.key}); @override - Widget build(BuildContext context) => _buildContainer(); + Widget build(BuildContext context, LearnPracticeViewModel viewModel) => + _buildContainer(viewModel); - Widget _buildContainer() => Container( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25), + Widget _buildContainer(LearnPracticeViewModel viewModel) => Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: kcPrimaryColor.withOpacity(0.1), ), - child: _buildColumn(), + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25), + child: _buildColumn(viewModel), ); - Widget _buildColumn() => Column( + Widget _buildColumn(LearnPracticeViewModel viewModel) => Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: _buildColumnChildren(), + children: _buildColumnChildren(viewModel), ); - List _buildColumnChildren() => - [_buildTitle(), verticalSpaceSmall, if (data.isNotEmpty) _buildResult()]; + List _buildColumnChildren(LearnPracticeViewModel viewModel) => [ + _buildTitle(), + verticalSpaceSmall, + _buildResults(viewModel) + ]; Widget _buildTitle() => Text( 'Conversation Review', @@ -36,5 +41,15 @@ class LearnPracticeResultsWrapper extends StatelessWidget { textAlign: TextAlign.center, ); - Widget _buildResult() => LearnPracticeResultCard(data: data); + Widget _buildResults(LearnPracticeViewModel viewModel) => ListView.separated( + shrinkWrap: true, + itemCount: viewModel.answers.length, + physics: const NeverScrollableScrollPhysics(), + separatorBuilder: (context, index) => verticalSpaceSmall, + itemBuilder: (context, index) => _buildResult( viewModel.answers[index]), + ); + + + + Widget _buildResult(Map answer) => LearnPracticeResultCard(answer: answer,); } diff --git a/lib/ui/widgets/learn_practice_tip_section.dart b/lib/ui/widgets/learn_practice_tip_section.dart index e0dcc0d..a1233ee 100644 --- a/lib/ui/widgets/learn_practice_tip_section.dart +++ b/lib/ui/widgets/learn_practice_tip_section.dart @@ -1,30 +1,34 @@ import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; import 'package:yimaru_app/ui/common/app_colors.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart'; +import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart'; -class LearnPracticeTipSection extends StatelessWidget { +import '../../models/learn_practice.dart'; + +class LearnPracticeTipSection extends ViewModelWidget { const LearnPracticeTipSection({super.key}); @override - Widget build(BuildContext context) => _buildContainer(); + Widget build(BuildContext context,LearnPracticeViewModel viewModel) => _buildContainer(viewModel); - Widget _buildContainer() => Container( + Widget _buildContainer(LearnPracticeViewModel viewModel) => Container( padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: kcBlue.withOpacity(0.1), ), - child: _buildColumn(), + child: _buildColumn(viewModel), ); - Widget _buildColumn() => Column( + Widget _buildColumn(LearnPracticeViewModel viewModel) => Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, - children: _buildColumnChildren(), + children: _buildColumnChildren( viewModel), ); - List _buildColumnChildren() => - [_buildTitleWrapper(), verticalSpaceTiny, _buildContent()]; + List _buildColumnChildren(LearnPracticeViewModel viewModel) => + [_buildTitleWrapper(), verticalSpaceTiny, _buildContent(viewModel)]; Widget _buildTitleWrapper() => Row( children: [_buildLeading(), horizontalSpaceSmall, _buildTitle()], @@ -40,8 +44,8 @@ class LearnPracticeTipSection extends StatelessWidget { style: style16B600, ); - Widget _buildContent() => Text( - "You can always do better!\nSpeak in full sentences instead of short phrases.\nMaintain a steady pace, not too fast, not too slow.\nUse varied vocabulary to make your answers richer.\nPause naturally instead of using fillers like “um” or “uh”.", + Widget _buildContent(LearnPracticeViewModel viewModel) => Text( + viewModel.practices.firstOrNull?.quickTips ?? '', style: style14B400, textAlign: TextAlign.start, ); diff --git a/lib/ui/widgets/learn_program_tile.dart b/lib/ui/widgets/learn_program_tile.dart new file mode 100644 index 0000000..d6b3dec --- /dev/null +++ b/lib/ui/widgets/learn_program_tile.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/ui/common/ui_helpers.dart'; +import 'package:yimaru_app/ui/widgets/progress_status.dart'; + +import '../../models/learn_program.dart'; +import '../common/app_colors.dart'; +import '../views/learn_program/learn_program_viewmodel.dart'; +import 'custom_elevated_button.dart'; + +class LearnProgramTile extends ViewModelWidget { + final LearnProgram program; + final GestureTapCallback? onTap; + + const LearnProgramTile({super.key, this.onTap, required this.program}); + + @override + Widget build(BuildContext context, LearnProgramViewModel viewModel) => + _buildExpansionTileCard(viewModel); + + Widget _buildExpansionTileCard(LearnProgramViewModel viewModel) => Container( + margin: const EdgeInsets.only(bottom: 15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + border: Border.all(color: kcPrimaryColor.withOpacity(0.1)), + ), + child: _buildExpansionTile(viewModel), + ); + + Widget _buildExpansionTile(LearnProgramViewModel viewModel) => ExpansionTile( + textColor: kcDarkGrey, + subtitle: _buildContent(), + title: _buildTitleWrapper(), + collapsedIconColor: kcDarkGrey, + collapsedTextColor: kcDarkGrey, + shape: Border.all(color: kcTransparent), + expandedAlignment: Alignment.centerLeft, + enabled: (program.access?.isAccessible ?? false), + backgroundColor: kcPrimaryColor.withOpacity(0.1), + controlAffinity: ListTileControlAffinity.trailing, + tilePadding: const EdgeInsets.fromLTRB(15, 0, 15, 5), + expandedCrossAxisAlignment: CrossAxisAlignment.start, + showTrailingIcon: (program.access?.isAccessible ?? false), + initiallyExpanded: (program.access?.isAccessible ?? false), + collapsedBackgroundColor: (program.access?.isAccessible ?? false) + ? kcPrimaryColor.withOpacity(0.1) + : kcBackgroundColor, + children: _buildExpansionTileChildren(viewModel), + ); + + List _buildExpansionTileChildren(LearnProgramViewModel viewModel) => [ + _buildDivider(), + verticalSpaceSmall, + _buildActionButtonWrapper(viewModel), + verticalSpaceMedium, + ]; + + Widget _buildTitleWrapper() => Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: _buildTitleState(), + ); + + Widget _buildTitleState() => (program.access?.isAccessible ?? false) + ? _buildActiveTitleWrapper() + : _buildInactiveTitleWrapper(); + + Widget _buildInactiveTitleWrapper() => Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: _buildInactiveTitleChildren(), + ); + + List _buildInactiveTitleChildren() => [ + _buildLockIcon(), + verticalSpaceSmall, + _buildTitle(), + ]; + + Widget _buildLockIcon() => const Icon( + Icons.lock_outline_rounded, + color: kcLightGrey, + ); + + Widget _buildActiveTitleWrapper() => Row( + mainAxisSize: MainAxisSize.min, + children: _buildActiveTitleChildren(), + ); + + List _buildActiveTitleChildren() => + [_buildTitle(), horizontalSpaceSmall, _buildProgressStatus()]; + + Widget _buildTitle() => Text( + program.name ?? '', + style: (program.access?.isAccessible ?? false) + ? style16P600 + : style16DG600, + ); + + Widget _buildProgressStatus() => ProgressStatus( + color: kcPrimaryColor, + status: (program.access?.isCompleted ?? false) + ? 'Completed' + : 'In Progress', + ); + + Widget _buildContent() => Text( + program.description ?? '', + style: style14DG400, + ); + + Widget _buildDivider() => const Divider(color: kcVeryLightGrey); + + Widget _buildActionButtonWrapper(LearnProgramViewModel viewModel) => Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: _buildActionButton(viewModel), + ); + + Widget _buildActionButton(LearnProgramViewModel viewModel) => + CustomElevatedButton( + height: 15, + onTap: onTap, + borderRadius: 12, + foregroundColor: kcWhite, + backgroundColor: kcPrimaryColor, + text: program.access?.progressPercent == 0 + ? 'Start Learning' + : 'Continue Learning', + ); +} diff --git a/lib/ui/widgets/learn_subcategory_card.dart b/lib/ui/widgets/learn_subcategory_card.dart deleted file mode 100644 index d09c3da..0000000 --- a/lib/ui/widgets/learn_subcategory_card.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:yimaru_app/models/subcategory.dart'; - -import '../common/app_colors.dart'; -import '../common/app_strings.dart'; -import '../common/helper_functions.dart'; -import '../common/ui_helpers.dart'; -import 'custom_elevated_button.dart'; - -class LearnSubcategoryCard extends StatelessWidget { - final Subcategory subcategory; - final GestureTapCallback? onTap; - - const LearnSubcategoryCard( - {super.key, this.onTap, required this.subcategory}); - - @override - Widget build(BuildContext context) => _buildContainer(); - - Widget _buildContainer() => Container( - height: 200, - padding: const EdgeInsets.all(15), - decoration: BoxDecoration( - color: getColor(), - borderRadius: BorderRadius.circular(5), - ), - child: _buildColumn(), - ); - - Widget _buildColumn() => Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: _buildColumnChildren(), - ); - - List _buildColumnChildren() => [ - _buildTitle(), - verticalSpaceTiny, - _buildSubtitle(), - verticalSpaceMedium, - __buildStartButtonWrapper(), - ]; - - Widget _buildTitle() => Text( - subcategory.name ?? '', - style: style18DG700, - ); - - Widget _buildSubtitle() => Text( - subcategory.description ?? ksCategorySubtitle, - maxLines: 3, - style: style16DG400, - ); - - Widget __buildStartButtonWrapper() => SizedBox( - height: 40, - child: _buildStartButton(), - ); - - Widget _buildStartButton() => CustomElevatedButton( - height: 50, - width: 200, - onTap: onTap, - borderRadius: 12, - text: 'Select Course', - foregroundColor: kcWhite, - backgroundColor: kcPrimaryColor, - ); -} diff --git a/lib/ui/widgets/learn_submodule_tile.dart b/lib/ui/widgets/learn_submodule_tile.dart deleted file mode 100644 index b735273..0000000 --- a/lib/ui/widgets/learn_submodule_tile.dart +++ /dev/null @@ -1,237 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/models/submodule.dart'; -import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart'; -import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart'; - -import '../common/app_colors.dart'; -import '../common/ui_helpers.dart'; -import '../views/learn_submodule/learn_submodule_viewmodel.dart'; -import 'custom_elevated_button.dart'; - -class LearnSubmoduleTile extends ViewModelWidget { - final Submodule submodule; - final GestureTapCallback? onLessonTap; - final GestureTapCallback? onPracticeTap; - - const LearnSubmoduleTile( - {super.key, - this.onLessonTap, - this.onPracticeTap, - required this.submodule}); - - Future _showSheet( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) async => - await showModalBottomSheet( - context: context, - backgroundColor: kcTransparent, - builder: (_) => _buildSheet(viewModel), - ); - - @override - Widget build(BuildContext context, LearnSubmoduleViewModel viewModel) => - _buildExpansionTileCard(context: context, viewModel: viewModel); - - Widget _buildExpansionTileCard( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - Container( - margin: const EdgeInsets.only(bottom: 15), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - border: Border.all(color: kcVeryLightGrey), - ), - child: _buildTileStack(context: context, viewModel: viewModel), - ); - - Widget _buildTileStack( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - Stack( - children: [ - _buildExpansionTile(context: context, viewModel: viewModel), - // _buildContainerShaderState() - ], - ); - - Widget _buildExpansionTile( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - ExpansionTile( - enabled: true, - title: _buildTitle(), - textColor: kcDarkGrey, - showTrailingIcon: true, - initiallyExpanded: true, - subtitle: _buildContent(), - leading: _buildIconWrapper(), - collapsedIconColor: kcDarkGrey, - collapsedTextColor: kcDarkGrey, - backgroundColor: kcBackgroundColor, - shape: Border.all(color: kcTransparent), - expandedAlignment: Alignment.centerLeft, - collapsedBackgroundColor: kcBackgroundColor, - controlAffinity: ListTileControlAffinity.trailing, - expandedCrossAxisAlignment: CrossAxisAlignment.start, - tilePadding: const EdgeInsets.symmetric(horizontal: 15), - childrenPadding: const EdgeInsets.fromLTRB(70, 15, 15, 15), - // enabled: status != ProgressStatuses.pending, - // showTrailingIcon: status != ProgressStatuses.pending ? true : false, - //initiallyExpanded: status == ProgressStatuses.started ? true : false, - children: - _buildExpansionTileChildren(context: context, viewModel: viewModel), - ); - - Widget _buildIconWrapper() => CircleAvatar( - backgroundColor: kcPrimaryColor.withOpacity(0.1), - child: _buildIcon(), - ); - - Widget _buildIcon() => const Icon( - Icons.lightbulb_outline, - color: kcPrimaryColor, - ); - - Widget _buildTitle() => Text( - submodule.title ?? '', - maxLines: 1, - softWrap: false, - style: style16P600, - overflow: TextOverflow.ellipsis, - ); - - Widget _buildContent() => Text( - submodule.description ?? '', - maxLines: 1, - softWrap: false, - style: style14DG400, - overflow: TextOverflow.ellipsis, - ); - - List _buildExpansionTileChildren( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - [_buildExpansionTileItem(context: context, viewModel: viewModel)]; - - Widget _buildExpansionTileItem( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: _buildExpansionTileItemChildren( - context: context, viewModel: viewModel), - ); - - List _buildExpansionTileItemChildren( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - [ - // _buildProgressRow(), - // verticalSpaceSmall, - _buildActionButtonWrapper(context: context, viewModel: viewModel) - ]; - - Widget _buildProgressRow() => Row( - mainAxisSize: MainAxisSize.min, - children: _buildProgressChildren(), - ); - - List _buildProgressChildren() => - [_buildProgressStatusWrapper(), horizontalSpaceSmall, _buildProgress()]; - - Widget _buildProgressStatusWrapper() => Expanded( - child: _buildProgressStatus(), - ); - - Widget _buildProgressStatus() => const CustomLinearProgressIndicator( - progress: 0.75, - activeColor: kcPrimaryColor, - backgroundColor: kcVeryLightGrey); - - Widget _buildProgress() => const Text( - '2/3', - style: TextStyle(color: kcDarkGrey), - ); - - Widget _buildActionButtonWrapper( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - SizedBox( - height: 40, - child: _buildActionButtons(context: context, viewModel: viewModel), - ); - - Widget _buildActionButtons( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - Row( - children: [ - _buildLessonButtonWrapper(viewModel), - horizontalSpaceSmall, - _buildPracticeButtonWrapper(context: context, viewModel: viewModel) - ], - ); - - Widget _buildLessonButtonWrapper(LearnSubmoduleViewModel viewModel) => - Expanded( - child: _buildLessonButton(viewModel), - ); - - Widget _buildLessonButton(LearnSubmoduleViewModel viewModel) => - CustomElevatedButton( - height: 15, - borderRadius: 12, - onTap: onLessonTap, - text: 'View Module', - foregroundColor: kcWhite, - backgroundColor: kcPrimaryColor, - // onTap: () async => await viewModel.navigateToLearnLesson( - // title: title, - // topics: topics, - // subtitle: subtitle, - // practices: practices, - // description: description), - ); - - Widget _buildPracticeButtonWrapper( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - Expanded( - child: _buildPracticeButton(context: context, viewModel: viewModel), - ); - - Widget _buildPracticeButton( - {required BuildContext context, - required LearnSubmoduleViewModel viewModel}) => - CustomElevatedButton( - height: 15, - borderRadius: 12, - onTap: onPracticeTap, - text: 'View Practices', - backgroundColor: kcWhite, - borderColor: kcPrimaryColor, - foregroundColor: kcPrimaryColor, - // onTap: () async => await viewModel.navigateToLearnPractice(practices), - ); - - Widget _buildSheet(LearnSubmoduleViewModel viewModel) => FinishPracticeSheet( - onTap: viewModel.pop, - ); - - // Widget _buildContainerShaderState() => status == ProgressStatuses.pending - // ? _buildContainerShaderWrapper() - // : Container(); - - Widget _buildContainerShaderWrapper() => Positioned.fill( - child: _buildContainerShader(), - ); - - Widget _buildContainerShader() => Container( - decoration: BoxDecoration( - color: kcWhite.withOpacity(0.5), - borderRadius: BorderRadius.circular(5), - ), - ); -} diff --git a/lib/ui/widgets/learn_tile.dart b/lib/ui/widgets/learn_tile.dart deleted file mode 100644 index 517d363..0000000 --- a/lib/ui/widgets/learn_tile.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:stacked/stacked.dart'; -import 'package:yimaru_app/models/course.dart'; -import 'package:yimaru_app/ui/common/ui_helpers.dart'; -import 'package:yimaru_app/ui/views/learn/learn_viewmodel.dart'; - -import '../common/app_colors.dart'; -import 'custom_elevated_button.dart'; - -class LearnTile extends ViewModelWidget { - final Course course; - final GestureTapCallback? onTap; - - const LearnTile({ - super.key, - this.onTap, - required this.course, - }); - - @override - Widget build(BuildContext context, LearnViewModel viewModel) => - _buildExpansionTileCard(viewModel); - - Widget _buildExpansionTileCard(LearnViewModel viewModel) => Container( - margin: const EdgeInsets.only(bottom: 15), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - border: Border.all(color: kcPrimaryColor.withOpacity(0.2) - // color: status == ProgressStatuses.started - // ? kcPrimaryColor.withOpacity(0.2) - // : kcVeryLightGrey, - ), - ), - child: _buildExpansionTile(viewModel), - ); - - Widget _buildExpansionTile(LearnViewModel viewModel) => ExpansionTile( - enabled: true, - textColor: kcDarkGrey, - showTrailingIcon: true, - title: _buildTitleRow(), - initiallyExpanded: false, - subtitle: _buildContent(), - collapsedIconColor: kcDarkGrey, - collapsedTextColor: kcDarkGrey, - shape: Border.all(color: kcTransparent), - expandedAlignment: Alignment.centerLeft, - backgroundColor: kcPrimaryColor.withOpacity(0.1), - controlAffinity: ListTileControlAffinity.trailing, - childrenPadding: const EdgeInsets.only(bottom: 15), - expandedCrossAxisAlignment: CrossAxisAlignment.start, - tilePadding: const EdgeInsets.symmetric(horizontal: 15), - collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1), - // enabled: status != ProgressStatuses.pending ? true : false, - // status != ProgressStatuses.pending - // ? kcPrimaryColor.withOpacity(0.1) - // : kcBackgroundColor, - // collapsedBackgroundColor: status != ProgressStatuses.pending - // ? kcPrimaryColor.withOpacity(0.1) - // : kcBackgroundColor, - // showTrailingIcon: status != ProgressStatuses.pending ? true : false, - // initiallyExpanded: status == ProgressStatuses.started ? true : false, - children: _buildExpansionTileChildren(viewModel), - ); - - List _buildExpansionTileChildren(LearnViewModel viewModel) => [ - _buildDivider(), - verticalSpaceTiny, - _buildActionButtonWrapper(viewModel) - ]; - - Widget _buildTitleRow() => Row( - mainAxisSize: MainAxisSize.min, - children: _buildTitleChildren(), - ); - - List _buildTitleChildren() => [ - _buildTitle(), - // if (status != ProgressStatuses.pending) horizontalSpaceSmall, - // if (status != ProgressStatuses.pending) _buildProgressStatus() - ]; - - Widget _buildTitle() => Text( - course.title ?? '', - style: const TextStyle( - fontSize: 16, - color: kcPrimaryColor, - fontWeight: FontWeight.w600, - ), - ); - - // Widget _buildProgressStatus() => ProgressStatus( - // status: status.name.substring(0, 1).toUpperCase() + - // status.name.substring(1, status.name.length), - // color: kcPrimaryColor, - // ); - - Widget _buildContent() => Text( - course.description ?? '', - style: style14DG400, - ); - - Widget _buildDivider() => const Divider(color: kcVeryLightGrey); - - Widget _buildActionButtonWrapper(LearnViewModel viewModel) => Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildActionButton(viewModel), - ); - - Widget _buildActionButton(LearnViewModel viewModel) => CustomElevatedButton( - height: 15, - onTap: onTap, - borderRadius: 12, - text: 'Start Course', - foregroundColor: kcWhite, - backgroundColor: kcPrimaryColor, - // text: status == ProgressStatuses.completed - // ? 'Review Course' - // : status == ProgressStatuses.pending - // ? 'Start Learning' - // : 'Continue Learning', - ); -} diff --git a/lib/ui/widgets/overall_learn_progress.dart b/lib/ui/widgets/overall_learn_progress.dart index 8049bef..8a88082 100644 --- a/lib/ui/widgets/overall_learn_progress.dart +++ b/lib/ui/widgets/overall_learn_progress.dart @@ -4,16 +4,20 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart'; import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart'; class OverallLearnProgress extends StatelessWidget { - final Color color; - const OverallLearnProgress({super.key, required this.color}); + final Color backgroundColor; + final Color indicatorBackgroundColor; + const OverallLearnProgress( + {super.key, + required this.backgroundColor, + required this.indicatorBackgroundColor}); @override Widget build(BuildContext context) => _buildContainer(); Widget _buildContainer() => Container( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25), + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 20), decoration: BoxDecoration( - color: color, + color: backgroundColor, borderRadius: BorderRadius.circular(4), ), child: _buildProgressSection(), @@ -51,10 +55,10 @@ class OverallLearnProgress extends StatelessWidget { style: style14P400, ); - Widget _buildProgressIndicator() => const CustomLinearProgressIndicator( + Widget _buildProgressIndicator() => CustomLinearProgressIndicator( progress: 0.0, activeColor: kcPrimaryColor, - backgroundColor: kcVeryLightGrey, + backgroundColor: indicatorBackgroundColor, ); Widget _buildSubtitle() => const Text( diff --git a/lib/ui/widgets/progress_status.dart b/lib/ui/widgets/progress_status.dart index 76ef5a8..b6650eb 100644 --- a/lib/ui/widgets/progress_status.dart +++ b/lib/ui/widgets/progress_status.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:yimaru_app/ui/common/ui_helpers.dart'; class ProgressStatus extends StatelessWidget { final Color color; @@ -20,10 +21,6 @@ class ProgressStatus extends StatelessWidget { Widget _buildLabel() => Text( status, - style: TextStyle( - color: color, - fontSize: 12, - fontWeight: FontWeight.w600, - ), + style: style12RP600.copyWith(color: color), ); } diff --git a/lib/ui/widgets/selectable_course_practice_question.dart b/lib/ui/widgets/selectable_course_practice_question.dart index 567eba7..2775ed9 100644 --- a/lib/ui/widgets/selectable_course_practice_question.dart +++ b/lib/ui/widgets/selectable_course_practice_question.dart @@ -106,7 +106,7 @@ class SelectableCoursePracticeQuestion index + 1 < viewModel.coursePracticeQuestions.length ? index + 1 : index] - .questionId ?? + .id ?? 0) : null, ); diff --git a/pubspec.lock b/pubspec.lock index eb73ab3..8b2e1dd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + sha256: c209688d9f5a5f26b2fb47a188131a6fb9e876ae9e47af3737c0b4f58a93470d url: "https://pub.dev" source: hosted - version: "67.0.0" + version: "91.0.0" _flutterfire_internals: dependency: transitive description: @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: analyzer - sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + sha256: f51c8499b35f9b26820cfe914828a6a98a94efd5cc78b37bb7d03debae3a1d08 url: "https://pub.dev" source: hosted - version: "6.4.1" + version: "8.4.1" ansicolor: dependency: transitive description: @@ -149,18 +149,18 @@ packages: dependency: transitive description: name: build - sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" + sha256: aadd943f4f8cc946882c954c187e6115a84c98c81ad1d9c6cbf0895a8c85da9c url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "4.0.5" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4070d2a59f8eec34c97c86ceb44403834899075f66e8a9d59706f8e7834f6f71" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.3.0" build_daemon: dependency: transitive description: @@ -169,30 +169,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.1" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" - url: "https://pub.dev" - source: hosted - version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" + sha256: "4425a87d87d0d1303540f867994303f5b141ad2f6ecac7ac2cf8851f41c0cef1" url: "https://pub.dev" source: hosted - version: "2.4.13" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 - url: "https://pub.dev" - source: hosted - version: "7.3.2" + version: "2.14.0" built_collection: dependency: transitive description: @@ -357,10 +341,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" + sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "3.1.3" dbus: dependency: transitive description: @@ -772,18 +756,10 @@ packages: dependency: transitive description: name: freezed_annotation - sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8" url: "https://pub.dev" source: hosted - version: "2.4.4" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" + version: "3.1.0" get: dependency: transitive description: @@ -1032,14 +1008,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.5" - js: - dependency: transitive - description: - name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" - url: "https://pub.dev" - source: hosted - version: "0.7.2" json_annotation: dependency: "direct main" description: @@ -1052,10 +1020,10 @@ packages: dependency: "direct main" description: name: json_serializable - sha256: ea1432d167339ea9b5bb153f0571d0039607a873d6e04e0117af043f14a1fd4b + sha256: c5b2ee75210a0f263c6c7b9eeea80553dbae96ea1bf57f02484e806a3ffdffa3 url: "https://pub.dev" source: hosted - version: "6.8.0" + version: "6.11.2" leak_tracker: dependency: transitive description: @@ -1100,10 +1068,10 @@ packages: dependency: transitive description: name: logger - sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" + sha256: "25aee487596a6257655a1e091ec2ae66bc30e7af663592cc3a27e6591e05035c" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "2.7.0" logging: dependency: transitive description: @@ -1148,10 +1116,10 @@ packages: dependency: "direct dev" description: name: mockito - sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" + sha256: eff30d002f0c8bf073b6f929df4483b543133fcafce056870163587b03f1d422 url: "https://pub.dev" source: hosted - version: "5.4.4" + version: "5.6.4" native_toolchain_c: dependency: transitive description: @@ -1529,18 +1497,18 @@ packages: dependency: transitive description: name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + sha256: "732792cfd197d2161a65bb029606a46e0a18ff30ef9e141a7a82172b05ea8ecd" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "4.2.2" source_helper: dependency: transitive description: name: source_helper - sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c" + sha256: "6a3c6cc82073a8797f8c4dc4572146114a39652851c157db37e964d9c7038723" url: "https://pub.dev" source: hosted - version: "1.3.5" + version: "1.3.8" source_span: dependency: transitive description: @@ -1609,10 +1577,10 @@ packages: dependency: "direct dev" description: name: stacked_generator - sha256: eaa6447e3fd4d4010b746629b5518364d7fa7f6453ffb6416ad449fd352d1181 + sha256: "251344e41a090226aeaca5d174882a7a6e4ff834feed6c9520ebee78850164a6" url: "https://pub.dev" source: hosted - version: "1.6.1" + version: "1.6.2" stacked_services: dependency: "direct main" description: @@ -1693,14 +1661,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.10.1" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" toastification: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 1ee24a5..1866157 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,8 @@ name: yimaru_app -description: A new Flutter project. +version: 0.1.4+6 publish_to: 'none' -version: 0.1.3+5 +description: A new Flutter project. + environment: sdk: '>=3.0.3 <4.0.0' diff --git a/test/helpers/test_helpers.dart b/test/helpers/test_helpers.dart index e2ba5ab..7b16b45 100644 --- a/test/helpers/test_helpers.dart +++ b/test/helpers/test_helpers.dart @@ -16,6 +16,7 @@ import 'package:yimaru_app/services/smart_auth_service.dart'; import 'package:yimaru_app/services/course_service.dart'; import 'package:yimaru_app/services/audio_player_service.dart'; import 'package:yimaru_app/services/voice_recorder_service.dart'; +import 'package:yimaru_app/services/in_app_update_service.dart'; // @stacked-import import 'test_helpers.mocks.dart'; @@ -42,6 +43,7 @@ import 'test_helpers.mocks.dart'; MockSpec(onMissingStub: OnMissingStub.returnDefault), MockSpec(onMissingStub: OnMissingStub.returnDefault), MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), // @stacked-mock-spec ], ) @@ -63,6 +65,7 @@ void registerServices() { getAndRegisterCourseService(); getAndRegisterAudioPlayerService(); getAndRegisterVoiceRecorderService(); + getAndRegisterInAppUpdateService(); // @stacked-mock-register } @@ -217,6 +220,13 @@ MockVoiceRecorderService getAndRegisterVoiceRecorderService() { locator.registerSingleton(service); return service; } + +MockInAppUpdateService getAndRegisterInAppUpdateService() { + _removeRegistrationIfExists(); + final service = MockInAppUpdateService(); + locator.registerSingleton(service); + return service; +} // @stacked-mock-create void _removeRegistrationIfExists() { diff --git a/test/helpers/test_helpers.mocks.dart b/test/helpers/test_helpers.mocks.dart index 33cdc91..de8f496 100644 --- a/test/helpers/test_helpers.mocks.dart +++ b/test/helpers/test_helpers.mocks.dart @@ -1,4 +1,4 @@ -// Mocks generated by Mockito 5.4.4 from annotations +// Mocks generated by Mockito 5.4.6 from annotations // in yimaru_app/test/helpers/test_helpers.dart. // Do not manually edit this file. @@ -8,42 +8,48 @@ import 'dart:ui' as _i10; import 'package:audioplayers/audioplayers.dart' as _i4; import 'package:dio/dio.dart' as _i2; -import 'package:firebase_messaging/firebase_messaging.dart' as _i34; +import 'package:firebase_messaging/firebase_messaging.dart' as _i39; import 'package:flutter/material.dart' as _i8; import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/src/dummies.dart' as _i7; -import 'package:permission_handler/permission_handler.dart' as _i29; +import 'package:permission_handler/permission_handler.dart' as _i34; import 'package:stacked_services/stacked_services.dart' as _i6; import 'package:waveform_recorder/waveform_recorder.dart' as _i5; -import 'package:yimaru_app/models/category.dart' as _i15; -import 'package:yimaru_app/models/course.dart' as _i21; -import 'package:yimaru_app/models/course_detail.dart' as _i37; -import 'package:yimaru_app/models/course_lesson.dart' as _i18; -import 'package:yimaru_app/models/course_progress.dart' as _i17; -import 'package:yimaru_app/models/lesson.dart' as _i25; -import 'package:yimaru_app/models/level.dart' as _i22; -import 'package:yimaru_app/models/module.dart' as _i23; -import 'package:yimaru_app/models/practice.dart' as _i19; -import 'package:yimaru_app/models/practice_question.dart' as _i20; +import 'package:yimaru_app/models/category.dart' as _i21; +import 'package:yimaru_app/models/course.dart' as _i26; +import 'package:yimaru_app/models/course_detail.dart' as _i42; +import 'package:yimaru_app/models/course_lesson.dart' as _i24; +import 'package:yimaru_app/models/course_progress.dart' as _i23; +import 'package:yimaru_app/models/learn_course.dart' as _i16; +import 'package:yimaru_app/models/learn_lesson.dart' as _i19; +import 'package:yimaru_app/models/learn_module.dart' as _i18; +import 'package:yimaru_app/models/learn_practice.dart' as _i17; +import 'package:yimaru_app/models/learn_program.dart' as _i15; +import 'package:yimaru_app/models/learn_question.dart' as _i20; +import 'package:yimaru_app/models/lesson.dart' as _i30; +import 'package:yimaru_app/models/level.dart' as _i27; +import 'package:yimaru_app/models/module.dart' as _i28; +import 'package:yimaru_app/models/practice.dart' as _i25; import 'package:yimaru_app/models/question.dart' as _i14; -import 'package:yimaru_app/models/subcategory.dart' as _i16; -import 'package:yimaru_app/models/submodule.dart' as _i24; +import 'package:yimaru_app/models/subcategory.dart' as _i22; +import 'package:yimaru_app/models/submodule.dart' as _i29; import 'package:yimaru_app/models/user.dart' as _i12; import 'package:yimaru_app/services/api_service.dart' as _i13; -import 'package:yimaru_app/services/audio_player_service.dart' as _i38; +import 'package:yimaru_app/services/audio_player_service.dart' as _i43; import 'package:yimaru_app/services/authentication_service.dart' as _i11; -import 'package:yimaru_app/services/course_service.dart' as _i36; -import 'package:yimaru_app/services/dio_service.dart' as _i26; -import 'package:yimaru_app/services/google_auth_service.dart' as _i31; -import 'package:yimaru_app/services/image_downloader_service.dart' as _i32; -import 'package:yimaru_app/services/image_picker_service.dart' as _i30; -import 'package:yimaru_app/services/notification_service.dart' as _i33; -import 'package:yimaru_app/services/permission_handler_service.dart' as _i28; +import 'package:yimaru_app/services/course_service.dart' as _i41; +import 'package:yimaru_app/services/dio_service.dart' as _i31; +import 'package:yimaru_app/services/google_auth_service.dart' as _i36; +import 'package:yimaru_app/services/image_downloader_service.dart' as _i37; +import 'package:yimaru_app/services/image_picker_service.dart' as _i35; +import 'package:yimaru_app/services/in_app_update_service.dart' as _i46; +import 'package:yimaru_app/services/notification_service.dart' as _i38; +import 'package:yimaru_app/services/permission_handler_service.dart' as _i33; import 'package:yimaru_app/services/secure_storage_service.dart' as _i3; -import 'package:yimaru_app/services/smart_auth_service.dart' as _i35; -import 'package:yimaru_app/services/status_checker_service.dart' as _i27; -import 'package:yimaru_app/services/voice_recorder_service.dart' as _i39; -import 'package:yimaru_app/ui/common/enmus.dart' as _i40; +import 'package:yimaru_app/services/smart_auth_service.dart' as _i40; +import 'package:yimaru_app/services/status_checker_service.dart' as _i32; +import 'package:yimaru_app/services/voice_recorder_service.dart' as _i44; +import 'package:yimaru_app/ui/common/enmus.dart' as _i45; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -53,10 +59,12 @@ import 'package:yimaru_app/ui/common/enmus.dart' as _i40; // ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: must_be_immutable // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis // ignore_for_file: camel_case_types // ignore_for_file: subtype_of_sealed_class +// ignore_for_file: invalid_use_of_internal_member class _FakeDio_0 extends _i1.SmartFake implements _i2.Dio { _FakeDio_0( @@ -171,7 +179,7 @@ class MockNavigationService extends _i1.Mock implements _i6.NavigationService { _i9.Future? navigateWithTransition( _i8.Widget? page, { bool? opaque, - String? transition = r'', + String? transition = '', Duration? duration, bool? popGesture, int? id, @@ -207,7 +215,7 @@ class MockNavigationService extends _i1.Mock implements _i6.NavigationService { _i9.Future? replaceWithTransition( _i8.Widget? page, { bool? opaque, - String? transition = r'', + String? transition = '', Duration? duration, bool? popGesture, int? id, @@ -480,7 +488,7 @@ class MockBottomSheetService extends _i1.Mock _i9.Future<_i6.SheetResponse?> showBottomSheet({ required String? title, String? description, - String? confirmButtonTitle = r'Ok', + String? confirmButtonTitle = 'Ok', String? cancelButtonTitle, bool? enableDrag = true, bool? barrierDismissible = true, @@ -533,7 +541,7 @@ class MockBottomSheetService extends _i1.Mock double? elevation = 1.0, bool? barrierDismissible = true, bool? isScrollControlled = false, - String? barrierLabel = r'', + String? barrierLabel = '', dynamic customData, R? data, bool? enableDrag = true, @@ -630,7 +638,7 @@ class MockDialogService extends _i1.Mock implements _i6.DialogService { String? description, String? cancelTitle, _i10.Color? cancelTitleColor, - String? buttonTitle = r'Ok', + String? buttonTitle = 'Ok', _i10.Color? buttonTitleColor, bool? barrierDismissible = false, _i8.RouteSettings? routeSettings, @@ -675,7 +683,7 @@ class MockDialogService extends _i1.Mock implements _i6.DialogService { bool? takesInput = false, _i10.Color? barrierColor = const _i10.Color(2315255808), bool? barrierDismissible = false, - String? barrierLabel = r'', + String? barrierLabel = '', bool? useSafeArea = true, _i8.RouteSettings? routeSettings, _i8.GlobalKey<_i8.NavigatorState>? navigatorKey, @@ -719,9 +727,9 @@ class MockDialogService extends _i1.Mock implements _i6.DialogService { _i9.Future<_i6.DialogResponse?> showConfirmationDialog({ String? title, String? description, - String? cancelTitle = r'Cancel', + String? cancelTitle = 'Cancel', _i10.Color? cancelTitleColor, - String? confirmationTitle = r'Ok', + String? confirmationTitle = 'Ok', _i10.Color? confirmationTitleColor, bool? barrierDismissible = false, _i8.RouteSettings? routeSettings, @@ -1128,54 +1136,157 @@ class MockApiService extends _i1.Mock implements _i13.ApiService { ) as _i9.Future>); @override - _i9.Future> getCategories() => (super.noSuchMethod( + _i9.Future> getLearnPrograms() => (super.noSuchMethod( + Invocation.method( + #getLearnPrograms, + [], + ), + returnValue: + _i9.Future>.value(<_i15.LearnProgram>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i15.LearnProgram>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLearnCourse(int? id) => + (super.noSuchMethod( + Invocation.method( + #getLearnCourse, + [id], + ), + returnValue: + _i9.Future>.value(<_i16.LearnCourse>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i16.LearnCourse>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLearnCoursePractices(int? id) => + (super.noSuchMethod( + Invocation.method( + #getLearnCoursePractices, + [id], + ), + returnValue: + _i9.Future>.value(<_i17.LearnPractice>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i17.LearnPractice>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLearnModules(int? id) => + (super.noSuchMethod( + Invocation.method( + #getLearnModules, + [id], + ), + returnValue: + _i9.Future>.value(<_i18.LearnModule>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i18.LearnModule>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLearnModulePractices(int? id) => + (super.noSuchMethod( + Invocation.method( + #getLearnModulePractices, + [id], + ), + returnValue: + _i9.Future>.value(<_i17.LearnPractice>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i17.LearnPractice>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLearnLessons(int? id) => + (super.noSuchMethod( + Invocation.method( + #getLearnLessons, + [id], + ), + returnValue: + _i9.Future>.value(<_i19.LearnLesson>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i19.LearnLesson>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLearnLessonPractices(int? id) => + (super.noSuchMethod( + Invocation.method( + #getLearnLessonPractices, + [id], + ), + returnValue: + _i9.Future>.value(<_i17.LearnPractice>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i17.LearnPractice>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLearnQuestions(int? id) => + (super.noSuchMethod( + Invocation.method( + #getLearnQuestions, + [id], + ), + returnValue: + _i9.Future>.value(<_i20.LearnQuestion>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i20.LearnQuestion>[]), + ) as _i9.Future>); + + @override + _i9.Future> getCategories() => (super.noSuchMethod( Invocation.method( #getCategories, [], ), - returnValue: _i9.Future>.value(<_i15.Category>[]), + returnValue: _i9.Future>.value(<_i21.Category>[]), returnValueForMissingStub: - _i9.Future>.value(<_i15.Category>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i21.Category>[]), + ) as _i9.Future>); @override - _i9.Future> getSubcategories(int? id) => + _i9.Future> getSubcategories(int? id) => (super.noSuchMethod( Invocation.method( #getSubcategories, [id], ), returnValue: - _i9.Future>.value(<_i16.Subcategory>[]), + _i9.Future>.value(<_i22.Subcategory>[]), returnValueForMissingStub: - _i9.Future>.value(<_i16.Subcategory>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i22.Subcategory>[]), + ) as _i9.Future>); @override - _i9.Future> getCourseProgress(int? id) => + _i9.Future> getCourseProgress(int? id) => (super.noSuchMethod( Invocation.method( #getCourseProgress, [id], ), - returnValue: _i9.Future>.value( - <_i17.CourseProgress>[]), - returnValueForMissingStub: _i9.Future>.value( - <_i17.CourseProgress>[]), - ) as _i9.Future>); + returnValue: _i9.Future>.value( + <_i23.CourseProgress>[]), + returnValueForMissingStub: _i9.Future>.value( + <_i23.CourseProgress>[]), + ) as _i9.Future>); @override - _i9.Future> getCourseLessons(int? id) => + _i9.Future> getCourseLessons(int? id) => (super.noSuchMethod( Invocation.method( #getCourseLessons, [id], ), returnValue: - _i9.Future>.value(<_i18.CourseLesson>[]), + _i9.Future>.value(<_i24.CourseLesson>[]), returnValueForMissingStub: - _i9.Future>.value(<_i18.CourseLesson>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i24.CourseLesson>[]), + ) as _i9.Future>); @override _i9.Future> completeLesson(int? id) => @@ -1191,30 +1302,28 @@ class MockApiService extends _i1.Mock implements _i13.ApiService { ) as _i9.Future>); @override - _i9.Future> getCoursePractices(int? id) => + _i9.Future> getCoursePractices(int? id) => (super.noSuchMethod( Invocation.method( #getCoursePractices, [id], ), - returnValue: _i9.Future>.value(<_i19.Practice>[]), + returnValue: _i9.Future>.value(<_i25.Practice>[]), returnValueForMissingStub: - _i9.Future>.value(<_i19.Practice>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i25.Practice>[]), + ) as _i9.Future>); @override - _i9.Future> getCoursePracticeQuestions(int? id) => + _i9.Future> getCoursePracticeQuestions(int? id) => (super.noSuchMethod( Invocation.method( #getCoursePracticeQuestions, [id], ), - returnValue: _i9.Future>.value( - <_i20.PracticeQuestion>[]), + returnValue: _i9.Future>.value(<_i14.Question>[]), returnValueForMissingStub: - _i9.Future>.value( - <_i20.PracticeQuestion>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i14.Question>[]), + ) as _i9.Future>); @override _i9.Future<_i14.Question?> getCoursePracticeQuestion(int? id) => @@ -1228,73 +1337,95 @@ class MockApiService extends _i1.Mock implements _i13.ApiService { ) as _i9.Future<_i14.Question?>); @override - _i9.Future> getLearnSubcategories() => + _i9.Future> getLearnSubcategories() => (super.noSuchMethod( Invocation.method( #getLearnSubcategories, [], ), returnValue: - _i9.Future>.value(<_i16.Subcategory>[]), + _i9.Future>.value(<_i22.Subcategory>[]), returnValueForMissingStub: - _i9.Future>.value(<_i16.Subcategory>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i22.Subcategory>[]), + ) as _i9.Future>); @override - _i9.Future> getCourses(int? id) => (super.noSuchMethod( + _i9.Future> getCourses(int? id) => (super.noSuchMethod( Invocation.method( #getCourses, [id], ), - returnValue: _i9.Future>.value(<_i21.Course>[]), + returnValue: _i9.Future>.value(<_i26.Course>[]), returnValueForMissingStub: - _i9.Future>.value(<_i21.Course>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i26.Course>[]), + ) as _i9.Future>); @override - _i9.Future> getLevels(int? id) => (super.noSuchMethod( + _i9.Future> getLevels(int? id) => (super.noSuchMethod( Invocation.method( #getLevels, [id], ), - returnValue: _i9.Future>.value(<_i22.Level>[]), + returnValue: _i9.Future>.value(<_i27.Level>[]), returnValueForMissingStub: - _i9.Future>.value(<_i22.Level>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i27.Level>[]), + ) as _i9.Future>); @override - _i9.Future> getModules(int? id) => (super.noSuchMethod( + _i9.Future> getModules(int? id) => (super.noSuchMethod( Invocation.method( #getModules, [id], ), - returnValue: _i9.Future>.value(<_i23.Module>[]), + returnValue: _i9.Future>.value(<_i28.Module>[]), returnValueForMissingStub: - _i9.Future>.value(<_i23.Module>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i28.Module>[]), + ) as _i9.Future>); @override - _i9.Future> getSubmodules(int? id) => + _i9.Future> getSubmodules(int? id) => (super.noSuchMethod( Invocation.method( #getSubmodules, [id], ), - returnValue: _i9.Future>.value(<_i24.Submodule>[]), + returnValue: _i9.Future>.value(<_i29.Submodule>[]), returnValueForMissingStub: - _i9.Future>.value(<_i24.Submodule>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i29.Submodule>[]), + ) as _i9.Future>); @override - _i9.Future> getLessons(int? id) => (super.noSuchMethod( + _i9.Future> getLessons(int? id) => (super.noSuchMethod( Invocation.method( #getLessons, [id], ), - returnValue: _i9.Future>.value(<_i25.Lesson>[]), + returnValue: _i9.Future>.value(<_i30.Lesson>[]), returnValueForMissingStub: - _i9.Future>.value(<_i25.Lesson>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i30.Lesson>[]), + ) as _i9.Future>); + + @override + _i9.Future> getPractices(int? id) => (super.noSuchMethod( + Invocation.method( + #getPractices, + [id], + ), + returnValue: _i9.Future>.value(<_i25.Practice>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i25.Practice>[]), + ) as _i9.Future>); + + @override + _i9.Future> getQuestions(int? id) => (super.noSuchMethod( + Invocation.method( + #getQuestions, + [id], + ), + returnValue: _i9.Future>.value(<_i14.Question>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i14.Question>[]), + ) as _i9.Future>); } /// A class which mocks [SecureStorageService]. @@ -1397,7 +1528,7 @@ class MockSecureStorageService extends _i1.Mock /// A class which mocks [DioService]. /// /// See the documentation for Mockito's code generation for more information. -class MockDioService extends _i1.Mock implements _i26.DioService { +class MockDioService extends _i1.Mock implements _i31.DioService { @override _i2.Dio get dio => (super.noSuchMethod( Invocation.getter(#dio), @@ -1416,7 +1547,7 @@ class MockDioService extends _i1.Mock implements _i26.DioService { /// /// See the documentation for Mockito's code generation for more information. class MockStatusCheckerService extends _i1.Mock - implements _i27.StatusCheckerService { + implements _i32.StatusCheckerService { @override _i3.SecureStorageService get storage => (super.noSuchMethod( Invocation.getter(#storage), @@ -1437,16 +1568,6 @@ class MockStatusCheckerService extends _i1.Mock returnValueForMissingStub: false, ) as bool); - @override - _i9.Future getBatteryLevel() => (super.noSuchMethod( - Invocation.method( - #getBatteryLevel, - [], - ), - returnValue: _i9.Future.value(0), - returnValueForMissingStub: _i9.Future.value(0), - ) as _i9.Future); - @override _i9.Future checkConnection() => (super.noSuchMethod( Invocation.method( @@ -1456,66 +1577,46 @@ class MockStatusCheckerService extends _i1.Mock returnValue: _i9.Future.value(false), returnValueForMissingStub: _i9.Future.value(false), ) as _i9.Future); - - @override - _i9.Future getAvailableStorage() => (super.noSuchMethod( - Invocation.method( - #getAvailableStorage, - [], - ), - returnValue: _i9.Future.value(0), - returnValueForMissingStub: _i9.Future.value(0), - ) as _i9.Future); - - @override - _i9.Future checkAndUpdate() => (super.noSuchMethod( - Invocation.method( - #checkAndUpdate, - [], - ), - returnValue: _i9.Future.value(), - returnValueForMissingStub: _i9.Future.value(), - ) as _i9.Future); } /// A class which mocks [PermissionHandlerService]. /// /// See the documentation for Mockito's code generation for more information. class MockPermissionHandlerService extends _i1.Mock - implements _i28.PermissionHandlerService { + implements _i33.PermissionHandlerService { @override - _i9.Future<_i29.PermissionStatus> requestPermission( - _i29.Permission? requestedPermission) => + _i9.Future<_i34.PermissionStatus> requestPermission( + _i34.Permission? requestedPermission) => (super.noSuchMethod( Invocation.method( #requestPermission, [requestedPermission], ), - returnValue: _i9.Future<_i29.PermissionStatus>.value( - _i29.PermissionStatus.denied), - returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value( - _i29.PermissionStatus.denied), - ) as _i9.Future<_i29.PermissionStatus>); + returnValue: _i9.Future<_i34.PermissionStatus>.value( + _i34.PermissionStatus.denied), + returnValueForMissingStub: _i9.Future<_i34.PermissionStatus>.value( + _i34.PermissionStatus.denied), + ) as _i9.Future<_i34.PermissionStatus>); @override - _i9.Future<_i29.PermissionStatus> request(_i29.Permission? permission) => + _i9.Future<_i34.PermissionStatus> request(_i34.Permission? permission) => (super.noSuchMethod( Invocation.method( #request, [permission], ), - returnValue: _i9.Future<_i29.PermissionStatus>.value( - _i29.PermissionStatus.denied), - returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value( - _i29.PermissionStatus.denied), - ) as _i9.Future<_i29.PermissionStatus>); + returnValue: _i9.Future<_i34.PermissionStatus>.value( + _i34.PermissionStatus.denied), + returnValueForMissingStub: _i9.Future<_i34.PermissionStatus>.value( + _i34.PermissionStatus.denied), + ) as _i9.Future<_i34.PermissionStatus>); } /// A class which mocks [ImagePickerService]. /// /// See the documentation for Mockito's code generation for more information. class MockImagePickerService extends _i1.Mock - implements _i30.ImagePickerService { + implements _i35.ImagePickerService { @override _i9.Future gallery() => (super.noSuchMethod( Invocation.method( @@ -1540,7 +1641,7 @@ class MockImagePickerService extends _i1.Mock /// A class which mocks [GoogleAuthService]. /// /// See the documentation for Mockito's code generation for more information. -class MockGoogleAuthService extends _i1.Mock implements _i31.GoogleAuthService { +class MockGoogleAuthService extends _i1.Mock implements _i36.GoogleAuthService { @override int get listenersCount => (super.noSuchMethod( Invocation.getter(#listenersCount), @@ -1610,7 +1711,7 @@ class MockGoogleAuthService extends _i1.Mock implements _i31.GoogleAuthService { /// /// See the documentation for Mockito's code generation for more information. class MockImageDownloaderService extends _i1.Mock - implements _i32.ImageDownloaderService { + implements _i37.ImageDownloaderService { @override _i9.Future downloader(String? networkImage) => (super.noSuchMethod( Invocation.method( @@ -1639,7 +1740,7 @@ class MockImageDownloaderService extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockNotificationService extends _i1.Mock - implements _i33.NotificationService { + implements _i38.NotificationService { @override _i9.Future initialize() => (super.noSuchMethod( Invocation.method( @@ -1661,7 +1762,7 @@ class MockNotificationService extends _i1.Mock ) as _i9.Future); @override - _i9.Future showNotification(_i34.RemoteMessage? message) => + _i9.Future showNotification(_i39.RemoteMessage? message) => (super.noSuchMethod( Invocation.method( #showNotification, @@ -1695,7 +1796,7 @@ class MockNotificationService extends _i1.Mock /// A class which mocks [SmartAuthService]. /// /// See the documentation for Mockito's code generation for more information. -class MockSmartAuthService extends _i1.Mock implements _i35.SmartAuthService { +class MockSmartAuthService extends _i1.Mock implements _i40.SmartAuthService { @override bool get listenForMultipleSms => (super.noSuchMethod( Invocation.getter(#listenForMultipleSms), @@ -1727,26 +1828,26 @@ class MockSmartAuthService extends _i1.Mock implements _i35.SmartAuthService { /// A class which mocks [CourseService]. /// /// See the documentation for Mockito's code generation for more information. -class MockCourseService extends _i1.Mock implements _i36.CourseService { +class MockCourseService extends _i1.Mock implements _i41.CourseService { @override - _i9.Future> getCoursesDetail(int? id) => + _i9.Future> getCoursesDetail(int? id) => (super.noSuchMethod( Invocation.method( #getCoursesDetail, [id], ), returnValue: - _i9.Future>.value(<_i37.CourseDetail>[]), + _i9.Future>.value(<_i42.CourseDetail>[]), returnValueForMissingStub: - _i9.Future>.value(<_i37.CourseDetail>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i42.CourseDetail>[]), + ) as _i9.Future>); } /// A class which mocks [AudioPlayerService]. /// /// See the documentation for Mockito's code generation for more information. class MockAudioPlayerService extends _i1.Mock - implements _i38.AudioPlayerService { + implements _i43.AudioPlayerService { @override _i4.AudioPlayer get player => (super.noSuchMethod( Invocation.getter(#player), @@ -1870,13 +1971,13 @@ class MockAudioPlayerService extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockVoiceRecorderService extends _i1.Mock - implements _i39.VoiceRecorderService { + implements _i44.VoiceRecorderService { @override - _i40.VoiceRecordingState get recordingState => (super.noSuchMethod( + _i45.VoiceRecordingState get recordingState => (super.noSuchMethod( Invocation.getter(#recordingState), - returnValue: _i40.VoiceRecordingState.pending, - returnValueForMissingStub: _i40.VoiceRecordingState.pending, - ) as _i40.VoiceRecordingState); + returnValue: _i45.VoiceRecordingState.pending, + returnValueForMissingStub: _i45.VoiceRecordingState.pending, + ) as _i45.VoiceRecordingState); @override _i5.WaveformRecorderController get waveController => (super.noSuchMethod( @@ -1965,3 +2066,39 @@ class MockVoiceRecorderService extends _i1.Mock returnValueForMissingStub: null, ); } + +/// A class which mocks [InAppUpdateService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockInAppUpdateService extends _i1.Mock + implements _i46.InAppUpdateService { + @override + _i9.Future getBatteryLevel() => (super.noSuchMethod( + Invocation.method( + #getBatteryLevel, + [], + ), + returnValue: _i9.Future.value(0), + returnValueForMissingStub: _i9.Future.value(0), + ) as _i9.Future); + + @override + _i9.Future getAvailableStorage() => (super.noSuchMethod( + Invocation.method( + #getAvailableStorage, + [], + ), + returnValue: _i9.Future.value(0), + returnValueForMissingStub: _i9.Future.value(0), + ) as _i9.Future); + + @override + _i9.Future checkForUpdate() => (super.noSuchMethod( + Invocation.method( + #checkForUpdate, + [], + ), + returnValue: _i9.Future.value(), + returnValueForMissingStub: _i9.Future.value(), + ) as _i9.Future); +} diff --git a/test/viewmodels/learn_viewmodel_test.dart b/test/services/in_app_update_service_test.dart similarity index 85% rename from test/viewmodels/learn_viewmodel_test.dart rename to test/services/in_app_update_service_test.dart index cf11c9c..73eec2a 100644 --- a/test/viewmodels/learn_viewmodel_test.dart +++ b/test/services/in_app_update_service_test.dart @@ -4,7 +4,7 @@ import 'package:yimaru_app/app/app.locator.dart'; import '../helpers/test_helpers.dart'; void main() { - group('LearnViewModel Tests -', () { + group('InAppUpdateServiceTest -', () { setUp(() => registerServices()); tearDown(() => locator.reset()); }); diff --git a/test/viewmodels/learn_level_viewmodel_test.dart b/test/viewmodels/learn_course_viewmodel_test.dart similarity index 83% rename from test/viewmodels/learn_level_viewmodel_test.dart rename to test/viewmodels/learn_course_viewmodel_test.dart index 5d97e54..a27b9dd 100644 --- a/test/viewmodels/learn_level_viewmodel_test.dart +++ b/test/viewmodels/learn_course_viewmodel_test.dart @@ -4,7 +4,7 @@ import 'package:yimaru_app/app/app.locator.dart'; import '../helpers/test_helpers.dart'; void main() { - group('LearnLevelViewModel Tests -', () { + group('LearnCourseViewModel Tests -', () { setUp(() => registerServices()); tearDown(() => locator.reset()); }); diff --git a/test/viewmodels/learn_submodule_viewmodel_test.dart b/test/viewmodels/learn_program_viewmodel_test.dart similarity index 83% rename from test/viewmodels/learn_submodule_viewmodel_test.dart rename to test/viewmodels/learn_program_viewmodel_test.dart index 1668467..e341a5f 100644 --- a/test/viewmodels/learn_submodule_viewmodel_test.dart +++ b/test/viewmodels/learn_program_viewmodel_test.dart @@ -4,7 +4,7 @@ import 'package:yimaru_app/app/app.locator.dart'; import '../helpers/test_helpers.dart'; void main() { - group('LearnSubmoduleViewModel Tests -', () { + group('LearnProgramViewModel Tests -', () { setUp(() => registerServices()); tearDown(() => locator.reset()); }); diff --git a/test/viewmodels/learn_subcategory_viewmodel_test.dart b/test/viewmodels/learn_subcategory_viewmodel_test.dart deleted file mode 100644 index 88f0f86..0000000 --- a/test/viewmodels/learn_subcategory_viewmodel_test.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:yimaru_app/app/app.locator.dart'; - -import '../helpers/test_helpers.dart'; - -void main() { - group('LearnSubcategoryViewModel Tests -', () { - setUp(() => registerServices()); - tearDown(() => locator.reset()); - }); -}