diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html index 1e24d19..84a82f1 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.dart b/lib/app/app.dart index 5897ed4..3834e90 100644 --- a/lib/app/app.dart +++ b/lib/app/app.dart @@ -52,6 +52,7 @@ 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'; // @stacked-import @StackedApp( @@ -92,6 +93,7 @@ import 'package:yimaru_app/ui/views/learn_subcategory/learn_subcategory_view.dar MaterialRoute(page: CourseView), MaterialRoute(page: CoursePracticeQuestionView), MaterialRoute(page: LearnSubcategoryView), + MaterialRoute(page: LearnSubmoduleView), // @stacked-route ], dependencies: [ diff --git a/lib/app/app.router.dart b/lib/app/app.router.dart index 93af0b9..feb59cd 100644 --- a/lib/app/app.router.dart +++ b/lib/app/app.router.dart @@ -5,15 +5,18 @@ // ************************************************************************** // ignore_for_file: no_leading_underscores_for_library_prefixes -import 'package:flutter/material.dart' as _i38; 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 _i44; -import 'package:yimaru_app/models/category.dart' as _i42; -import 'package:yimaru_app/models/course.dart' as _i40; -import 'package:yimaru_app/models/course_lesson.dart' as _i41; -import 'package:yimaru_app/models/level.dart' as _i39; -import 'package:yimaru_app/models/subcategory.dart' as _i43; +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:yimaru_app/ui/views/account_privacy/account_privacy_view.dart' as _i9; import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i22; @@ -53,6 +56,8 @@ 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; 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' @@ -143,6 +148,8 @@ class Routes { static const learnSubcategoryView = '/learn-subcategory-view'; + static const learnSubmoduleView = '/learn-submodule-view'; + static const all = { homeView, onboardingView, @@ -180,6 +187,7 @@ class Routes { courseView, coursePracticeQuestionView, learnSubcategoryView, + learnSubmoduleView, }; } @@ -329,17 +337,21 @@ class StackedRouter extends _i1.RouterBase { Routes.learnSubcategoryView, page: _i37.LearnSubcategoryView, ), + _i1.RouteDef( + Routes.learnSubmoduleView, + page: _i38.LearnSubmoduleView, + ), ]; final _pagesMap = { _i2.HomeView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i2.HomeView(), settings: data, ); }, _i3.OnboardingView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i3.OnboardingView(), settings: data, ); @@ -348,120 +360,120 @@ class StackedRouter extends _i1.RouterBase { final args = data.getArgs( orElse: () => const StartupViewArguments(), ); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i4.StartupView(key: args.key, label: args.label), settings: data, ); }, _i5.ProfileView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i5.ProfileView(), settings: data, ); }, _i6.ProfileDetailView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i6.ProfileDetailView(), settings: data, ); }, _i7.DownloadsView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i7.DownloadsView(), settings: data, ); }, _i8.ProgressView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i8.ProgressView(), settings: data, ); }, _i9.AccountPrivacyView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i9.AccountPrivacyView(), settings: data, ); }, _i10.SupportView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i10.SupportView(), settings: data, ); }, _i11.TelegramSupportView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i11.TelegramSupportView(), settings: data, ); }, _i12.CallSupportView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i12.CallSupportView(), settings: data, ); }, _i13.LanguageView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i13.LanguageView(), settings: data, ); }, _i14.PrivacyPolicyView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i14.PrivacyPolicyView(), settings: data, ); }, _i15.TermsAndConditionsView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i15.TermsAndConditionsView(), settings: data, ); }, _i16.RegisterView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i16.RegisterView(), settings: data, ); }, _i17.LoginView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i17.LoginView(), settings: data, ); }, _i18.LearnView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + 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 _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i19.LearnLevelView(key: args.key, id: args.id), settings: data, ); }, _i20.LearnModuleView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i20.LearnModuleView(key: args.key, level: args.level), settings: data, ); }, _i21.WelcomeView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i21.WelcomeView(), settings: data, ); }, _i22.AssessmentView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i22.AssessmentView(key: args.key, data: args.data), settings: data, @@ -469,37 +481,29 @@ class StackedRouter extends _i1.RouterBase { }, _i23.LearnLessonView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( - builder: (context) => _i23.LearnLessonView( - key: args.key, - title: args.title, - topics: args.topics, - subtitle: args.subtitle, - practices: args.practices, - description: args.description), + return _i39.MaterialPageRoute( + builder: (context) => + _i23.LearnLessonView(key: args.key, submodule: args.submodule), settings: data, ); }, _i24.ForgetPasswordView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i24.ForgetPasswordView(), settings: data, ); }, _i25.LearnLessonDetailView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( - builder: (context) => _i25.LearnLessonDetailView( - key: args.key, - title: args.title, - practices: args.practices, - description: args.description), + return _i39.MaterialPageRoute( + builder: (context) => + _i25.LearnLessonDetailView(key: args.key, lesson: args.lesson), settings: data, ); }, _i26.LearnPracticeView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i26.LearnPracticeView( key: args.key, title: args.title, @@ -511,7 +515,7 @@ class StackedRouter extends _i1.RouterBase { }, _i27.CoursePracticeView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i27.CoursePracticeView(key: args.key, id: args.id), settings: data, @@ -519,21 +523,21 @@ class StackedRouter extends _i1.RouterBase { }, _i28.CoursePaymentView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i28.CoursePaymentView(key: args.key, course: args.course), settings: data, ); }, _i29.CourseCategoryView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i29.CourseCategoryView(), settings: data, ); }, _i30.FailureView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i30.FailureView(key: args.key, label: args.label), settings: data, @@ -541,7 +545,7 @@ class StackedRouter extends _i1.RouterBase { }, _i31.CourseLessonView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i31.CourseLessonView(key: args.key, course: args.course), settings: data, @@ -549,21 +553,21 @@ class StackedRouter extends _i1.RouterBase { }, _i32.CourseLessonDetailView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i32.CourseLessonDetailView(key: args.key, lesson: args.lesson), settings: data, ); }, _i33.DuolingoView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i33.DuolingoView(), settings: data, ); }, _i34.CourseSubcategoryView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i34.CourseSubcategoryView(key: args.key, category: args.category), settings: data, @@ -571,7 +575,7 @@ class StackedRouter extends _i1.RouterBase { }, _i35.CourseView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i35.CourseView(key: args.key, subcategory: args.subcategory), settings: data, @@ -580,18 +584,26 @@ class StackedRouter extends _i1.RouterBase { _i36.CoursePracticeQuestionView: (data) { final args = data.getArgs(nullOk: false); - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => _i36.CoursePracticeQuestionView(key: args.key, id: args.id), settings: data, ); }, _i37.LearnSubcategoryView: (data) { - return _i38.MaterialPageRoute( + return _i39.MaterialPageRoute( builder: (context) => const _i37.LearnSubcategoryView(), settings: data, ); }, + _i38.LearnSubmoduleView: (data) { + final args = data.getArgs(nullOk: false); + return _i39.MaterialPageRoute( + builder: (context) => + _i38.LearnSubmoduleView(key: args.key, module: args.module), + settings: data, + ); + }, }; @override @@ -607,7 +619,7 @@ class StartupViewArguments { this.label = 'Loading', }); - final _i38.Key? key; + final _i39.Key? key; final String label; @@ -634,7 +646,7 @@ class LearnViewArguments { required this.id, }); - final _i38.Key? key; + final _i39.Key? key; final int id; @@ -661,7 +673,7 @@ class LearnLevelViewArguments { required this.id, }); - final _i38.Key? key; + final _i39.Key? key; final int id; @@ -688,9 +700,9 @@ class LearnModuleViewArguments { required this.level, }); - final _i38.Key? key; + final _i39.Key? key; - final _i39.Level level; + final _i40.Level level; @override String toString() { @@ -715,7 +727,7 @@ class AssessmentViewArguments { required this.data, }); - final _i38.Key? key; + final _i39.Key? key; final Map data; @@ -739,88 +751,54 @@ class AssessmentViewArguments { class LearnLessonViewArguments { const LearnLessonViewArguments({ this.key, - required this.title, - required this.topics, - required this.subtitle, - required this.practices, - required this.description, + required this.submodule, }); - final _i38.Key? key; + final _i39.Key? key; - final String title; - - final String topics; - - final String subtitle; - - final List> practices; - - final String description; + final _i41.Submodule submodule; @override String toString() { - return '{"key": "$key", "title": "$title", "topics": "$topics", "subtitle": "$subtitle", "practices": "$practices", "description": "$description"}'; + return '{"key": "$key", "submodule": "$submodule"}'; } @override bool operator ==(covariant LearnLessonViewArguments other) { if (identical(this, other)) return true; - return other.key == key && - other.title == title && - other.topics == topics && - other.subtitle == subtitle && - other.practices == practices && - other.description == description; + return other.key == key && other.submodule == submodule; } @override int get hashCode { - return key.hashCode ^ - title.hashCode ^ - topics.hashCode ^ - subtitle.hashCode ^ - practices.hashCode ^ - description.hashCode; + return key.hashCode ^ submodule.hashCode; } } class LearnLessonDetailViewArguments { const LearnLessonDetailViewArguments({ this.key, - required this.title, - required this.practices, - required this.description, + required this.lesson, }); - final _i38.Key? key; + final _i39.Key? key; - final String title; - - final List> practices; - - final String description; + final _i42.Lesson lesson; @override String toString() { - return '{"key": "$key", "title": "$title", "practices": "$practices", "description": "$description"}'; + return '{"key": "$key", "lesson": "$lesson"}'; } @override bool operator ==(covariant LearnLessonDetailViewArguments other) { if (identical(this, other)) return true; - return other.key == key && - other.title == title && - other.practices == practices && - other.description == description; + return other.key == key && other.lesson == lesson; } @override int get hashCode { - return key.hashCode ^ - title.hashCode ^ - practices.hashCode ^ - description.hashCode; + return key.hashCode ^ lesson.hashCode; } } @@ -833,7 +811,7 @@ class LearnPracticeViewArguments { required this.buttonLabel, }); - final _i38.Key? key; + final _i39.Key? key; final String title; @@ -874,7 +852,7 @@ class CoursePracticeViewArguments { required this.id, }); - final _i38.Key? key; + final _i39.Key? key; final int id; @@ -901,9 +879,9 @@ class CoursePaymentViewArguments { required this.course, }); - final _i38.Key? key; + final _i39.Key? key; - final _i40.Course course; + final _i43.Course course; @override String toString() { @@ -928,7 +906,7 @@ class FailureViewArguments { required this.label, }); - final _i38.Key? key; + final _i39.Key? key; final String label; @@ -955,9 +933,9 @@ class CourseLessonViewArguments { required this.course, }); - final _i38.Key? key; + final _i39.Key? key; - final _i40.Course course; + final _i43.Course course; @override String toString() { @@ -982,9 +960,9 @@ class CourseLessonDetailViewArguments { required this.lesson, }); - final _i38.Key? key; + final _i39.Key? key; - final _i41.CourseLesson lesson; + final _i44.CourseLesson lesson; @override String toString() { @@ -1009,9 +987,9 @@ class CourseSubcategoryViewArguments { required this.category, }); - final _i38.Key? key; + final _i39.Key? key; - final _i42.Category category; + final _i45.Category category; @override String toString() { @@ -1036,9 +1014,9 @@ class CourseViewArguments { required this.subcategory, }); - final _i38.Key? key; + final _i39.Key? key; - final _i43.Subcategory subcategory; + final _i46.Subcategory subcategory; @override String toString() { @@ -1063,7 +1041,7 @@ class CoursePracticeQuestionViewArguments { required this.id, }); - final _i38.Key? key; + final _i39.Key? key; final int id; @@ -1084,7 +1062,34 @@ class CoursePracticeQuestionViewArguments { } } -extension NavigatorStateExtension on _i44.NavigationService { +class LearnSubmoduleViewArguments { + const LearnSubmoduleViewArguments({ + this.key, + required this.module, + }); + + final _i39.Key? key; + + final _i47.Module module; + + @override + String toString() { + return '{"key": "$key", "module": "$module"}'; + } + + @override + bool operator ==(covariant LearnSubmoduleViewArguments other) { + if (identical(this, other)) return true; + return other.key == key && other.module == module; + } + + @override + int get hashCode { + return key.hashCode ^ module.hashCode; + } +} + +extension NavigatorStateExtension on _i48.NavigationService { Future navigateToHomeView([ int? routerId, bool preventDuplicates = true, @@ -1114,7 +1119,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToStartupView({ - _i38.Key? key, + _i39.Key? key, String label = 'Loading', int? routerId, bool preventDuplicates = true, @@ -1313,7 +1318,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToLearnView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1330,7 +1335,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToLearnLevelView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1347,8 +1352,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToLearnModuleView({ - _i38.Key? key, - required _i39.Level level, + _i39.Key? key, + required _i40.Level level, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1378,7 +1383,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToAssessmentView({ - _i38.Key? key, + _i39.Key? key, required Map data, int? routerId, bool preventDuplicates = true, @@ -1395,12 +1400,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToLearnLessonView({ - _i38.Key? key, - required String title, - required String topics, - required String subtitle, - required List> practices, - required String description, + _i39.Key? key, + required _i41.Submodule submodule, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1408,13 +1409,7 @@ extension NavigatorStateExtension on _i44.NavigationService { transition, }) async { return navigateTo(Routes.learnLessonView, - arguments: LearnLessonViewArguments( - key: key, - title: title, - topics: topics, - subtitle: subtitle, - practices: practices, - description: description), + arguments: LearnLessonViewArguments(key: key, submodule: submodule), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1436,10 +1431,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToLearnLessonDetailView({ - _i38.Key? key, - required String title, - required List> practices, - required String description, + _i39.Key? key, + required _i42.Lesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1447,11 +1440,7 @@ extension NavigatorStateExtension on _i44.NavigationService { transition, }) async { return navigateTo(Routes.learnLessonDetailView, - arguments: LearnLessonDetailViewArguments( - key: key, - title: title, - practices: practices, - description: description), + arguments: LearnLessonDetailViewArguments(key: key, lesson: lesson), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -1459,7 +1448,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToLearnPracticeView({ - _i38.Key? key, + _i39.Key? key, required String title, required String subtitle, required List> practices, @@ -1484,7 +1473,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToCoursePracticeView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1501,8 +1490,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToCoursePaymentView({ - _i38.Key? key, - required _i40.Course course, + _i39.Key? key, + required _i43.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1532,7 +1521,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToFailureView({ - _i38.Key? key, + _i39.Key? key, required String label, int? routerId, bool preventDuplicates = true, @@ -1549,8 +1538,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToCourseLessonView({ - _i38.Key? key, - required _i40.Course course, + _i39.Key? key, + required _i43.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1566,8 +1555,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToCourseLessonDetailView({ - _i38.Key? key, - required _i41.CourseLesson lesson, + _i39.Key? key, + required _i44.CourseLesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1597,8 +1586,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToCourseSubcategoryView({ - _i38.Key? key, - required _i42.Category category, + _i39.Key? key, + required _i45.Category category, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1614,8 +1603,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToCourseView({ - _i38.Key? key, - required _i43.Subcategory subcategory, + _i39.Key? key, + required _i46.Subcategory subcategory, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1631,7 +1620,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future navigateToCoursePracticeQuestionView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1661,6 +1650,23 @@ extension NavigatorStateExtension on _i44.NavigationService { transition: transition); } + Future navigateToLearnSubmoduleView({ + _i39.Key? key, + required _i47.Module module, + 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), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + Future replaceWithHomeView([ int? routerId, bool preventDuplicates = true, @@ -1690,7 +1696,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithStartupView({ - _i38.Key? key, + _i39.Key? key, String label = 'Loading', int? routerId, bool preventDuplicates = true, @@ -1889,7 +1895,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithLearnView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1906,7 +1912,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithLearnLevelView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -1923,8 +1929,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithLearnModuleView({ - _i38.Key? key, - required _i39.Level level, + _i39.Key? key, + required _i40.Level level, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1954,7 +1960,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithAssessmentView({ - _i38.Key? key, + _i39.Key? key, required Map data, int? routerId, bool preventDuplicates = true, @@ -1971,12 +1977,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithLearnLessonView({ - _i38.Key? key, - required String title, - required String topics, - required String subtitle, - required List> practices, - required String description, + _i39.Key? key, + required _i41.Submodule submodule, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -1984,13 +1986,7 @@ extension NavigatorStateExtension on _i44.NavigationService { transition, }) async { return replaceWith(Routes.learnLessonView, - arguments: LearnLessonViewArguments( - key: key, - title: title, - topics: topics, - subtitle: subtitle, - practices: practices, - description: description), + arguments: LearnLessonViewArguments(key: key, submodule: submodule), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -2012,10 +2008,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithLearnLessonDetailView({ - _i38.Key? key, - required String title, - required List> practices, - required String description, + _i39.Key? key, + required _i42.Lesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2023,11 +2017,7 @@ extension NavigatorStateExtension on _i44.NavigationService { transition, }) async { return replaceWith(Routes.learnLessonDetailView, - arguments: LearnLessonDetailViewArguments( - key: key, - title: title, - practices: practices, - description: description), + arguments: LearnLessonDetailViewArguments(key: key, lesson: lesson), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -2035,7 +2025,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithLearnPracticeView({ - _i38.Key? key, + _i39.Key? key, required String title, required String subtitle, required List> practices, @@ -2060,7 +2050,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithCoursePracticeView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -2077,8 +2067,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithCoursePaymentView({ - _i38.Key? key, - required _i40.Course course, + _i39.Key? key, + required _i43.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2108,7 +2098,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithFailureView({ - _i38.Key? key, + _i39.Key? key, required String label, int? routerId, bool preventDuplicates = true, @@ -2125,8 +2115,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithCourseLessonView({ - _i38.Key? key, - required _i40.Course course, + _i39.Key? key, + required _i43.Course course, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2142,8 +2132,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithCourseLessonDetailView({ - _i38.Key? key, - required _i41.CourseLesson lesson, + _i39.Key? key, + required _i44.CourseLesson lesson, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2173,8 +2163,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithCourseSubcategoryView({ - _i38.Key? key, - required _i42.Category category, + _i39.Key? key, + required _i45.Category category, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2190,8 +2180,8 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithCourseView({ - _i38.Key? key, - required _i43.Subcategory subcategory, + _i39.Key? key, + required _i46.Subcategory subcategory, int? routerId, bool preventDuplicates = true, Map? parameters, @@ -2207,7 +2197,7 @@ extension NavigatorStateExtension on _i44.NavigationService { } Future replaceWithCoursePracticeQuestionView({ - _i38.Key? key, + _i39.Key? key, required int id, int? routerId, bool preventDuplicates = true, @@ -2236,4 +2226,21 @@ extension NavigatorStateExtension on _i44.NavigationService { parameters: parameters, transition: transition); } + + Future replaceWithLearnSubmoduleView({ + _i39.Key? key, + required _i47.Module module, + 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), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } } diff --git a/lib/models/lesson.dart b/lib/models/lesson.dart new file mode 100644 index 0000000..2bab71e --- /dev/null +++ b/lib/models/lesson.dart @@ -0,0 +1,52 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'lesson.g.dart'; + +@JsonSerializable() +class Lesson { + final int? id; + + final String? title; + + final String? thumbnail; + + final String? description; + + @JsonKey(name: 'is_active') + final bool? isActive; + + @JsonKey(name: 'sub_module_id') + final int? subModuleId; + + @JsonKey(name: 'teaching_text') + final String? teachingText; + + @JsonKey(name: 'display_order') + final int? displayOrder; + + @JsonKey(name: 'teaching_video_url') + final String? teachingVideoUrl; + + @JsonKey(name: 'teaching_image_url') + final String? teachingImageUrl; + + @JsonKey(name: 'teaching_audio_url') + final String? teachingAudioUrl; + + const Lesson( + {this.id, + this.title, + this.isActive, + this.thumbnail, + this.subModuleId, + this.description, + this.teachingText, + this.displayOrder, + this.teachingAudioUrl, + this.teachingImageUrl, + this.teachingVideoUrl}); + + factory Lesson.fromJson(Map json) => _$LessonFromJson(json); + + Map toJson() => _$LessonToJson(this); +} diff --git a/lib/models/lesson.g.dart b/lib/models/lesson.g.dart new file mode 100644 index 0000000..1ffe886 --- /dev/null +++ b/lib/models/lesson.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'lesson.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Lesson _$LessonFromJson(Map json) => Lesson( + id: (json['id'] as num?)?.toInt(), + title: json['title'] as String?, + isActive: json['is_active'] as bool?, + thumbnail: json['thumbnail'] as String?, + subModuleId: (json['sub_module_id'] as num?)?.toInt(), + description: json['description'] as String?, + teachingText: json['teaching_text'] as String?, + displayOrder: (json['display_order'] as num?)?.toInt(), + teachingAudioUrl: json['teaching_audio_url'] as String?, + teachingImageUrl: json['teaching_image_url'] as String?, + teachingVideoUrl: json['teaching_video_url'] as String?, + ); + +Map _$LessonToJson(Lesson instance) => { + 'id': instance.id, + 'title': instance.title, + 'thumbnail': instance.thumbnail, + 'description': instance.description, + 'is_active': instance.isActive, + 'sub_module_id': instance.subModuleId, + 'teaching_text': instance.teachingText, + 'display_order': instance.displayOrder, + 'teaching_video_url': instance.teachingVideoUrl, + 'teaching_image_url': instance.teachingImageUrl, + 'teaching_audio_url': instance.teachingAudioUrl, + }; diff --git a/lib/models/submodule.dart b/lib/models/submodule.dart new file mode 100644 index 0000000..2f895d3 --- /dev/null +++ b/lib/models/submodule.dart @@ -0,0 +1,44 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'submodule.g.dart'; + +@JsonSerializable() +class Submodule { + final int? id; + + final String? tips; + + final String? title; + + final String? thumbnail; + + final String? description; + + @JsonKey(name: 'module_id') + final int? moduleId; + + @JsonKey(name: 'is_active') + final bool? isActive; + + @JsonKey(name: 'display_order') + final int? displayOrder; + + @JsonKey(name: 'legacy_sub_course_id') + final int? legacySubCourseId; + + const Submodule( + {this.id, + this.title, + this.tips, + this.moduleId, + this.isActive, + this.thumbnail, + this.description, + this.displayOrder, + this.legacySubCourseId}); + + factory Submodule.fromJson(Map json) => + _$SubmoduleFromJson(json); + + Map toJson() => _$SubmoduleToJson(this); +} diff --git a/lib/models/submodule.g.dart b/lib/models/submodule.g.dart new file mode 100644 index 0000000..2d926d3 --- /dev/null +++ b/lib/models/submodule.g.dart @@ -0,0 +1,31 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'submodule.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Submodule _$SubmoduleFromJson(Map json) => Submodule( + id: (json['id'] as num?)?.toInt(), + title: json['title'] as String?, + tips: json['tips'] as String?, + moduleId: (json['module_id'] as num?)?.toInt(), + isActive: json['is_active'] as bool?, + thumbnail: json['thumbnail'] as String?, + description: json['description'] as String?, + displayOrder: (json['display_order'] as num?)?.toInt(), + legacySubCourseId: (json['legacy_sub_course_id'] as num?)?.toInt(), + ); + +Map _$SubmoduleToJson(Submodule instance) => { + 'id': instance.id, + 'tips': instance.tips, + 'title': instance.title, + 'thumbnail': instance.thumbnail, + 'description': instance.description, + 'module_id': instance.moduleId, + 'is_active': instance.isActive, + 'display_order': instance.displayOrder, + 'legacy_sub_course_id': instance.legacySubCourseId, + }; diff --git a/lib/services/api_service.dart b/lib/services/api_service.dart index ceac617..7dfce73 100644 --- a/lib/services/api_service.dart +++ b/lib/services/api_service.dart @@ -13,7 +13,9 @@ import 'package:yimaru_app/services/dio_service.dart'; import 'package:yimaru_app/ui/common/app_constants.dart'; import '../app/app.locator.dart'; +import '../models/lesson.dart'; import '../models/module.dart'; +import '../models/submodule.dart'; import '../ui/common/enmus.dart'; class ApiService { @@ -674,4 +676,52 @@ class ApiService { return []; } } + + // Get submodules + Future> getSubmodules(int id) async { + try { + List submodules = []; + + final Response response = await _service.dio.get( + '$kBaseUrl/api/$kApiVersionUrl/$kCourseManagementUrl/$kModulesUrl/$id/$kSubmodulesUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data']['sub_modules'] as List; + submodules = decodedData.map( + (e) { + return Submodule.fromJson(e); + }, + ).toList(); + return submodules; + } + return []; + } catch (e) { + return []; + } + } + + // Get lessons + Future> getLessons(int id) async { + try { + List lessons = []; + + final Response response = await _service.dio.get( + '$kBaseUrl/api/$kApiVersionUrl/$kCourseManagementUrl/$kSubmodulesUrl/$id/$kLessonsUrl'); + + if (response.statusCode == 200) { + var data = response.data; + var decodedData = data['data'] as List; + lessons = decodedData.map( + (e) { + return Lesson.fromJson(e); + }, + ).toList(); + return lessons; + } + return []; + } catch (e) { + return []; + } + } } diff --git a/lib/ui/common/app_constants.dart b/lib/ui/common/app_constants.dart index 63a14dc..da5fcfb 100644 --- a/lib/ui/common/app_constants.dart +++ b/lib/ui/common/app_constants.dart @@ -10,6 +10,8 @@ String kCoursesUrl = 'courses'; String kModulesUrl = 'modules'; +String kLessonsUrl = 'lessons'; + String kRegisterUrl = 'register'; String kCategoryUrl = 'categories'; @@ -24,6 +26,8 @@ String kResendOtpUrl = 'resend-otp'; String kGetUserUrl = 'user-profile'; +String kSubmodulesUrl = 'sub-modules'; + String kSubcoursesUrl = 'sub-courses'; String kCompleteLessonUrl = 'complete'; diff --git a/lib/ui/common/enmus.dart b/lib/ui/common/enmus.dart index fa8789f..f56f05d 100644 --- a/lib/ui/common/enmus.dart +++ b/lib/ui/common/enmus.dart @@ -28,6 +28,7 @@ enum StateObjects { verifyOtp, resendOtp, learnLevels, + learnLessons, learnModules, learnCourses, profileImage, @@ -40,6 +41,7 @@ enum StateObjects { loginWithGoogle, loadLessonVideo, loadCourseVideo, + learnSubmodules, requestResetCode, courseCategories, profileCompletion, diff --git a/lib/ui/views/course_category/course_category_viewmodel.dart b/lib/ui/views/course_category/course_category_viewmodel.dart index 683f6f3..b0dfed8 100644 --- a/lib/ui/views/course_category/course_category_viewmodel.dart +++ b/lib/ui/views/course_category/course_category_viewmodel.dart @@ -41,9 +41,8 @@ class CourseCategoryViewModel extends ReactiveViewModel { // Remote api call // Course categories - Future getCategories() async => - await runBusyFuture(_getCategories(), - busyObject: StateObjects.courseCategories); + Future getCategories() async => await runBusyFuture(_getCategories(), + busyObject: StateObjects.courseCategories); Future _getCategories() async { if (categories.isEmpty) { diff --git a/lib/ui/views/course_lesson_detail/course_lesson_detail_viewmodel.dart b/lib/ui/views/course_lesson_detail/course_lesson_detail_viewmodel.dart index 7d76635..c0ac889 100644 --- a/lib/ui/views/course_lesson_detail/course_lesson_detail_viewmodel.dart +++ b/lib/ui/views/course_lesson_detail/course_lesson_detail_viewmodel.dart @@ -66,6 +66,7 @@ class CourseLessonDetailViewModel extends BaseViewModel { busyObject: StateObjects.loadCourseVideo); Future _initializePlayer(CourseLesson lesson) async { + print('URL: $kSampleVideoUrl'); _videoPlayerController = VideoPlayerController.networkUrl(Uri.parse(kSampleVideoUrl)); diff --git a/lib/ui/views/learn_lesson/learn_lesson_view.dart b/lib/ui/views/learn_lesson/learn_lesson_view.dart index 1fe0a8b..7d324f0 100644 --- a/lib/ui/views/learn_lesson/learn_lesson_view.dart +++ b/lib/ui/views/learn_lesson/learn_lesson_view.dart @@ -1,31 +1,30 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; +import 'package:yimaru_app/models/submodule.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_elevated_button.dart'; +import '../../widgets/custom_circular_progress_indicator.dart'; import '../../widgets/small_app_bar.dart'; import 'learn_lesson_viewmodel.dart'; class LearnLessonView extends StackedView { - final String title; - final String topics; - final String subtitle; - final String description; - final List> practices; + final Submodule submodule; + + const LearnLessonView({Key? key, required this.submodule}) : super(key: key); + + + @override + void onViewModelReady(LearnLessonViewModel viewModel) async { + await viewModel.getLessons(submodule.id ?? 0); + super.onViewModelReady(viewModel); + } - const LearnLessonView( - {Key? key, - required this.title, - required this.topics, - required this.subtitle, - required this.practices, - required this.description}) - : super(key: key); Widget getPadding(context) { double half = screenHeight(context) / 2; @@ -117,95 +116,63 @@ class LearnLessonView extends StackedView { verticalSpaceTiny, _buildSubtitle(), verticalSpaceSmall, - _buildTopics(), verticalSpaceSmall, - // _buildModuleProgress(), - // verticalSpaceMedium, - // _buildContinueButton(), - // verticalSpaceMedium, - // _buildMotivationCard(), - // verticalSpaceMedium, - //_buildHeader(), - //verticalSpaceMedium, - // _buildListView(viewModel), - getPadding(context), - _buildStartButton(viewModel), - verticalSpaceSmall, - _buildPracticeButton(viewModel) + _buildModuleProgress(), + verticalSpaceMedium, + verticalSpaceMedium, + _buildMotivationCard(), + verticalSpaceMedium, + _buildHeader(), + verticalSpaceMedium, + _buildListViewBuilder(viewModel), ]; Widget _buildTitle() => Text( - title, + submodule.title ?? '', style: style16DG600, ); Widget _buildSubtitle() => Text( - subtitle, + submodule.description ?? '', style: style14DG600, ); - Widget _buildTopics() => Text( - topics, - style: style14DG500, - ); - Widget _buildModuleProgress() => const ModuleProgress(); - Widget _buildStartButton(LearnLessonViewModel viewModel) => - CustomElevatedButton( - height: 55, - borderRadius: 12, - text: 'Start $title', - foregroundColor: kcWhite, - backgroundColor: kcPrimaryColor, - onTap: () async => await viewModel.navigateToLearnLessonDetail( - title: title, practices: practices, description: description), - ); - - Widget _buildPracticeButton(LearnLessonViewModel viewModel) => - CustomElevatedButton( - height: 55, - borderRadius: 12, - text: 'Practice', - backgroundColor: kcWhite, - borderColor: kcPrimaryColor, - foregroundColor: kcPrimaryColor, - onTap: () async => - await viewModel.navigateToLearnPractice(practices)); - Widget _buildMotivationCard() => const MotivationCard(); Widget _buildHeader() => Text( - title, + 'Lessons in this module', style: style18DG700, ); + + Widget _buildListViewBuilder(LearnLessonViewModel viewModel) => + viewModel.busy(StateObjects.learnLessons) + ? _buildProgressIndicator() + : _buildListView(viewModel); + + Widget _buildProgressIndicator() => const Center( + child: CustomCircularProgressIndicator(color: kcPrimaryColor), + ); + + Widget _buildListView(LearnLessonViewModel viewModel) => ListView.builder( shrinkWrap: true, itemCount: viewModel.lessons.length, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _buildTile( - title: viewModel.lessons[index]['title'], - status: viewModel.lessons[index]['status'], - thumbnail: viewModel.lessons[index]['thumbnail'], - onLessonTap: () async => await viewModel.navigateToLearnLessonDetail( - title: title, practices: practices, description: description), - // onPracticeTap: () async => await viewModel.navigateToLearnPractice(), + lesson: viewModel.lessons[index], + onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(viewModel.lessons[index]), ), ); Widget _buildTile({ - required String title, - required String thumbnail, - GestureTapCallback? onLessonTap, - required ProgressStatuses status, - GestureTapCallback? onPracticeTap, + required Lesson lesson, + required GestureTapCallback? onLessonTap, }) => LearnLessonTile( - title: title, - status: status, - thumbnail: thumbnail, + 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 1cb08ac..b3cc5e6 100644 --- a/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart +++ b/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart @@ -4,47 +4,42 @@ import 'package:yimaru_app/app/app.router.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'; class LearnLessonViewModel extends BaseViewModel { + // Dependency injection + final _apiService = locator(); + + final _statusChecker = locator(); + final _navigationService = locator(); - // Lessons - final List> _lessons = [ - { - 'title': '1.1 Introducing Yourself', - 'status': ProgressStatuses.completed, - 'thumbnail': 'assets/images/image_1.png', - }, - { - 'status': ProgressStatuses.completed, - 'thumbnail': 'assets/images/image_1.png', - 'title': '1.2 Talking About Your Surroundings', - }, - { - 'status': ProgressStatuses.pending, - 'title': '1.1 Introducing Yourself', - 'thumbnail': 'assets/images/image_1.png', - }, - ]; + // Learn lessons + List _lessons = []; - List> get lessons => _lessons; + List get lessons => _lessons; // Navigation void pop() => _navigationService.back(); - Future navigateToLearnLessonDetail( - {required String title, - required List> practices, - required String description}) async => - await _navigationService.navigateToLearnLessonDetailView( - title: title, practices: practices, description: description); + Future navigateToLearnLessonDetail(Lesson lesson) async => + await _navigationService.navigateToLearnLessonDetailView(lesson: lesson); - Future navigateToLearnPractice( - List> practices) async => - await _navigationService.navigateToLearnPracticeView( - practices: practices, - title: 'Let’s Practice', - buttonLabel: 'Begin Lesson Practice', - subtitle: 'Let’s quickly review what you’ve learned in this lesson!', - ); + // Remote api call + + // Learn modules + 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)); + } + } + } } 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 825a1fa..d6e8bcc 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,8 +1,9 @@ -import 'package:chewie/chewie.dart'; 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 '../../../models/lesson.dart'; import '../../common/app_colors.dart'; import '../../common/enmus.dart'; import '../../common/ui_helpers.dart'; @@ -11,20 +12,14 @@ import '../../widgets/small_app_bar.dart'; import 'learn_lesson_detail_viewmodel.dart'; class LearnLessonDetailView extends StackedView { - final String title; - final String description; - final List> practices; + final Lesson lesson; - const LearnLessonDetailView( - {Key? key, - required this.title, - required this.practices, - required this.description}) + 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(practices); } @override @@ -34,12 +29,6 @@ class LearnLessonDetailView extends StackedView { super.onDispose(viewModel); } - @override - void onViewModelReady(LearnLessonDetailViewModel viewModel) async { - await viewModel.initializePlayer(); - super.onViewModelReady(viewModel); - } - @override LearnLessonDetailViewModel viewModelBuilder(BuildContext context) => LearnLessonDetailViewModel(); @@ -125,7 +114,7 @@ class LearnLessonDetailView extends StackedView { ); Widget _buildTitle() => Text( - title, + lesson.title ?? '', style: style16DG600, ); @@ -134,21 +123,21 @@ class LearnLessonDetailView extends StackedView { height: 200, color: kcBlack, width: double.maxFinite, - child: _buildVideoPlayerState(viewModel), + child: _buildVideoPlayer(viewModel), ); - Widget _buildVideoPlayerState(LearnLessonDetailViewModel viewModel) => - viewModel.chewieController != null && - viewModel.videoPlayerController != null && - !viewModel.busy(StateObjects.loadLessonVideo) - ? _buildVideoPlayer(viewModel) - : _buildEmptyVideoPlayer(); + Widget _buildVideoPlayer(LearnLessonDetailViewModel viewModel) => - _buildChewiePlayer(viewModel); + _buildVimeoPlayer(viewModel); - Widget _buildChewiePlayer(LearnLessonDetailViewModel viewModel) => - Chewie(controller: viewModel.chewieController!); + Widget _buildVimeoPlayer(LearnLessonDetailViewModel viewModel) => + VimeoVideoPlayer( + isAutoPlay: true, + onInAppWebViewCreated: (controller) => + viewModel.initializePlayer(controller), + videoId: lesson.teachingVideoUrl?.split('/').last ?? '', + ); Widget _buildEmptyVideoPlayer() => const EmptyVideoPlayer(); @@ -158,7 +147,7 @@ class LearnLessonDetailView extends StackedView { ); Widget _buildDescription() => Text( - description, + lesson.description ?? '', style: style14DG600, ); @@ -175,7 +164,7 @@ class LearnLessonDetailView extends StackedView { Widget _buildContinueButton(LearnLessonDetailViewModel viewModel) => CustomElevatedButton( height: 55, - text: 'Practice', + text: 'Lessons', borderRadius: 12, foregroundColor: kcWhite, backgroundColor: kcPrimaryColor, 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 f7d6f1e..1a54d3c 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,11 +1,10 @@ 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/app_constants.dart'; import 'package:yimaru_app/ui/common/enmus.dart'; -import 'package:yimaru_app/ui/common/ui_helpers.dart'; import '../../../app/app.locator.dart'; import '../../../services/status_checker_service.dart'; @@ -20,6 +19,10 @@ class LearnLessonDetailViewModel extends BaseViewModel { ChewieController? get chewieController => _chewieController; + InAppWebViewController? _webViewController; + + InAppWebViewController? get webViewController => _webViewController; + VideoPlayerController? _videoPlayerController; VideoPlayerController? get videoPlayerController => _videoPlayerController; @@ -34,32 +37,22 @@ class LearnLessonDetailViewModel extends BaseViewModel { await _chewieController?.pause(); } - Future initializePlayer() async => - await runBusyFuture(_initializePlayer(), - busyObject: StateObjects.loadLessonVideo); - - Future _initializePlayer() async { - _videoPlayerController = - VideoPlayerController.networkUrl(Uri.parse(kSampleVideoUrl)); - - await _videoPlayerController?.initialize(); - - if (_videoPlayerController != null) { - _chewieController = ChewieController( - looping: true, - autoPlay: true, - showOptions: true, - showControls: true, - aspectRatio: 16 / 9, - autoInitialize: true, - allowedScreenSleep: false, - videoPlayerController: _videoPlayerController!, - materialProgressColors: buildChewieProgressIndicator); - } - - // rebuildUi(); + void initializePlayer(InAppWebViewController controller){ + _webViewController = controller; + rebuildUi(); } + void onLoadVideoStart() { + setBusyForObject(StateObjects.loadLessonVideo, true); + rebuildUi(); + } + + void onLoadVideoComplete() { + setBusyForObject(StateObjects.loadLessonVideo, false); + rebuildUi(); + } + + // Navigation void pop() => _navigationService.back(); diff --git a/lib/ui/views/learn_level/learn_level_view.dart b/lib/ui/views/learn_level/learn_level_view.dart index 4dc8c7c..81076c6 100644 --- a/lib/ui/views/learn_level/learn_level_view.dart +++ b/lib/ui/views/learn_level/learn_level_view.dart @@ -55,6 +55,7 @@ class LearnLevelView extends StackedView { ); Widget _buildAppBar(LearnLevelViewModel viewModel) => SmallAppBar( + title: 'Levels', onTap: viewModel.pop, showBackButton: true, ); @@ -82,7 +83,8 @@ class LearnLevelView extends StackedView { physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _buildTile( level: viewModel.levels[index], - onTap: () async => await viewModel.navigateToModule( viewModel.levels[index]), + onTap: () async => + await viewModel.navigateToModule(viewModel.levels[index]), ), separatorBuilder: (context, index) => verticalSpaceSmall, ); diff --git a/lib/ui/views/learn_module/learn_module_view.dart b/lib/ui/views/learn_module/learn_module_view.dart index 8e8699e..4713fec 100644 --- a/lib/ui/views/learn_module/learn_module_view.dart +++ b/lib/ui/views/learn_module/learn_module_view.dart @@ -1,13 +1,14 @@ import 'package:flutter/material.dart'; import 'package:stacked/stacked.dart'; import 'package:yimaru_app/models/level.dart'; -import 'package:yimaru_app/ui/common/enmus.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 '../../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_module_viewmodel.dart'; @@ -57,6 +58,7 @@ class LearnModuleView extends StackedView { ); Widget _buildAppBar(LearnModuleViewModel viewModel) => SmallAppBar( + title: 'Modules', onTap: viewModel.pop, showBackButton: true, ); @@ -79,10 +81,10 @@ class LearnModuleView extends StackedView { verticalSpaceMedium, _buildTitle(), _buildSubtitle(), - verticalSpaceMedium, + verticalSpaceLarge, _buildOverallProgress(), verticalSpaceMedium, - _buildListView(viewModel) + _buildListViewBuilder(viewModel) ]; Widget _buildTitle() => Text( @@ -95,26 +97,36 @@ class LearnModuleView extends StackedView { style: style14DG400, ); - Widget _buildOverallProgress() => const OverallLearnProgress(); + Widget _buildOverallProgress() => OverallLearnProgress( + color: kcPrimaryColor.withOpacity(0.1), + ); + + Widget _buildListViewBuilder(LearnModuleViewModel viewModel) => + viewModel.busy(StateObjects.learnModules) + ? _buildProgressIndicator() + : _buildListView(viewModel); + + Widget _buildProgressIndicator() => const Center( + child: CustomCircularProgressIndicator(color: kcPrimaryColor), + ); Widget _buildListView(LearnModuleViewModel viewModel) => ListView.builder( shrinkWrap: true, itemCount: viewModel.modules.length, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _buildTile( - module: viewModel.modules[index], - onLessonTap: () {}, - onPracticeTap: () {}), + module: viewModel.modules[index], + onModuleTap: () async => await viewModel + .navigateToLearnSubmodule(viewModel.modules[index]), + ), ); Widget _buildTile({ required Module module, - required GestureTapCallback onLessonTap, - required GestureTapCallback onPracticeTap, + required GestureTapCallback onModuleTap, }) => LearnModuleTile( module: module, - onLessonTap: onLessonTap, - onPracticeTap: onPracticeTap, + onModuleTap: onModuleTap, ); } diff --git a/lib/ui/views/learn_module/learn_module_viewmodel.dart b/lib/ui/views/learn_module/learn_module_viewmodel.dart index 60fe809..348830a 100644 --- a/lib/ui/views/learn_module/learn_module_viewmodel.dart +++ b/lib/ui/views/learn_module/learn_module_viewmodel.dart @@ -24,27 +24,8 @@ class LearnModuleViewModel extends BaseViewModel { // Navigation void pop() => _navigationService.back(); - Future navigateToLearnLesson( - {required String title, - required String topics, - required String subtitle, - required String description, - required List> practices}) async => - await _navigationService.navigateToLearnLessonView( - title: title, - topics: topics, - subtitle: subtitle, - practices: practices, - description: description); - - Future navigateToLearnPractice( - List> practices) async => - await _navigationService.navigateToLearnPracticeView( - practices: practices, - title: 'Let’s Practice', - buttonLabel: 'Begin Lesson Practice', - subtitle: 'Let’s quickly review what you’ve learned in this lesson!', - ); + Future navigateToLearnSubmodule(Module module) async => + await _navigationService.navigateToLearnSubmoduleView(module: module); // Remote api call diff --git a/lib/ui/views/learn_submodule/learn_submodule_view.dart b/lib/ui/views/learn_submodule/learn_submodule_view.dart new file mode 100644 index 0000000..e394e9c --- /dev/null +++ b/lib/ui/views/learn_submodule/learn_submodule_view.dart @@ -0,0 +1,146 @@ +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 new file mode 100644 index 0000000..9b00dac --- /dev/null +++ b/lib/ui/views/learn_submodule/learn_submodule_viewmodel.dart @@ -0,0 +1,46 @@ +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/widgets/course_module_banner.dart b/lib/ui/widgets/course_module_banner.dart index e6b6c3b..a5483de 100644 --- a/lib/ui/widgets/course_module_banner.dart +++ b/lib/ui/widgets/course_module_banner.dart @@ -8,7 +8,7 @@ class CourseModuleBanner extends StatelessWidget { Widget build(BuildContext context) => _buildContainer(); Widget _buildContainer() => Container( - height: 150, + height: 125, width: double.maxFinite, padding: const EdgeInsets.all(15), decoration: BoxDecoration( diff --git a/lib/ui/widgets/learn_lesson_tile.dart b/lib/ui/widgets/learn_lesson_tile.dart index a622630..b5ed843 100644 --- a/lib/ui/widgets/learn_lesson_tile.dart +++ b/lib/ui/widgets/learn_lesson_tile.dart @@ -1,27 +1,17 @@ import 'package:flutter/material.dart'; +import 'package:yimaru_app/models/lesson.dart'; import 'package:yimaru_app/ui/widgets/mini_thumbnail.dart'; import '../common/app_colors.dart'; -import '../common/enmus.dart'; import '../common/ui_helpers.dart'; import 'custom_elevated_button.dart'; import 'custom_linear_progress_indicator.dart'; class LearnLessonTile extends StatelessWidget { - final String title; - final String thumbnail; - final ProgressStatuses status; + final Lesson lesson; final GestureTapCallback? onLessonTap; - final GestureTapCallback? onPracticeTap; - const LearnLessonTile({ - super.key, - this.onLessonTap, - this.onPracticeTap, - required this.title, - required this.status, - required this.thumbnail, - }); + const LearnLessonTile({super.key, this.onLessonTap, required this.lesson}); @override Widget build(BuildContext context) => _buildContainer(); @@ -32,50 +22,55 @@ class LearnLessonTile extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(5), border: Border.all( - color: ProgressStatuses.pending == status - ? kcPrimaryColor.withOpacity(0.1) - : kcGreen.withOpacity(0.1), + color: kcPrimaryColor.withOpacity(0.1), + // color: ProgressStatuses.pending == status + // ? kcPrimaryColor.withOpacity(0.1) + // : kcGreen.withOpacity(0.1), ), ), child: _buildExpansionTile(), ); Widget _buildExpansionTile() => ExpansionTile( + enabled: true, title: _buildTitle(), textColor: kcDarkGrey, showTrailingIcon: true, - trailing: _buildIconState(), - // subtitle: _buildContent(), + initiallyExpanded: true, + trailing: _buildPendingIcon(), collapsedIconColor: kcDarkGrey, collapsedTextColor: kcDarkGrey, leading: _buildLeadingWrapper(), shape: Border.all(color: kcTransparent), expandedAlignment: Alignment.centerLeft, - enabled: status != ProgressStatuses.pending, + backgroundColor: kcGreen.withOpacity(0.1), controlAffinity: ListTileControlAffinity.trailing, - backgroundColor: ProgressStatuses.pending == status - ? kcPrimaryColor.withOpacity(0.1) - : kcGreen.withOpacity(0.1), - childrenPadding: const EdgeInsets.fromLTRB(15, 15, 15, 15), expandedCrossAxisAlignment: CrossAxisAlignment.start, - collapsedBackgroundColor: ProgressStatuses.pending == status - ? kcPrimaryColor.withOpacity(0.1) - : kcGreen.withOpacity(0.1), + collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1), + childrenPadding: const EdgeInsets.fromLTRB(15, 15, 15, 15), tilePadding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), - initiallyExpanded: status != ProgressStatuses.completed ? true : false, + // enabled: status != ProgressStatuses.pending, + // backgroundColor: ProgressStatuses.pending == status + // ? kcPrimaryColor.withOpacity(0.1) + // : kcGreen.withOpacity(0.1), + // collapsedBackgroundColor: ProgressStatuses.pending == status + // ? kcPrimaryColor.withOpacity(0.1) + // : kcGreen.withOpacity(0.1), + // initiallyExpanded: status != ProgressStatuses.completed ? true : false, children: _buildExpansionTileChildren(), ); - Widget _buildLeadingWrapper() => MiniThumbnail(thumbnail: thumbnail); + Widget _buildLeadingWrapper() => + MiniThumbnail(thumbnail: lesson.thumbnail ?? 'assets/images/image_1.png'); Widget _buildTitle() => Text( - title, + lesson.title ?? '', style: style16DG600, ); - Widget _buildIconState() => ProgressStatuses.pending == status - ? _buildPendingIcon() - : _buildCompleteIcon(); + // Widget _buildIconState() => ProgressStatuses.pending == status + // ? _buildPendingIcon() + // : _buildCompleteIcon(); Widget _buildCompleteIcon() => const Icon( Icons.check, @@ -98,58 +93,35 @@ class LearnLessonTile extends StatelessWidget { List _buildExpansionTileItemChildren() => [ _buildProgress(), horizontalSpaceSmall, - _buildProgressText(), - verticalSpaceSmall, + // _buildProgressText(), + // verticalSpaceSmall, _buildActionButtonWrapper() ]; - Widget _buildProgress() => CustomLinearProgressIndicator( + Widget _buildProgress() => const CustomLinearProgressIndicator( + progress: 0, activeColor: kcPrimaryColor, backgroundColor: kcVeryLightGrey, - progress: ProgressStatuses.completed == status ? 1 : 0.75, ); - Widget _buildProgressText() => Text( - ProgressStatuses.completed == status ? 'Completed' : 'In Progress', - style: style14P400, - ); + // Widget _buildProgressText() => Text( + // ProgressStatuses.completed == status ? 'Completed' : 'In Progress', + // style: style14P400, + // ); Widget _buildActionButtonWrapper() => SizedBox( - height: 40, - child: _buildActionButtons(), - ); - - Widget _buildActionButtons() => Row( - mainAxisAlignment: MainAxisAlignment.end, - children: _buildActionButtonChildren(), - ); - - List _buildActionButtonChildren() => [ - _buildPracticeButton(), - horizontalSpaceSmall, - _buildLessonButton(), - ]; - - Widget _buildPracticeButton() => CustomElevatedButton( - height: 15, - width: 135, - text: 'Practice', - borderRadius: 12, - onTap: onPracticeTap, - trailingIcon: Icons.mic, - backgroundColor: kcWhite, - borderColor: kcPrimaryColor, - foregroundColor: kcPrimaryColor, + height: 50, + child: _buildLessonButton(), ); Widget _buildLessonButton() => CustomElevatedButton( height: 15, - width: 135, + text: 'Start', borderRadius: 12, onTap: onLessonTap, + width: double.maxFinite, foregroundColor: kcWhite, trailingIcon: Icons.play_arrow, backgroundColor: kcPrimaryColor, - text: ProgressStatuses.completed == status ? 'View' : 'Continue', ); } diff --git a/lib/ui/widgets/learn_module_tile.dart b/lib/ui/widgets/learn_module_tile.dart index 3387146..be883e7 100644 --- a/lib/ui/widgets/learn_module_tile.dart +++ b/lib/ui/widgets/learn_module_tile.dart @@ -6,17 +6,14 @@ import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart'; import '../../models/module.dart'; import '../common/app_colors.dart'; -import '../common/enmus.dart'; import '../common/ui_helpers.dart'; import 'custom_elevated_button.dart'; class LearnModuleTile extends ViewModelWidget { final Module module; - final GestureTapCallback? onLessonTap; - final GestureTapCallback? onPracticeTap; + final GestureTapCallback? onModuleTap; - const LearnModuleTile( - {super.key, this.onLessonTap, this.onPracticeTap, required this.module}); + const LearnModuleTile({super.key, this.onModuleTap, required this.module}); Future _showSheet( {required BuildContext context, @@ -158,7 +155,7 @@ class LearnModuleTile extends ViewModelWidget { required LearnModuleViewModel viewModel}) => SizedBox( height: 40, - child: _buildActionButtons(context: context, viewModel: viewModel), + child: _buildModuleButton(viewModel), ); Widget _buildActionButtons( @@ -166,46 +163,39 @@ class LearnModuleTile extends ViewModelWidget { required LearnModuleViewModel viewModel}) => Row( children: [ - _buildLessonButtonWrapper(viewModel), + _buildModuleButtonWrapper(viewModel), horizontalSpaceSmall, _buildPracticeButtonWrapper(context: context, viewModel: viewModel) ], ); - Widget _buildLessonButtonWrapper(LearnModuleViewModel viewModel) => Expanded( - child: _buildLessonButton(viewModel), + Widget _buildModuleButtonWrapper(LearnModuleViewModel viewModel) => Expanded( + child: _buildModuleButton(viewModel), ); - Widget _buildLessonButton(LearnModuleViewModel viewModel) => + Widget _buildModuleButton(LearnModuleViewModel viewModel) => CustomElevatedButton( height: 15, borderRadius: 12, - onTap: onLessonTap, + onTap: onModuleTap, 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 LearnModuleViewModel viewModel}) => Expanded( - child: _buildPracticeButton(context: context, viewModel: viewModel), + child: Container(), ); Widget _buildPracticeButton( {required BuildContext context, required LearnModuleViewModel viewModel}) => - CustomElevatedButton( + const CustomElevatedButton( height: 15, borderRadius: 12, - onTap: onPracticeTap, text: 'View Practices', backgroundColor: kcWhite, borderColor: kcPrimaryColor, diff --git a/lib/ui/widgets/learn_submodule_tile.dart b/lib/ui/widgets/learn_submodule_tile.dart new file mode 100644 index 0000000..b735273 --- /dev/null +++ b/lib/ui/widgets/learn_submodule_tile.dart @@ -0,0 +1,237 @@ +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/module_progress.dart b/lib/ui/widgets/module_progress.dart index 0d6d90f..61d4dd3 100644 --- a/lib/ui/widgets/module_progress.dart +++ b/lib/ui/widgets/module_progress.dart @@ -36,17 +36,17 @@ class ModuleProgress extends StatelessWidget { [_buildProgressInfo(), _buildProgress()]; Widget _buildProgressInfo() => Text( - '60% Progress', + '0% Progress', style: style16DG400, ); Widget _buildProgress() => Text( - '2/3', + '0/3', style: style14P400, ); Widget _buildProgressIndicator() => const CustomLinearProgressIndicator( - progress: 0.75, + progress: 0, activeColor: kcPrimaryColor, backgroundColor: kcVeryLightGrey, ); diff --git a/lib/ui/widgets/overall_learn_progress.dart b/lib/ui/widgets/overall_learn_progress.dart index c85ce5d..8049bef 100644 --- a/lib/ui/widgets/overall_learn_progress.dart +++ b/lib/ui/widgets/overall_learn_progress.dart @@ -4,7 +4,8 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart'; import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart'; class OverallLearnProgress extends StatelessWidget { - const OverallLearnProgress({super.key}); + final Color color; + const OverallLearnProgress({super.key, required this.color}); @override Widget build(BuildContext context) => _buildContainer(); @@ -12,8 +13,8 @@ class OverallLearnProgress extends StatelessWidget { Widget _buildContainer() => Container( padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25), decoration: BoxDecoration( + color: color, borderRadius: BorderRadius.circular(4), - color: kcPrimaryColor.withOpacity(0.1), ), child: _buildProgressSection(), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index f6b0c3a..3038d01 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -18,6 +19,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_inappwebview_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterInappwebviewLinuxPlugin"); + flutter_inappwebview_linux_plugin_register_with_registrar(flutter_inappwebview_linux_registrar); g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f947226..f1eba05 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux file_selector_linux + flutter_inappwebview_linux flutter_secure_storage_linux record_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 791238f..99c8352 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -11,6 +11,7 @@ import connectivity_plus import file_selector_macos import firebase_core import firebase_messaging +import flutter_inappwebview_macos import flutter_local_notifications import flutter_secure_storage_darwin import google_sign_in_ios @@ -27,6 +28,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin")) + InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 4bb5c3c..eb73ab3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -558,6 +558,78 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + flutter_inappwebview: + dependency: "direct main" + description: + name: flutter_inappwebview + sha256: "3952d116ee93bad2946401377e7ade87b5ef200e95ecb5ba1affa1b6329a6867" + url: "https://pub.dev" + source: hosted + version: "6.2.0-beta.3" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: "8dfb76bd4e507112c3942c2272eeb01fab2e42be11374e5eb226f58698e7a04b" + url: "https://pub.dev" + source: hosted + version: "1.2.0-beta.3" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: ae8a78829398771be863aa3c8804a9d40728e1815e66c9c966f86d2cc3ae4fd9 + url: "https://pub.dev" + source: hosted + version: "1.2.0-beta.3" + flutter_inappwebview_linux: + dependency: transitive + description: + name: flutter_inappwebview_linux + sha256: "2e1a3b09bb911fb5a8bb155cb7f1eb1428a19b6e20363b9db48beef428b8cef5" + url: "https://pub.dev" + source: hosted + version: "0.1.0-beta.1" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: "545148cb5c46475ce669ab21621e9f2ad66e05f8e80b2cf49d4018879ab52393" + url: "https://pub.dev" + source: hosted + version: "1.2.0-beta.3" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: e3522c76e6760d1c0a9ff690e30e1503f226783d3277fa4d26675911977e9766 + url: "https://pub.dev" + source: hosted + version: "1.4.0-beta.3" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: e98b8875ccb6a3fd255873318db45c18ab135ed0ed22d20169abad9f5c810eb9 + url: "https://pub.dev" + source: hosted + version: "1.2.0-beta.3" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "902edd6f6326952af822e21aa928f7426d723d45c94c15e6ce3c2d5640d28ad7" + url: "https://pub.dev" + source: hosted + version: "0.7.0-beta.3" flutter_lints: dependency: "direct dev" description: @@ -1741,6 +1813,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.4.0" + vimeo_video_player: + dependency: "direct main" + description: + name: vimeo_video_player + sha256: b5dc8ad763489c94136e6080ba3ee89830742a48f5e7b2e28968f54d8c3734ad + url: "https://pub.dev" + source: hosted + version: "1.0.3" vm_service: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 128a562..1ee24a5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: yimaru_app description: A new Flutter project. publish_to: 'none' -version: 0.1.3+4 +version: 0.1.3+5 environment: sdk: '>=3.0.3 <4.0.0' @@ -38,6 +38,7 @@ dependencies: omni_datetime_picker: any json_serializable: ^6.8.0 waveform_recorder: ^1.8.0 + vimeo_video_player: ^1.0.3 permission_handler: ^12.0.1 firebase_messaging: ^16.1.1 cached_network_image: ^3.4.1 @@ -46,6 +47,7 @@ dependencies: flutter_secure_storage: ^10.0.0 flutter_timer_countdown: ^1.0.7 flutter_carousel_widget: ^3.1.0 + flutter_inappwebview: ^6.2.0-beta.3 flutter_local_notifications: ^20.1.0 internet_connection_checker_plus: ^2.9.1+2 diff --git a/test/helpers/test_helpers.mocks.dart b/test/helpers/test_helpers.mocks.dart index 550914e..33cdc91 100644 --- a/test/helpers/test_helpers.mocks.dart +++ b/test/helpers/test_helpers.mocks.dart @@ -8,40 +8,42 @@ 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 _i32; +import 'package:firebase_messaging/firebase_messaging.dart' as _i34; 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 _i27; +import 'package:permission_handler/permission_handler.dart' as _i29; 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 _i35; +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/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/user.dart' as _i12; import 'package:yimaru_app/services/api_service.dart' as _i13; -import 'package:yimaru_app/services/audio_player_service.dart' as _i36; +import 'package:yimaru_app/services/audio_player_service.dart' as _i38; import 'package:yimaru_app/services/authentication_service.dart' as _i11; -import 'package:yimaru_app/services/course_service.dart' as _i34; -import 'package:yimaru_app/services/dio_service.dart' as _i24; -import 'package:yimaru_app/services/google_auth_service.dart' as _i29; -import 'package:yimaru_app/services/image_downloader_service.dart' as _i30; -import 'package:yimaru_app/services/image_picker_service.dart' as _i28; -import 'package:yimaru_app/services/notification_service.dart' as _i31; -import 'package:yimaru_app/services/permission_handler_service.dart' as _i26; +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/secure_storage_service.dart' as _i3; -import 'package:yimaru_app/services/smart_auth_service.dart' as _i33; -import 'package:yimaru_app/services/status_checker_service.dart' as _i25; -import 'package:yimaru_app/services/voice_recorder_service.dart' as _i37; -import 'package:yimaru_app/ui/common/enmus.dart' as _i38; +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; // ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values @@ -1128,7 +1130,7 @@ class MockApiService extends _i1.Mock implements _i13.ApiService { @override _i9.Future> getCategories() => (super.noSuchMethod( Invocation.method( - #getCourseCategories, + #getCategories, [], ), returnValue: _i9.Future>.value(<_i15.Category>[]), @@ -1140,7 +1142,7 @@ class MockApiService extends _i1.Mock implements _i13.ApiService { _i9.Future> getSubcategories(int? id) => (super.noSuchMethod( Invocation.method( - #getCourseSubcategories, + #getSubcategories, [id], ), returnValue: @@ -1270,6 +1272,29 @@ class MockApiService extends _i1.Mock implements _i13.ApiService { returnValueForMissingStub: _i9.Future>.value(<_i23.Module>[]), ) as _i9.Future>); + + @override + _i9.Future> getSubmodules(int? id) => + (super.noSuchMethod( + Invocation.method( + #getSubmodules, + [id], + ), + returnValue: _i9.Future>.value(<_i24.Submodule>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i24.Submodule>[]), + ) as _i9.Future>); + + @override + _i9.Future> getLessons(int? id) => (super.noSuchMethod( + Invocation.method( + #getLessons, + [id], + ), + returnValue: _i9.Future>.value(<_i25.Lesson>[]), + returnValueForMissingStub: + _i9.Future>.value(<_i25.Lesson>[]), + ) as _i9.Future>); } /// A class which mocks [SecureStorageService]. @@ -1372,7 +1397,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 _i24.DioService { +class MockDioService extends _i1.Mock implements _i26.DioService { @override _i2.Dio get dio => (super.noSuchMethod( Invocation.getter(#dio), @@ -1391,7 +1416,7 @@ class MockDioService extends _i1.Mock implements _i24.DioService { /// /// See the documentation for Mockito's code generation for more information. class MockStatusCheckerService extends _i1.Mock - implements _i25.StatusCheckerService { + implements _i27.StatusCheckerService { @override _i3.SecureStorageService get storage => (super.noSuchMethod( Invocation.getter(#storage), @@ -1457,40 +1482,40 @@ class MockStatusCheckerService extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockPermissionHandlerService extends _i1.Mock - implements _i26.PermissionHandlerService { + implements _i28.PermissionHandlerService { @override - _i9.Future<_i27.PermissionStatus> requestPermission( - _i27.Permission? requestedPermission) => + _i9.Future<_i29.PermissionStatus> requestPermission( + _i29.Permission? requestedPermission) => (super.noSuchMethod( Invocation.method( #requestPermission, [requestedPermission], ), - returnValue: _i9.Future<_i27.PermissionStatus>.value( - _i27.PermissionStatus.denied), - returnValueForMissingStub: _i9.Future<_i27.PermissionStatus>.value( - _i27.PermissionStatus.denied), - ) as _i9.Future<_i27.PermissionStatus>); + returnValue: _i9.Future<_i29.PermissionStatus>.value( + _i29.PermissionStatus.denied), + returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value( + _i29.PermissionStatus.denied), + ) as _i9.Future<_i29.PermissionStatus>); @override - _i9.Future<_i27.PermissionStatus> request(_i27.Permission? permission) => + _i9.Future<_i29.PermissionStatus> request(_i29.Permission? permission) => (super.noSuchMethod( Invocation.method( #request, [permission], ), - returnValue: _i9.Future<_i27.PermissionStatus>.value( - _i27.PermissionStatus.denied), - returnValueForMissingStub: _i9.Future<_i27.PermissionStatus>.value( - _i27.PermissionStatus.denied), - ) as _i9.Future<_i27.PermissionStatus>); + returnValue: _i9.Future<_i29.PermissionStatus>.value( + _i29.PermissionStatus.denied), + returnValueForMissingStub: _i9.Future<_i29.PermissionStatus>.value( + _i29.PermissionStatus.denied), + ) as _i9.Future<_i29.PermissionStatus>); } /// A class which mocks [ImagePickerService]. /// /// See the documentation for Mockito's code generation for more information. class MockImagePickerService extends _i1.Mock - implements _i28.ImagePickerService { + implements _i30.ImagePickerService { @override _i9.Future gallery() => (super.noSuchMethod( Invocation.method( @@ -1515,7 +1540,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 _i29.GoogleAuthService { +class MockGoogleAuthService extends _i1.Mock implements _i31.GoogleAuthService { @override int get listenersCount => (super.noSuchMethod( Invocation.getter(#listenersCount), @@ -1585,7 +1610,7 @@ class MockGoogleAuthService extends _i1.Mock implements _i29.GoogleAuthService { /// /// See the documentation for Mockito's code generation for more information. class MockImageDownloaderService extends _i1.Mock - implements _i30.ImageDownloaderService { + implements _i32.ImageDownloaderService { @override _i9.Future downloader(String? networkImage) => (super.noSuchMethod( Invocation.method( @@ -1614,7 +1639,7 @@ class MockImageDownloaderService extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockNotificationService extends _i1.Mock - implements _i31.NotificationService { + implements _i33.NotificationService { @override _i9.Future initialize() => (super.noSuchMethod( Invocation.method( @@ -1636,7 +1661,7 @@ class MockNotificationService extends _i1.Mock ) as _i9.Future); @override - _i9.Future showNotification(_i32.RemoteMessage? message) => + _i9.Future showNotification(_i34.RemoteMessage? message) => (super.noSuchMethod( Invocation.method( #showNotification, @@ -1670,7 +1695,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 _i33.SmartAuthService { +class MockSmartAuthService extends _i1.Mock implements _i35.SmartAuthService { @override bool get listenForMultipleSms => (super.noSuchMethod( Invocation.getter(#listenForMultipleSms), @@ -1702,26 +1727,26 @@ class MockSmartAuthService extends _i1.Mock implements _i33.SmartAuthService { /// A class which mocks [CourseService]. /// /// See the documentation for Mockito's code generation for more information. -class MockCourseService extends _i1.Mock implements _i34.CourseService { +class MockCourseService extends _i1.Mock implements _i36.CourseService { @override - _i9.Future> getCoursesDetail(int? id) => + _i9.Future> getCoursesDetail(int? id) => (super.noSuchMethod( Invocation.method( #getCoursesDetail, [id], ), returnValue: - _i9.Future>.value(<_i35.CourseDetail>[]), + _i9.Future>.value(<_i37.CourseDetail>[]), returnValueForMissingStub: - _i9.Future>.value(<_i35.CourseDetail>[]), - ) as _i9.Future>); + _i9.Future>.value(<_i37.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 _i36.AudioPlayerService { + implements _i38.AudioPlayerService { @override _i4.AudioPlayer get player => (super.noSuchMethod( Invocation.getter(#player), @@ -1845,13 +1870,13 @@ class MockAudioPlayerService extends _i1.Mock /// /// See the documentation for Mockito's code generation for more information. class MockVoiceRecorderService extends _i1.Mock - implements _i37.VoiceRecorderService { + implements _i39.VoiceRecorderService { @override - _i38.VoiceRecordingState get recordingState => (super.noSuchMethod( + _i40.VoiceRecordingState get recordingState => (super.noSuchMethod( Invocation.getter(#recordingState), - returnValue: _i38.VoiceRecordingState.pending, - returnValueForMissingStub: _i38.VoiceRecordingState.pending, - ) as _i38.VoiceRecordingState); + returnValue: _i40.VoiceRecordingState.pending, + returnValueForMissingStub: _i40.VoiceRecordingState.pending, + ) as _i40.VoiceRecordingState); @override _i5.WaveformRecorderController get waveController => (super.noSuchMethod( diff --git a/test/viewmodels/learn_submodule_viewmodel_test.dart b/test/viewmodels/learn_submodule_viewmodel_test.dart new file mode 100644 index 0000000..1668467 --- /dev/null +++ b/test/viewmodels/learn_submodule_viewmodel_test.dart @@ -0,0 +1,11 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:yimaru_app/app/app.locator.dart'; + +import '../helpers/test_helpers.dart'; + +void main() { + group('LearnSubmoduleViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 99cf51a..18488b6 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FileSelectorWindows")); FirebaseCorePluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FirebaseCorePluginCApi")); + FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); PermissionHandlerWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index ba56a87..b0a64d4 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus file_selector_windows firebase_core + flutter_inappwebview_windows flutter_secure_storage_windows permission_handler_windows record_windows