From 80c9d014daff2e4214886feaee990b75b958d4fe Mon Sep 17 00:00:00 2001 From: BisratHailu Date: Thu, 28 May 2026 17:35:43 +0300 Subject: [PATCH] feat(learn): Integrate progress tracker --- assets/translations/am.json | 3 +- assets/translations/en.json | 5 +- lib/main.dart | 4 + lib/models/access.dart | 4 +- lib/models/access.g.dart | 2 +- lib/models/user.dart | 39 +++--- lib/models/user.g.dart | 2 + lib/services/dio_service.dart | 2 +- lib/services/learn_service.dart | 28 ++++- lib/ui/common/enmus.dart | 1 + .../common/translations/codegen_loader.g.dart | 8 +- lib/ui/common/translations/locale_keys.g.dart | 1 + lib/ui/views/arif_pay/arif_pay_view.dart | 12 +- lib/ui/views/arif_pay/arif_pay_viewmodel.dart | 35 +++++- .../views/learn_course/learn_course_view.dart | 114 +++++++++++------ .../views/learn_lesson/learn_lesson_view.dart | 44 +++++-- .../learn_lesson/learn_lesson_viewmodel.dart | 25 +++- .../views/learn_module/learn_module_view.dart | 119 +++++++++++++----- .../learn_module/learn_module_viewmodel.dart | 6 + .../learn_practice_viewmodel.dart | 9 +- .../interact_learn_practice_screen.dart | 1 + .../screens/learning_goal_form_screen.dart | 93 ++++++++++---- lib/ui/widgets/custom_large_radio_button.dart | 88 +++++++------ lib/ui/widgets/finish_practice_sheet.dart | 8 +- lib/ui/widgets/learn_course_tile.dart | 10 +- lib/ui/widgets/learn_lesson_tile.dart | 2 + lib/ui/widgets/learn_module_tile.dart | 13 +- lib/ui/widgets/overall_progress_wrapper.dart | 8 +- pubspec.yaml | 2 +- 29 files changed, 489 insertions(+), 199 deletions(-) diff --git a/assets/translations/am.json b/assets/translations/am.json index 35660ec..7c1f645 100644 --- a/assets/translations/am.json +++ b/assets/translations/am.json @@ -182,8 +182,9 @@ "lets_start_practice": "ልምምድህን እንጀምር", "welcome_abroad": "እንኳን ደህና መጣህ", "ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።", - "finish": "አጠናቅቅ" + "finish": "አጠናቅቅ", + "finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።" diff --git a/assets/translations/en.json b/assets/translations/en.json index e1c2f49..7ce626a 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -125,7 +125,7 @@ "open_in_telegram": "Open in Telegram", "search_for": "Search for", "current_level": "Current Level", - "keep_up_the_great_work": "Keep up the great work! You\\'re doing amazing.", + "keep_up_the_great_work": "Keep up the great work! You're doing amazing.", "no_practice_available": "No practice available!", "begin_module_practice": "Begin Module Practice", "lets_practice_lesson": "Let’s Practice", @@ -182,5 +182,6 @@ "lets_start_practice": "Let's start your practice", "welcome_abroad": "Welcome aboard", "ready_to_explore": "You’re ready to explore your personalized lessons.", - "finish": "Finish" + "finish": "Finish", + "finish_all_practice": "Finish all the practices in the lessons to take this practice" } diff --git a/lib/main.dart b/lib/main.dart index b56ef67..eee16d1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:toastification/toastification.dart'; import 'package:yimaru_app/app/app.bottomsheets.dart'; import 'package:yimaru_app/app/app.dialogs.dart'; @@ -13,12 +14,15 @@ import 'firebase_options.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); + await setupLocator(); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await locator().initialize(); await EasyLocalization.ensureInitialized(); setupDialogUi(); setupBottomSheetUi(); + await SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); runApp( EasyLocalization( supportedLocales: const [ diff --git a/lib/models/access.dart b/lib/models/access.dart index 9bb0997..0644dbc 100644 --- a/lib/models/access.dart +++ b/lib/models/access.dart @@ -21,7 +21,7 @@ class Access { final int? progressPercent; @JsonKey(name: 'progress_percent_precise') - final int? progressPercentPrecise; + final double? progressPercentPrecise; const Access({ this.reason, @@ -40,7 +40,7 @@ class Access { bool? isAccessible, int? completedCount, int? progressPercent, - int? progressPercentPrecise, + double? progressPercentPrecise, }) { return Access( reason: reason ?? this.reason, diff --git a/lib/models/access.g.dart b/lib/models/access.g.dart index 27f3d64..76dd54b 100644 --- a/lib/models/access.g.dart +++ b/lib/models/access.g.dart @@ -14,7 +14,7 @@ Access _$AccessFromJson(Map json) => Access( completedCount: (json['completed_count'] as num?)?.toInt(), progressPercent: (json['progress_percent'] as num?)?.toInt(), progressPercentPrecise: - (json['progress_percent_precise'] as num?)?.toInt(), + (json['progress_percent_precise'] as num?)?.toDouble(), ); Map _$AccessToJson(Access instance) => { diff --git a/lib/models/user.dart b/lib/models/user.dart index 7c363a1..b290e15 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -43,23 +43,22 @@ class User { @JsonKey(name: 'profile_picture_url') final String? profilePicture; - const User({ - this.email, - this.region, - this.gender, - this.userId, - this.country, - this.lastName, - this.birthday, - this.firstName, - this.occupation, - this.accessToken, - this.refreshToken, - this.profilePicture, - this.userInfoLoaded, - this.profileCompleted, - this.subscriptionStatus - }); + const User( + {this.email, + this.region, + this.gender, + this.userId, + this.country, + this.lastName, + this.birthday, + this.firstName, + this.occupation, + this.accessToken, + this.refreshToken, + this.profilePicture, + this.userInfoLoaded, + this.profileCompleted, + this.subscriptionStatus}); User copyWith( {int? userId, @@ -75,7 +74,8 @@ class User { String? refreshToken, bool? userInfoLoaded, bool? profileCompleted, - String? profilePicture}) => + String? profilePicture, + String? subscriptionStatus}) => User( email: email ?? this.email, userId: userId ?? this.userId, @@ -90,7 +90,8 @@ class User { refreshToken: refreshToken ?? this.refreshToken, userInfoLoaded: userInfoLoaded ?? this.userInfoLoaded, profilePicture: profilePicture ?? this.profilePicture, - profileCompleted: profileCompleted ?? this.profileCompleted); + profileCompleted: profileCompleted ?? this.profileCompleted, + subscriptionStatus: subscriptionStatus ?? this.subscriptionStatus); factory User.fromJson(Map json) => _$UserFromJson(json); diff --git a/lib/models/user.g.dart b/lib/models/user.g.dart index 312d7d5..bf31905 100644 --- a/lib/models/user.g.dart +++ b/lib/models/user.g.dart @@ -21,6 +21,7 @@ User _$UserFromJson(Map json) => User( profilePicture: json['profile_picture_url'] as String?, userInfoLoaded: json['userInfoLoaded'] as bool?, profileCompleted: json['profile_completed'] as bool?, + subscriptionStatus: json['subscription_status'] as String?, ); Map _$UserToJson(User instance) => { @@ -37,5 +38,6 @@ Map _$UserToJson(User instance) => { 'access_token': instance.accessToken, 'refresh_token': instance.refreshToken, 'profile_completed': instance.profileCompleted, + 'subscription_status': instance.subscriptionStatus, 'profile_picture_url': instance.profilePicture, }; diff --git a/lib/services/dio_service.dart b/lib/services/dio_service.dart index 6bf2d54..675b398 100644 --- a/lib/services/dio_service.dart +++ b/lib/services/dio_service.dart @@ -27,7 +27,7 @@ class DioService { DioService() { _dio.options ..baseUrl = kBaseUrl - ..connectTimeout = const Duration(seconds: 5) + ..connectTimeout = const Duration(seconds: 10) ..receiveTimeout = const Duration(seconds: 15); _dio.interceptors.add( diff --git a/lib/services/learn_service.dart b/lib/services/learn_service.dart index 5394ee9..a10a7cf 100644 --- a/lib/services/learn_service.dart +++ b/lib/services/learn_service.dart @@ -17,7 +17,7 @@ class LearnService with ListenableServiceMixin { // Initialization learnService() { - listenToReactiveValues([_programs, _lessons, _modules]); + listenToReactiveValues([_programs,_courses, _lessons, _modules]); } // Learn program @@ -89,7 +89,6 @@ class LearnService with ListenableServiceMixin { // Learn progress Future getLearnProgressSummary() async { final summaries = await _apiService.getProgressSummary(); - print('MY SUMMARIES: ${summaries.length}'); /// PROGRAM ACCESS MAP final Map programAccessMap = {}; @@ -149,6 +148,11 @@ class LearnService with ListenableServiceMixin { ); }).toList(); + print('MY SUMMARIES - COMPLETED COUNT: ${_modules.first.access?.completedCount}'); + print('PROGRESS PERCENT: ${_modules.first.access?.progressPercent}'); + + + /// UPDATE LESSONS _lessons = _lessons.map((lesson) { return lesson.copyWith( @@ -158,4 +162,24 @@ class LearnService with ListenableServiceMixin { notifyListeners(); } + + LearnModule? getLearnModuleById(int id) { + try { + return _modules.firstWhere((e) => e.id == id); + } catch (_) { + return null; + } + + + } + + LearnCourse? getLearnCourseById(int id) { + try { + return _courses.firstWhere((e) => e.id == id); + } catch (_) { + return null; + } + + + } } diff --git a/lib/ui/common/enmus.dart b/lib/ui/common/enmus.dart index 2fdcab4..7eb039a 100644 --- a/lib/ui/common/enmus.dart +++ b/lib/ui/common/enmus.dart @@ -39,6 +39,7 @@ enum StateObjects { learnModules, learnCourses, profileImage, + paymentStatus, profileDetail, learnPrograms, courseLessons, diff --git a/lib/ui/common/translations/codegen_loader.g.dart b/lib/ui/common/translations/codegen_loader.g.dart index f95e766..6ef5b32 100644 --- a/lib/ui/common/translations/codegen_loader.g.dart +++ b/lib/ui/common/translations/codegen_loader.g.dart @@ -198,7 +198,8 @@ class CodegenLoader extends AssetLoader{ "lets_start_practice": "ልምምድህን እንጀምር", "welcome_abroad": "እንኳን ደህና መጣህ", "ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።", - "finish": "አጠናቅቅ" + "finish": "አጠናቅቅ", + "finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።" }; static const Map _en = { "loading": "Loading", @@ -327,7 +328,7 @@ static const Map _en = { "open_in_telegram": "Open in Telegram", "search_for": "Search for", "current_level": "Current Level", - "keep_up_the_great_work": "Keep up the great work! You\\'re doing amazing.", + "keep_up_the_great_work": "Keep up the great work! You're doing amazing.", "no_practice_available": "No practice available!", "begin_module_practice": "Begin Module Practice", "lets_practice_lesson": "Let’s Practice", @@ -384,7 +385,8 @@ static const Map _en = { "lets_start_practice": "Let's start your practice", "welcome_abroad": "Welcome aboard", "ready_to_explore": "You’re ready to explore your personalized lessons.", - "finish": "Finish" + "finish": "Finish", + "finish_all_practice": "Finish all the practices in the lessons to take this practice" }; static const Map> mapLocales = {"am": _am, "en": _en}; } diff --git a/lib/ui/common/translations/locale_keys.g.dart b/lib/ui/common/translations/locale_keys.g.dart index f7dcb52..b2be009 100644 --- a/lib/ui/common/translations/locale_keys.g.dart +++ b/lib/ui/common/translations/locale_keys.g.dart @@ -185,5 +185,6 @@ abstract class LocaleKeys { static const welcome_abroad = 'welcome_abroad'; static const ready_to_explore = 'ready_to_explore'; static const finish = 'finish'; + static const finish_all_practice = 'finish_all_practice'; } diff --git a/lib/ui/views/arif_pay/arif_pay_view.dart b/lib/ui/views/arif_pay/arif_pay_view.dart index ffce663..f4f224a 100644 --- a/lib/ui/views/arif_pay/arif_pay_view.dart +++ b/lib/ui/views/arif_pay/arif_pay_view.dart @@ -13,12 +13,16 @@ class ArifPayView extends StackedView { const ArifPayView({Key? key, required this.phone}) : super(key: key); - void _pop(ArifPayViewModel viewModel) => viewModel.pop; void _error(ArifPayViewModel viewModel) => viewModel.pop(); - Future _success(ArifPayViewModel viewModel) async => - await viewModel.replaceWithHome(); + + Future _success(ArifPayViewModel viewModel) async { + + await viewModel.updatePaymentStatus(); + + await viewModel.replaceWithHome(); + } @override void onViewModelReady(ArifPayViewModel viewModel) async { @@ -45,6 +49,8 @@ class ArifPayView extends StackedView { ? const PageLoadingIndicator() : _buildScaffold(viewModel); + + Widget _buildScaffold(ArifPayViewModel viewModel) => SafeArea(child: _buildBody(viewModel)); diff --git a/lib/ui/views/arif_pay/arif_pay_viewmodel.dart b/lib/ui/views/arif_pay/arif_pay_viewmodel.dart index 540fd6f..2f7e7d7 100644 --- a/lib/ui/views/arif_pay/arif_pay_viewmodel.dart +++ b/lib/ui/views/arif_pay/arif_pay_viewmodel.dart @@ -5,10 +5,13 @@ import 'package:yimaru_app/ui/common/enmus.dart'; import '../../../app/app.locator.dart'; import '../../../app/app.router.dart'; import '../../../models/learn_subscription_request.dart'; +import '../../../models/user.dart'; import '../../../services/api_service.dart'; +import '../../../services/authentication_service.dart'; import '../../../services/status_checker_service.dart'; +import '../../common/ui_helpers.dart'; -class ArifPayViewModel extends BaseViewModel { +class ArifPayViewModel extends ReactiveViewModel { // Dependency injection final _apiService = locator(); @@ -17,6 +20,16 @@ class ArifPayViewModel extends BaseViewModel { final _navigationService = locator(); + final _authenticationService = locator(); + + @override + List get listenableServices => + [_authenticationService]; + + // Current user + User? get _user => _authenticationService.user; + + User? get user => _user; // Learn subscription request LearnSubscriptionRequest? _request; @@ -36,6 +49,7 @@ class ArifPayViewModel extends BaseViewModel { busyObject: StateObjects.learnSubscription); Future _createLearnSubscriptionRequest(String phone) async { + print('MY SUMMARIES : PAYMENT'); if (await _statusChecker.checkConnection()) { Map data = { 'plan_id': 1, @@ -53,4 +67,23 @@ class ArifPayViewModel extends BaseViewModel { } } + // Update payment status + Future updatePaymentStatus() async => await runBusyFuture(_updatePaymentStatus(), + busyObject: StateObjects.learnSubscription); + + Future _updatePaymentStatus() async { + + Map response = {}; + + response = await _apiService.getProfileData(_user?.userId); + + if (response['status'] == ResponseStatus.success) { + User user = response['data'] as User; + await _authenticationService.saveUserData(user); + + } + + + } + } diff --git a/lib/ui/views/learn_course/learn_course_view.dart b/lib/ui/views/learn_course/learn_course_view.dart index 572a93c..91dbc5f 100644 --- a/lib/ui/views/learn_course/learn_course_view.dart +++ b/lib/ui/views/learn_course/learn_course_view.dart @@ -6,14 +6,38 @@ import '../../common/app_colors.dart'; import '../../common/enmus.dart'; import '../../common/ui_helpers.dart'; import '../../widgets/custom_circular_progress_indicator.dart'; +import '../../widgets/finish_practice_sheet.dart'; import '../../widgets/learn_course_tile.dart'; import '../../widgets/small_app_bar.dart'; import 'learn_course_viewmodel.dart'; class LearnCourseView extends StackedView { final int id; + const LearnCourseView({Key? key, required this.id}) : super(key: key); + + Future _onPractice({required BuildContext context, + required LearnCourse course, + required LearnCourseViewModel viewModel}) async { + if (course.access?.completedCount == course.access?.totalCount) { + await viewModel.navigateToLearnPractice( + id: course.id ?? 0, + level: course.name ?? ''); + } else { + await _showSheet(context: context, viewModel: viewModel); + } + } + + Future _showSheet({required BuildContext context, + required LearnCourseViewModel viewModel}) async => + await showModalBottomSheet( + context: context, + backgroundColor: kcTransparent, + builder: (_) => _buildSheet(viewModel), + ); + + @override void onViewModelReady(LearnCourseViewModel viewModel) async { await viewModel.getLearnCourses(id); @@ -25,88 +49,108 @@ class LearnCourseView extends StackedView { LearnCourseViewModel(); @override - Widget builder( - BuildContext context, - LearnCourseViewModel viewModel, - Widget? child, - ) => - _buildScaffoldWrapper(viewModel); + Widget builder(BuildContext context, + LearnCourseViewModel viewModel, + Widget? child,) => + _buildScaffoldWrapper(context: context,viewModel: viewModel); - Widget _buildScaffoldWrapper(LearnCourseViewModel viewModel) => Scaffold( + Widget _buildScaffoldWrapper({required BuildContext context, + required LearnCourseViewModel viewModel}) => + Scaffold( backgroundColor: kcBackgroundColor, - body: _buildScaffoldContainer(viewModel), + body: _buildScaffoldContainer(context: context,viewModel: viewModel), ); - Widget _buildScaffoldContainer(LearnCourseViewModel viewModel) => Container( + Widget _buildScaffoldContainer({required BuildContext context, + required LearnCourseViewModel viewModel}) => + Container( decoration: bgDecoration, - child: _buildScaffold(viewModel), + child: _buildScaffold(context: context,viewModel: viewModel), ); - Widget _buildScaffold(LearnCourseViewModel viewModel) => - SafeArea(child: _buildBody(viewModel)); + Widget _buildScaffold({required BuildContext context, + required LearnCourseViewModel viewModel}) => + SafeArea(child: _buildBody(context: context,viewModel: viewModel)); - Widget _buildBody(LearnCourseViewModel viewModel) => Padding( + Widget _buildBody({required BuildContext context, + required LearnCourseViewModel viewModel}) => + Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), + child: _buildColumn(context: context,viewModel: viewModel), ); - Widget _buildColumn(LearnCourseViewModel viewModel) => Column( + Widget _buildColumn({required BuildContext context, + required LearnCourseViewModel viewModel}) => + Column( children: [ verticalSpaceMedium, _buildAppBar(viewModel), verticalSpaceMedium, - _buildCoursesColumnWrapper(viewModel) + _buildCoursesColumnWrapper(context: context,viewModel: viewModel) ], ); - Widget _buildAppBar(LearnCourseViewModel viewModel) => SmallAppBar( + Widget _buildAppBar(LearnCourseViewModel viewModel) => + SmallAppBar( onPop: viewModel.pop, showBackButton: true, ); - Widget _buildCoursesColumnWrapper(LearnCourseViewModel viewModel) => - Expanded(child: _buildLevelsColumnScrollView(viewModel)); + Widget _buildCoursesColumnWrapper({required BuildContext context, + required LearnCourseViewModel viewModel}) => + Expanded(child: _buildLevelsColumnScrollView(context: context,viewModel: viewModel)); - Widget _buildLevelsColumnScrollView(LearnCourseViewModel viewModel) => + Widget _buildLevelsColumnScrollView({required BuildContext context, + required LearnCourseViewModel viewModel}) => SingleChildScrollView( - child: _buildListViewBuilder(viewModel), + child: _buildListViewBuilder(context: context,viewModel: viewModel), ); - Widget _buildListViewBuilder(LearnCourseViewModel viewModel) => + Widget _buildListViewBuilder({required BuildContext context, + required LearnCourseViewModel viewModel}) => viewModel.busy(StateObjects.learnCourses) ? _buildProgressIndicator() - : _buildListView(viewModel); + : _buildListView(context: context,viewModel: viewModel); - Widget _buildProgressIndicator() => const Center( + Widget _buildProgressIndicator() => + const Center( child: CustomCircularProgressIndicator(color: kcPrimaryColor), ); - Widget _buildListView(LearnCourseViewModel viewModel) => ListView.separated( + Widget _buildListView({required BuildContext context, + required LearnCourseViewModel viewModel}) => + ListView.separated( shrinkWrap: true, itemCount: viewModel.courses.length, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _buildTile( - course: viewModel.courses[index], - onViewTap: () async => + itemBuilder: (context, index) => + _buildTile( + course: viewModel.courses[index], + + onPracticeTap: () async => + await _onPractice( + context: context, + viewModel: viewModel, + course: viewModel.courses[index] + ), + onViewTap: () async => await viewModel.navigateToLearnModule(viewModel.courses[index]), - onLockTap: () async => await viewModel.navigateToLearnSubscription(), - onPracticeTap: () async => await viewModel.navigateToLearnPractice( - id: viewModel.courses[index].id ?? 0, - level: viewModel.courses[index].name ?? ''), - ), + ), separatorBuilder: (context, index) => verticalSpaceSmall, ); Widget _buildTile({ required LearnCourse course, required GestureTapCallback onViewTap, - required GestureTapCallback onLockTap, required GestureTapCallback onPracticeTap, }) => LearnCourseTile( course: course, onViewTap: onViewTap, - onLockTap: onLockTap, onPracticeTap: onPracticeTap, ); + + + Widget _buildSheet(LearnCourseViewModel viewModel) => + FinishPracticeSheet(onTap: viewModel.pop); } diff --git a/lib/ui/views/learn_lesson/learn_lesson_view.dart b/lib/ui/views/learn_lesson/learn_lesson_view.dart index 3f04346..a04ff2f 100644 --- a/lib/ui/views/learn_lesson/learn_lesson_view.dart +++ b/lib/ui/views/learn_lesson/learn_lesson_view.dart @@ -20,6 +20,24 @@ class LearnLessonView extends StackedView { const LearnLessonView({Key? key, required this.module}) : super(key: key); + Future _onPractice( + {required int index, + required LearnLesson lesson, + required LearnLessonViewModel viewModel}) async { + if (index > 1) { + + print(index); + print(viewModel.user?.subscriptionStatus); + if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') { + await viewModel.navigateToLearnPractice(lesson.id ?? 0); + } else { + await viewModel.navigateToLearnSubscription(); + } + } else { + await viewModel.navigateToLearnPractice(lesson.id ?? 0); + } + } + @override void onViewModelReady(LearnLessonViewModel viewModel) async { await viewModel.getLessons(module.id ?? 0); @@ -124,7 +142,7 @@ class LearnLessonView extends StackedView { verticalSpaceTiny, _buildSubtitle(), verticalSpaceSmall, - _buildModuleProgress(), + _buildModuleProgress(viewModel), verticalSpaceLarge, _buildMotivationCard(), verticalSpaceLarge, @@ -143,10 +161,19 @@ class LearnLessonView extends StackedView { style: style14DG500, ); - Widget _buildModuleProgress() => ModuleProgress( - total: module.access?.totalCount ?? 0, - completed: module.access?.completedCount ?? 0, - progress: module.access?.progressPercent ?? 0, + Widget _buildModuleProgress(LearnLessonViewModel viewModel) => ModuleProgress( + total: (viewModel.getUpdatedLearnModule(module.id ?? 0) ?? module) + .access + ?.totalCount ?? + 0, + completed: (viewModel.getUpdatedLearnModule(module.id ?? 0) ?? module) + .access + ?.completedCount ?? + 0, + progress: (viewModel.getUpdatedLearnModule(module.id ?? 0) ?? module) + .access + ?.progressPercent ?? + 0, ); Widget _buildMotivationCard() => const MotivationCard(); @@ -172,13 +199,16 @@ class LearnLessonView extends StackedView { itemBuilder: (context, index) => _buildTile( index: index, lesson: viewModel.lessons[index], + onPracticeTap: () async => await _onPractice( + index: index, + viewModel: viewModel, + lesson: viewModel.lessons[index], + ), onLessonTap: () async => await viewModel.navigateToLearnLessonDetail( module: module, lesson: viewModel.lessons[index], hasPractice: index != viewModel.lessons.length - 1 ? true : false), - onPracticeTap: () async => await viewModel - .navigateToLearnPractice(viewModel.lessons[index].id ?? 0), ), ); diff --git a/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart b/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart index 4f93865..3d19424 100644 --- a/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart +++ b/lib/ui/views/learn_lesson/learn_lesson_viewmodel.dart @@ -8,6 +8,8 @@ import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import '../../../app/app.locator.dart'; import '../../../models/learn_module.dart'; +import '../../../models/user.dart'; +import '../../../services/authentication_service.dart'; import '../../../services/learn_service.dart'; import '../../../services/status_checker_service.dart'; import '../../common/helper_functions.dart'; @@ -20,8 +22,19 @@ class LearnLessonViewModel extends ReactiveViewModel { final _navigationService = locator(); + final _authenticationService = locator(); + + + + @override - List get listenableServices => [_learnService]; + List get listenableServices => [_learnService,_authenticationService]; + + + // Current user + User? get _user => _authenticationService.user; + + User? get user => _user; // Learn lessons @@ -36,6 +49,8 @@ class LearnLessonViewModel extends ReactiveViewModel { // Navigation void pop() => _navigationService.back(); + + Future navigateToLearnPractice(int id) async => await _navigationService.navigateToLearnPracticeView( id: id, @@ -45,6 +60,10 @@ class LearnLessonViewModel extends ReactiveViewModel { subtitle: LocaleKeys.ask_you_few_actions.tr(), ); + + Future navigateToLearnSubscription() async => + await _navigationService.navigateToLearnSubscriptionView(); + Future navigateToLearnLessonDetail( {required bool hasPractice, required LearnLesson lesson, @@ -65,6 +84,10 @@ class LearnLessonViewModel extends ReactiveViewModel { } } + // Get module + LearnModule? getUpdatedLearnModule(int id) { + return _learnService.getLearnModuleById(id); + } //Refresh image Future refreshLessonImages(List lessons) async { for (final lesson in lessons) { diff --git a/lib/ui/views/learn_module/learn_module_view.dart b/lib/ui/views/learn_module/learn_module_view.dart index 8213654..22d700b 100644 --- a/lib/ui/views/learn_module/learn_module_view.dart +++ b/lib/ui/views/learn_module/learn_module_view.dart @@ -11,14 +11,35 @@ import '../../common/app_colors.dart'; import '../../common/enmus.dart'; import '../../common/ui_helpers.dart'; import '../../widgets/custom_circular_progress_indicator.dart'; +import '../../widgets/finish_practice_sheet.dart'; import '../../widgets/small_app_bar.dart'; import 'learn_module_viewmodel.dart'; class LearnModuleView extends StackedView { final LearnCourse course; - const LearnModuleView({Key? key, required this.course}) : super(key: key); + Future _onPractice( + {required BuildContext context, + required LearnModule module, + required LearnModuleViewModel viewModel}) async { + if (module.access?.completedCount == module.access?.totalCount) { + await viewModel.navigateToLearnPractice( + id: module.id ?? 0, module: module.name ?? ''); + } else { + await _showSheet(context: context, viewModel: viewModel); + } + } + + Future _showSheet( + {required BuildContext context, + required LearnModuleViewModel viewModel}) async => + await showModalBottomSheet( + context: context, + backgroundColor: kcTransparent, + builder: (_) => _buildSheet(viewModel), + ); + @override void onViewModelReady(LearnModuleViewModel viewModel) async { await viewModel.getLearnModules(course.id ?? 0); @@ -35,32 +56,46 @@ class LearnModuleView extends StackedView { LearnModuleViewModel viewModel, Widget? child, ) => - _buildScaffoldWrapper(viewModel); + _buildScaffoldWrapper(context: context, viewModel: viewModel); - Widget _buildScaffoldWrapper(LearnModuleViewModel viewModel) => Scaffold( + Widget _buildScaffoldWrapper( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + Scaffold( backgroundColor: kcBackgroundColor, - body: _buildScaffoldContainer(viewModel), + body: _buildScaffoldContainer(context: context, viewModel: viewModel), ); - Widget _buildScaffoldContainer(LearnModuleViewModel viewModel) => Container( + Widget _buildScaffoldContainer( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + Container( decoration: bgDecoration, - child: _buildScaffold(viewModel), + child: _buildScaffold(context: context, viewModel: viewModel), ); - Widget _buildScaffold(LearnModuleViewModel viewModel) => - SafeArea(child: _buildBody(viewModel)); + Widget _buildScaffold( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + SafeArea(child: _buildBody(context: context, viewModel: viewModel)); - Widget _buildBody(LearnModuleViewModel viewModel) => Padding( + Widget _buildBody( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), + child: _buildColumn(context: context, viewModel: viewModel), ); - Widget _buildColumn(LearnModuleViewModel viewModel) => Column( + Widget _buildColumn( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + Column( children: [ verticalSpaceMedium, _buildAppBar(viewModel), verticalSpaceMedium, - _buildModulesColumnWrapper(viewModel), + _buildModulesColumnWrapper(context: context, viewModel: viewModel), ], ); @@ -69,28 +104,41 @@ class LearnModuleView extends StackedView { showBackButton: true, ); - Widget _buildModulesColumnWrapper(LearnModuleViewModel viewModel) => - Expanded(child: _buildLevelsColumnScrollView(viewModel)); + Widget _buildModulesColumnWrapper( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + Expanded( + child: _buildLevelsColumnScrollView( + context: context, viewModel: viewModel)); - Widget _buildLevelsColumnScrollView(LearnModuleViewModel viewModel) => + Widget _buildLevelsColumnScrollView( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => SingleChildScrollView( - child: _buildLevelsColumn(viewModel), + child: _buildLevelsColumn(context: context, viewModel: viewModel), ); - Widget _buildLevelsColumn(LearnModuleViewModel viewModel) => Column( + Widget _buildLevelsColumn( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, - children: _buildLevelsColumnChildren(viewModel), + children: + _buildLevelsColumnChildren(context: context, viewModel: viewModel), ); - List _buildLevelsColumnChildren(LearnModuleViewModel viewModel) => [ + List _buildLevelsColumnChildren( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + [ verticalSpaceSmall, _buildTitle(), _buildSubtitle(), verticalSpaceMedium, - _buildOverallProgress(), + _buildOverallProgress(viewModel), verticalSpaceMedium, - _buildListViewBuilder(viewModel) + _buildListViewBuilder(context: context, viewModel: viewModel) ]; Widget _buildTitle() => Text( @@ -103,30 +151,38 @@ class LearnModuleView extends StackedView { style: style14P400, ); - Widget _buildOverallProgress() => OverallProgress( + Widget _buildOverallProgress(LearnModuleViewModel viewModel) => OverallProgress( indicatorBackgroundColor: kcWhite, - progress: course.access?.progressPercent ?? 0, - backgroundColor: kcPrimaryColor.withOpacity(0.1), + backgroundColor: kcPrimaryColor.withOpacity(0.1), + progress: + (viewModel.getUpdatedLearnCourse(course.id ?? 0) ?? course).access?.progressPercent ?? 0, ); - Widget _buildListViewBuilder(LearnModuleViewModel viewModel) => + Widget _buildListViewBuilder( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => viewModel.busy(StateObjects.learnModules) ? _buildProgressIndicator() - : _buildListView(viewModel); + : _buildListView(context: context, viewModel: viewModel); Widget _buildProgressIndicator() => const Center( child: CustomCircularProgressIndicator(color: kcPrimaryColor), ); - Widget _buildListView(LearnModuleViewModel viewModel) => ListView.builder( + Widget _buildListView( + {required BuildContext context, + required LearnModuleViewModel viewModel}) => + ListView.builder( shrinkWrap: true, itemCount: viewModel.modules.length, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) => _buildTile( module: viewModel.modules[index], - onPracticeTap: () async => await viewModel.navigateToLearnPractice( - id: viewModel.modules[index].id ?? 0, - module: viewModel.modules[index].name ?? ''), + onPracticeTap: () async => await _onPractice( + context: context, + viewModel: viewModel, + module: viewModel.modules[index], + ), onModuleTap: () async => await viewModel.navigateToLearnLesson(viewModel.modules[index]), ), @@ -141,4 +197,7 @@ class LearnModuleView extends StackedView { module: module, onModuleTap: onModuleTap, onPracticeTap: onPracticeTap); + + Widget _buildSheet(LearnModuleViewModel viewModel) => + FinishPracticeSheet(onTap: viewModel.pop); } diff --git a/lib/ui/views/learn_module/learn_module_viewmodel.dart b/lib/ui/views/learn_module/learn_module_viewmodel.dart index fc5f771..babf34c 100644 --- a/lib/ui/views/learn_module/learn_module_viewmodel.dart +++ b/lib/ui/views/learn_module/learn_module_viewmodel.dart @@ -6,6 +6,7 @@ import 'package:yimaru_app/models/learn_module.dart'; import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import '../../../app/app.locator.dart'; +import '../../../models/learn_course.dart'; import '../../../services/learn_service.dart'; import '../../../services/status_checker_service.dart'; import '../../common/enmus.dart'; @@ -61,6 +62,11 @@ class LearnModuleViewModel extends ReactiveViewModel { } } + // Get course + LearnCourse? getUpdatedLearnCourse(int id) { + return _learnService.getLearnCourseById(id); + } + //Refresh image Future refreshModuleImages(List modules) async { for (final module in modules) { diff --git a/lib/ui/views/learn_practice/learn_practice_viewmodel.dart b/lib/ui/views/learn_practice/learn_practice_viewmodel.dart index ebf3d41..b35fbfb 100644 --- a/lib/ui/views/learn_practice/learn_practice_viewmodel.dart +++ b/lib/ui/views/learn_practice/learn_practice_viewmodel.dart @@ -96,12 +96,11 @@ class LearnPracticeViewModel extends ReactiveViewModel { // Learn practices - List _practices = []; List get practices => _practices; - final Map _refreshedImages= {}; + final Map _refreshedImages = {}; Map get refreshedImages => _refreshedImages; @@ -251,7 +250,6 @@ class LearnPracticeViewModel extends ReactiveViewModel { ); await playVoicePrompt(_questions[index]); } else { - await completeLearnPractices(); goTo(3); } } @@ -283,11 +281,11 @@ class LearnPracticeViewModel extends ReactiveViewModel { if (await _statusChecker.checkConnection()) { if (practice == LearnPractices.course) { _practices = await _apiService.getLearnCoursePractices(id); - // await refreshPracticeImages(_practices); + // await refreshPracticeImages(_practices); await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); } else if (practice == LearnPractices.module) { _practices = await _apiService.getLearnModulePractices(id); - // await refreshPracticeImages(_practices); + // await refreshPracticeImages(_practices); await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); } else { _practices = await _apiService.getLearnLessonPractices(id); @@ -331,5 +329,4 @@ class LearnPracticeViewModel extends ReactiveViewModel { String getPracticeImage(LearnPractice practice) => getReadableUrl(_refreshedImages[practice.id] ?? '') ?? ''; - } diff --git a/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart b/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart index f0e18d4..27f8ea6 100644 --- a/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart +++ b/lib/ui/views/learn_practice/screens/interact_learn_practice_screen.dart @@ -169,6 +169,7 @@ class InteractLearnPracticeScreen Widget _buildSpeakingIndicator(LearnPracticeViewModel viewModel) => WaveWrapper(height: 200, child: _buildSpinnerState(viewModel)); + Widget _buildSpinnerState(LearnPracticeViewModel viewModel) => viewModel.busy(StateObjects.recordLearnPracticeAnswer) || viewModel.busy(StateObjects.finishLearnPracticeQuestion) diff --git a/lib/ui/views/onboarding/screens/learning_goal_form_screen.dart b/lib/ui/views/onboarding/screens/learning_goal_form_screen.dart index 0f5900c..d61efdc 100644 --- a/lib/ui/views/onboarding/screens/learning_goal_form_screen.dart +++ b/lib/ui/views/onboarding/screens/learning_goal_form_screen.dart @@ -13,8 +13,8 @@ import 'package:yimaru_app/ui/widgets/large_app_bar.dart'; class LearningGoalFormScreen extends ViewModelWidget { const LearningGoalFormScreen({super.key}); - IconData getIcon(int icon) { - switch (icon) { + IconData getIcon(int index) { + switch (index) { case 0: return Iconsax.book; case 1: @@ -25,6 +25,31 @@ class LearningGoalFormScreen extends ViewModelWidget { return Icons.book; } + String getTitles(int index) { + switch (index) { + case 0: + return 'Learn to Speak English'; + case 1: + return 'Practice Speaking English'; + case 2: + return 'Skill-based Courses'; + } + return ''; + } + + String getSubtitle(int index) { + switch (index) { + case 0: + return 'I know some English, but i want to learn to speak it'; + case 1: + return 'I already speak English, but I want more practice.'; + case 2: + return 'I want courses for IELTS, TOEFL, Duolingo, or work'; + } + return ''; + } + + void _pop(OnboardingViewModel viewModel) { viewModel.resetLearningGoalFormScreen(); viewModel.goBack(); @@ -45,17 +70,20 @@ class LearningGoalFormScreen extends ViewModelWidget { Widget build(BuildContext context, OnboardingViewModel viewModel) => _buildScaffoldWrapper(viewModel); - Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold( + Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => + Scaffold( backgroundColor: kcBackgroundColor, body: _buildScaffold(viewModel), ); - Widget _buildScaffold(OnboardingViewModel viewModel) => Column( + Widget _buildScaffold(OnboardingViewModel viewModel) => + Column( crossAxisAlignment: CrossAxisAlignment.start, children: _buildScaffoldChildren(viewModel), ); - List _buildScaffoldChildren(OnboardingViewModel viewModel) => [ + List _buildScaffoldChildren(OnboardingViewModel viewModel) => + [ _buildAppBar(viewModel), verticalSpaceMedium, _buildExpandedBody(viewModel) @@ -69,12 +97,14 @@ class LearningGoalFormScreen extends ViewModelWidget { child: _buildBodyWrapper(viewModel), ); - Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding( + Widget _buildBodyWrapper(OnboardingViewModel viewModel) => + Padding( padding: const EdgeInsets.symmetric(horizontal: 15), child: _buildBody(viewModel), ); - Widget _buildBody(OnboardingViewModel viewModel) => Column( + Widget _buildBody(OnboardingViewModel viewModel) => + Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: _buildBodyChildren(viewModel), @@ -83,20 +113,23 @@ class LearningGoalFormScreen extends ViewModelWidget { List _buildBodyChildren(OnboardingViewModel viewModel) => [_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)]; - Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column( + Widget _buildUpperColumn(OnboardingViewModel viewModel) => + Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: _buildUpperColumnChildren(viewModel), ); - List _buildUpperColumnChildren(OnboardingViewModel viewModel) => [ + List _buildUpperColumnChildren(OnboardingViewModel viewModel) => + [ verticalSpaceMedium, _buildTitle(viewModel), verticalSpaceMedium, _buildLearningGoals(viewModel) ]; - Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar( + Widget _buildAppBar(OnboardingViewModel viewModel) => + LargeAppBar( showBackButton: true, showLanguageSelection: true, onPop: () => _pop(viewModel), @@ -106,10 +139,11 @@ class LearningGoalFormScreen extends ViewModelWidget { : viewModel.selectedLanguage['code'], ); - Widget _buildTitle(OnboardingViewModel viewModel) => Text.rich( + Widget _buildTitle(OnboardingViewModel viewModel) => + Text.rich( TextSpan( text: - '${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},', + '${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},', style: style18P600.copyWith(fontSize: 22), children: [ TextSpan( @@ -119,30 +153,39 @@ class LearningGoalFormScreen extends ViewModelWidget { ]), ); - Widget _buildLearningGoals(OnboardingViewModel viewModel) => ListView.builder( + Widget _buildLearningGoals(OnboardingViewModel viewModel) => + ListView.builder( shrinkWrap: true, - itemCount: viewModel.learningGoals.length, + itemCount: 3,// viewModel.learningGoals.length, physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) => _buildLearningGoal( - title: viewModel.learningGoals[index].label ?? '', - selected: + itemBuilder: (context, index) => + _buildLearningGoal( + icon: getIcon(index), + title: getTitles(index), + subtitle: getSubtitle(index), + selected: viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]), - onTap: () => - viewModel.setSelectedLearningGoal(viewModel.learningGoals[index]), - ), + onTap: () => + viewModel.setSelectedLearningGoal( + viewModel.learningGoals[index]), + ), ); - Widget _buildLearningGoal( - {required String title, - required bool selected, - required GestureTapCallback onTap}) => + Widget _buildLearningGoal({required String title, + required bool selected, + required IconData icon, + required String subtitle, + required GestureTapCallback onTap}) => CustomLargeRadioButton( + icon:icon, title: title, onTap: onTap, + subtitle: subtitle, selected: selected, ); - Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding( + Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => + Padding( padding: const EdgeInsets.only(bottom: 50), child: _buildContinueButton(viewModel), ); diff --git a/lib/ui/widgets/custom_large_radio_button.dart b/lib/ui/widgets/custom_large_radio_button.dart index bb1739d..7f625f4 100644 --- a/lib/ui/widgets/custom_large_radio_button.dart +++ b/lib/ui/widgets/custom_large_radio_button.dart @@ -5,58 +5,76 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart'; class CustomLargeRadioButton extends StatelessWidget { final String title; final bool selected; + final IconData icon; + final String subtitle; final GestureTapCallback? onTap; - const CustomLargeRadioButton({ - super.key, - this.onTap, - required this.title, - required this.selected, - }); + const CustomLargeRadioButton( + {super.key, + this.onTap, + required this.title, + required this.icon, + required this.selected, + required this.subtitle}); @override Widget build(BuildContext context) => _buildButtonWrapper(); Widget _buildButtonWrapper() => Container( - height: 75, - width: double.maxFinite, - margin: const EdgeInsets.only(bottom: 15), - child: _buildContainerWrapper(), - ); + height: 125, + width: double.maxFinite, + margin: const EdgeInsets.only(bottom: 15), + child: _buildContainerWrapper(), + ); Widget _buildContainerWrapper() => GestureDetector( - onTap: onTap, - child: _buildContainer(), - ); + onTap: onTap, + child: _buildContainer(), + ); Widget _buildContainer() => Container( - padding: const EdgeInsets.symmetric(horizontal: 15), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(4), - color: selected ? kcPrimaryColor.withOpacity(0.1) : kcWhite, - border: Border.all( - color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75), - ), - ), - child: _buildButtonRowWrapper(), - ); + padding: const EdgeInsets.symmetric(horizontal: 15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(4), + color: selected ? kcPrimaryColor.withOpacity(0.1) : kcWhite, + border: Border.all( + color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75), + ), + ), + child: _buildButtonColumnWrapper(), + ); - Widget _buildButtonRowWrapper() => Row( - children: _buildButtonRowChildren(), - ); + Widget _buildButtonColumnWrapper() => Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: _buildButtonRowChildren(), + ); List _buildButtonRowChildren() => - [_buildTitleWrapper(), _buildSelectedCheckBox()]; + [_buildIconSectionWrapper(), _buildTitle(), _buildSubtitle()]; - Widget _buildTitleWrapper() => Expanded( - child: _buildTitle(), - ); + Widget _buildIconSectionWrapper() => Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _buildIconSectionChildren(), + ); + + List _buildIconSectionChildren() => + [_buildLeadingIcon(), _buildSelectedCheckBox()]; + + Widget _buildLeadingIcon() => Icon( + icon, + size: 25, + color: kcPrimaryColor, + ); Widget _buildTitle() => Text( - title, - maxLines: 1, - style: style16DG400, - ); + title, + style: style18DG700, + ); + + Widget _buildSubtitle() => Text( + subtitle, + style: const TextStyle(color: kcMediumGrey), + ); Widget _buildSelectedCheckBox() => Checkbox( value: selected, diff --git a/lib/ui/widgets/finish_practice_sheet.dart b/lib/ui/widgets/finish_practice_sheet.dart index 27c0e21..075f9a8 100644 --- a/lib/ui/widgets/finish_practice_sheet.dart +++ b/lib/ui/widgets/finish_practice_sheet.dart @@ -1,6 +1,8 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:yimaru_app/ui/common/app_colors.dart'; +import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart'; import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart'; @@ -8,6 +10,7 @@ import 'custom_elevated_button.dart'; class FinishPracticeSheet extends StatelessWidget { final GestureTapCallback? onTap; + const FinishPracticeSheet({super.key, this.onTap}); @override @@ -20,6 +23,7 @@ class FinishPracticeSheet extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 15), child: _buildColumn(), ); + Widget _buildColumn() => Column( crossAxisAlignment: CrossAxisAlignment.center, children: _buildSheetChildren(), @@ -40,7 +44,7 @@ class FinishPracticeSheet extends StatelessWidget { ); Widget _buildMessage() => Text( - 'Finish all the practices in the lessons to take this practice', + LocaleKeys.finish_all_practice.tr(), style: style16DG600, textAlign: TextAlign.center, ); @@ -48,9 +52,9 @@ class FinishPracticeSheet extends StatelessWidget { Widget _buildContinueButton() => CustomElevatedButton( height: 55, onTap: onTap, - text: 'Continue', borderRadius: 12, foregroundColor: kcWhite, + text: LocaleKeys.cont.tr(), backgroundColor: kcPrimaryColor, ); } diff --git a/lib/ui/widgets/learn_course_tile.dart b/lib/ui/widgets/learn_course_tile.dart index 7689c77..5d3ec1d 100644 --- a/lib/ui/widgets/learn_course_tile.dart +++ b/lib/ui/widgets/learn_course_tile.dart @@ -13,26 +13,20 @@ import 'custom_elevated_button.dart'; class LearnCourseTile extends ViewModelWidget { final LearnCourse course; final GestureTapCallback? onViewTap; - final GestureTapCallback? onLockTap; final GestureTapCallback? onPracticeTap; const LearnCourseTile({ super.key, this.onViewTap, - this.onLockTap, this.onPracticeTap, required this.course, }); @override Widget build(BuildContext context, LearnCourseViewModel viewModel) => - _buildExpansionTileCardWrapper(viewModel); + _buildExpansionTileCard(viewModel); + - Widget _buildExpansionTileCardWrapper(LearnCourseViewModel viewModel) => - GestureDetector( - onTap: !(course.access?.isAccessible ?? false) ? onLockTap : null, - child: _buildExpansionTileCard(viewModel), - ); Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container( margin: const EdgeInsets.only(bottom: 15), diff --git a/lib/ui/widgets/learn_lesson_tile.dart b/lib/ui/widgets/learn_lesson_tile.dart index e882b3d..68680cc 100644 --- a/lib/ui/widgets/learn_lesson_tile.dart +++ b/lib/ui/widgets/learn_lesson_tile.dart @@ -27,6 +27,8 @@ class LearnLessonTile extends ViewModelWidget { required this.index, required this.lesson}); + + @override Widget build(BuildContext context, LearnLessonViewModel viewModel) => _buildContainer(viewModel); diff --git a/lib/ui/widgets/learn_module_tile.dart b/lib/ui/widgets/learn_module_tile.dart index 656ab4d..f19e12b 100644 --- a/lib/ui/widgets/learn_module_tile.dart +++ b/lib/ui/widgets/learn_module_tile.dart @@ -21,14 +21,7 @@ class LearnModuleTile extends ViewModelWidget { const LearnModuleTile( {super.key, this.onModuleTap, this.onPracticeTap, required this.module}); - Future _showSheet( - {required BuildContext context, - required LearnModuleViewModel viewModel}) async => - await showModalBottomSheet( - context: context, - backgroundColor: kcTransparent, - builder: (_) => _buildSheet(viewModel), - ); + @override Widget build(BuildContext context, LearnModuleViewModel viewModel) => @@ -221,9 +214,7 @@ class LearnModuleTile extends ViewModelWidget { text: LocaleKeys.take_practice.tr(), ); - Widget _buildSheet(LearnModuleViewModel viewModel) => FinishPracticeSheet( - onTap: viewModel.pop, - ); + Widget _buildContainerShaderState() => !(module.access?.isAccessible ?? false) ? _buildContainerShader() diff --git a/lib/ui/widgets/overall_progress_wrapper.dart b/lib/ui/widgets/overall_progress_wrapper.dart index 4d729db..480f7f5 100644 --- a/lib/ui/widgets/overall_progress_wrapper.dart +++ b/lib/ui/widgets/overall_progress_wrapper.dart @@ -1,4 +1,6 @@ +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import '../common/app_colors.dart'; import '../common/ui_helpers.dart'; @@ -48,8 +50,8 @@ class OverallProgressWrapper extends StatelessWidget { backgroundColor: kcVeryLightGrey, ); - Widget _buildSubtitle() => const Text( - 'Keep up the great work! You\'re doing amazing.', - style: TextStyle(color: kcDarkGrey), + Widget _buildSubtitle() => Text( + LocaleKeys.keep_up_the_great_work.tr(), + style:style14DG400 , ); } diff --git a/pubspec.yaml b/pubspec.yaml index 4b45150..34fd2b0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: yimaru_app -version: 0.1.25+27 +version: 0.1.26+28 publish_to: 'none' description: A new Flutter project.