Compare commits

..

No commits in common. "4b65e389bf5b6d9af292f3c578648d39dccdf8cc" and "0842a0b357421b8bef550b2e4bdc7a87d5460dbe" have entirely different histories.

29 changed files with 199 additions and 489 deletions

View File

@ -182,9 +182,8 @@
"lets_start_practice": "ልምምድህን እንጀምር", "lets_start_practice": "ልምምድህን እንጀምር",
"welcome_abroad": "እንኳን ደህና መጣህ", "welcome_abroad": "እንኳን ደህና መጣህ",
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።", "ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
"finish": "አጠናቅቅ", "finish": "አጠናቅቅ"
"finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።"

View File

@ -125,7 +125,7 @@
"open_in_telegram": "Open in Telegram", "open_in_telegram": "Open in Telegram",
"search_for": "Search for", "search_for": "Search for",
"current_level": "Current Level", "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!", "no_practice_available": "No practice available!",
"begin_module_practice": "Begin Module Practice", "begin_module_practice": "Begin Module Practice",
"lets_practice_lesson": "Lets Practice", "lets_practice_lesson": "Lets Practice",
@ -182,6 +182,5 @@
"lets_start_practice": "Let's start your practice", "lets_start_practice": "Let's start your practice",
"welcome_abroad": "Welcome aboard", "welcome_abroad": "Welcome aboard",
"ready_to_explore": "Youre ready to explore your personalized lessons.", "ready_to_explore": "Youre ready to explore your personalized lessons.",
"finish": "Finish", "finish": "Finish"
"finish_all_practice": "Finish all the practices in the lessons to take this practice"
} }

View File

@ -1,6 +1,5 @@
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:toastification/toastification.dart'; import 'package:toastification/toastification.dart';
import 'package:yimaru_app/app/app.bottomsheets.dart'; import 'package:yimaru_app/app/app.bottomsheets.dart';
import 'package:yimaru_app/app/app.dialogs.dart'; import 'package:yimaru_app/app/app.dialogs.dart';
@ -14,15 +13,12 @@ import 'firebase_options.dart';
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
await setupLocator(); await setupLocator();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform); await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await locator<NotificationService>().initialize(); await locator<NotificationService>().initialize();
await EasyLocalization.ensureInitialized(); await EasyLocalization.ensureInitialized();
setupDialogUi(); setupDialogUi();
setupBottomSheetUi(); setupBottomSheetUi();
await SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
runApp( runApp(
EasyLocalization( EasyLocalization(
supportedLocales: const [ supportedLocales: const [

View File

@ -21,7 +21,7 @@ class Access {
final int? progressPercent; final int? progressPercent;
@JsonKey(name: 'progress_percent_precise') @JsonKey(name: 'progress_percent_precise')
final double? progressPercentPrecise; final int? progressPercentPrecise;
const Access({ const Access({
this.reason, this.reason,
@ -40,7 +40,7 @@ class Access {
bool? isAccessible, bool? isAccessible,
int? completedCount, int? completedCount,
int? progressPercent, int? progressPercent,
double? progressPercentPrecise, int? progressPercentPrecise,
}) { }) {
return Access( return Access(
reason: reason ?? this.reason, reason: reason ?? this.reason,

View File

@ -14,7 +14,7 @@ Access _$AccessFromJson(Map<String, dynamic> json) => Access(
completedCount: (json['completed_count'] as num?)?.toInt(), completedCount: (json['completed_count'] as num?)?.toInt(),
progressPercent: (json['progress_percent'] as num?)?.toInt(), progressPercent: (json['progress_percent'] as num?)?.toInt(),
progressPercentPrecise: progressPercentPrecise:
(json['progress_percent_precise'] as num?)?.toDouble(), (json['progress_percent_precise'] as num?)?.toInt(),
); );
Map<String, dynamic> _$AccessToJson(Access instance) => <String, dynamic>{ Map<String, dynamic> _$AccessToJson(Access instance) => <String, dynamic>{

View File

@ -43,22 +43,23 @@ class User {
@JsonKey(name: 'profile_picture_url') @JsonKey(name: 'profile_picture_url')
final String? profilePicture; final String? profilePicture;
const User( const User({
{this.email, this.email,
this.region, this.region,
this.gender, this.gender,
this.userId, this.userId,
this.country, this.country,
this.lastName, this.lastName,
this.birthday, this.birthday,
this.firstName, this.firstName,
this.occupation, this.occupation,
this.accessToken, this.accessToken,
this.refreshToken, this.refreshToken,
this.profilePicture, this.profilePicture,
this.userInfoLoaded, this.userInfoLoaded,
this.profileCompleted, this.profileCompleted,
this.subscriptionStatus}); this.subscriptionStatus
});
User copyWith( User copyWith(
{int? userId, {int? userId,
@ -74,8 +75,7 @@ class User {
String? refreshToken, String? refreshToken,
bool? userInfoLoaded, bool? userInfoLoaded,
bool? profileCompleted, bool? profileCompleted,
String? profilePicture, String? profilePicture}) =>
String? subscriptionStatus}) =>
User( User(
email: email ?? this.email, email: email ?? this.email,
userId: userId ?? this.userId, userId: userId ?? this.userId,
@ -90,8 +90,7 @@ class User {
refreshToken: refreshToken ?? this.refreshToken, refreshToken: refreshToken ?? this.refreshToken,
userInfoLoaded: userInfoLoaded ?? this.userInfoLoaded, userInfoLoaded: userInfoLoaded ?? this.userInfoLoaded,
profilePicture: profilePicture ?? this.profilePicture, profilePicture: profilePicture ?? this.profilePicture,
profileCompleted: profileCompleted ?? this.profileCompleted, profileCompleted: profileCompleted ?? this.profileCompleted);
subscriptionStatus: subscriptionStatus ?? this.subscriptionStatus);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);

View File

@ -21,7 +21,6 @@ User _$UserFromJson(Map<String, dynamic> json) => User(
profilePicture: json['profile_picture_url'] as String?, profilePicture: json['profile_picture_url'] as String?,
userInfoLoaded: json['userInfoLoaded'] as bool?, userInfoLoaded: json['userInfoLoaded'] as bool?,
profileCompleted: json['profile_completed'] as bool?, profileCompleted: json['profile_completed'] as bool?,
subscriptionStatus: json['subscription_status'] as String?,
); );
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{ Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
@ -38,6 +37,5 @@ Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
'access_token': instance.accessToken, 'access_token': instance.accessToken,
'refresh_token': instance.refreshToken, 'refresh_token': instance.refreshToken,
'profile_completed': instance.profileCompleted, 'profile_completed': instance.profileCompleted,
'subscription_status': instance.subscriptionStatus,
'profile_picture_url': instance.profilePicture, 'profile_picture_url': instance.profilePicture,
}; };

View File

@ -27,7 +27,7 @@ class DioService {
DioService() { DioService() {
_dio.options _dio.options
..baseUrl = kBaseUrl ..baseUrl = kBaseUrl
..connectTimeout = const Duration(seconds: 10) ..connectTimeout = const Duration(seconds: 5)
..receiveTimeout = const Duration(seconds: 15); ..receiveTimeout = const Duration(seconds: 15);
_dio.interceptors.add( _dio.interceptors.add(

View File

@ -17,7 +17,7 @@ class LearnService with ListenableServiceMixin {
// Initialization // Initialization
learnService() { learnService() {
listenToReactiveValues([_programs,_courses, _lessons, _modules]); listenToReactiveValues([_programs, _lessons, _modules]);
} }
// Learn program // Learn program
@ -89,6 +89,7 @@ class LearnService with ListenableServiceMixin {
// Learn progress // Learn progress
Future<void> getLearnProgressSummary() async { Future<void> getLearnProgressSummary() async {
final summaries = await _apiService.getProgressSummary(); final summaries = await _apiService.getProgressSummary();
print('MY SUMMARIES: ${summaries.length}');
/// PROGRAM ACCESS MAP /// PROGRAM ACCESS MAP
final Map<int, Access?> programAccessMap = {}; final Map<int, Access?> programAccessMap = {};
@ -148,11 +149,6 @@ class LearnService with ListenableServiceMixin {
); );
}).toList(); }).toList();
print('MY SUMMARIES - COMPLETED COUNT: ${_modules.first.access?.completedCount}');
print('PROGRESS PERCENT: ${_modules.first.access?.progressPercent}');
/// UPDATE LESSONS /// UPDATE LESSONS
_lessons = _lessons.map((lesson) { _lessons = _lessons.map((lesson) {
return lesson.copyWith( return lesson.copyWith(
@ -162,24 +158,4 @@ class LearnService with ListenableServiceMixin {
notifyListeners(); 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;
}
}
} }

View File

@ -39,7 +39,6 @@ enum StateObjects {
learnModules, learnModules,
learnCourses, learnCourses,
profileImage, profileImage,
paymentStatus,
profileDetail, profileDetail,
learnPrograms, learnPrograms,
courseLessons, courseLessons,

View File

@ -198,8 +198,7 @@ class CodegenLoader extends AssetLoader{
"lets_start_practice": "ልምምድህን እንጀምር", "lets_start_practice": "ልምምድህን እንጀምር",
"welcome_abroad": "እንኳን ደህና መጣህ", "welcome_abroad": "እንኳን ደህና መጣህ",
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።", "ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
"finish": "አጠናቅቅ", "finish": "አጠናቅቅ"
"finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።"
}; };
static const Map<String,dynamic> _en = { static const Map<String,dynamic> _en = {
"loading": "Loading", "loading": "Loading",
@ -328,7 +327,7 @@ static const Map<String,dynamic> _en = {
"open_in_telegram": "Open in Telegram", "open_in_telegram": "Open in Telegram",
"search_for": "Search for", "search_for": "Search for",
"current_level": "Current Level", "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!", "no_practice_available": "No practice available!",
"begin_module_practice": "Begin Module Practice", "begin_module_practice": "Begin Module Practice",
"lets_practice_lesson": "Lets Practice", "lets_practice_lesson": "Lets Practice",
@ -385,8 +384,7 @@ static const Map<String,dynamic> _en = {
"lets_start_practice": "Let's start your practice", "lets_start_practice": "Let's start your practice",
"welcome_abroad": "Welcome aboard", "welcome_abroad": "Welcome aboard",
"ready_to_explore": "Youre ready to explore your personalized lessons.", "ready_to_explore": "Youre ready to explore your personalized lessons.",
"finish": "Finish", "finish": "Finish"
"finish_all_practice": "Finish all the practices in the lessons to take this practice"
}; };
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en}; static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en};
} }

View File

@ -185,6 +185,5 @@ abstract class LocaleKeys {
static const welcome_abroad = 'welcome_abroad'; static const welcome_abroad = 'welcome_abroad';
static const ready_to_explore = 'ready_to_explore'; static const ready_to_explore = 'ready_to_explore';
static const finish = 'finish'; static const finish = 'finish';
static const finish_all_practice = 'finish_all_practice';
} }

View File

@ -13,16 +13,12 @@ class ArifPayView extends StackedView<ArifPayViewModel> {
const ArifPayView({Key? key, required this.phone}) : super(key: key); const ArifPayView({Key? key, required this.phone}) : super(key: key);
void _pop(ArifPayViewModel viewModel) => viewModel.pop;
void _error(ArifPayViewModel viewModel) => viewModel.pop(); void _error(ArifPayViewModel viewModel) => viewModel.pop();
Future<void> _success(ArifPayViewModel viewModel) async =>
Future<void> _success(ArifPayViewModel viewModel) async { await viewModel.replaceWithHome();
await viewModel.updatePaymentStatus();
await viewModel.replaceWithHome();
}
@override @override
void onViewModelReady(ArifPayViewModel viewModel) async { void onViewModelReady(ArifPayViewModel viewModel) async {
@ -49,8 +45,6 @@ class ArifPayView extends StackedView<ArifPayViewModel> {
? const PageLoadingIndicator() ? const PageLoadingIndicator()
: _buildScaffold(viewModel); : _buildScaffold(viewModel);
Widget _buildScaffold(ArifPayViewModel viewModel) => Widget _buildScaffold(ArifPayViewModel viewModel) =>
SafeArea(child: _buildBody(viewModel)); SafeArea(child: _buildBody(viewModel));

View File

@ -5,13 +5,10 @@ import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../app/app.locator.dart'; import '../../../app/app.locator.dart';
import '../../../app/app.router.dart'; import '../../../app/app.router.dart';
import '../../../models/learn_subscription_request.dart'; import '../../../models/learn_subscription_request.dart';
import '../../../models/user.dart';
import '../../../services/api_service.dart'; import '../../../services/api_service.dart';
import '../../../services/authentication_service.dart';
import '../../../services/status_checker_service.dart'; import '../../../services/status_checker_service.dart';
import '../../common/ui_helpers.dart';
class ArifPayViewModel extends ReactiveViewModel { class ArifPayViewModel extends BaseViewModel {
// Dependency injection // Dependency injection
final _apiService = locator<ApiService>(); final _apiService = locator<ApiService>();
@ -20,16 +17,6 @@ class ArifPayViewModel extends ReactiveViewModel {
final _navigationService = locator<NavigationService>(); final _navigationService = locator<NavigationService>();
final _authenticationService = locator<AuthenticationService>();
@override
List<ListenableServiceMixin> get listenableServices =>
[_authenticationService];
// Current user
User? get _user => _authenticationService.user;
User? get user => _user;
// Learn subscription request // Learn subscription request
LearnSubscriptionRequest? _request; LearnSubscriptionRequest? _request;
@ -49,7 +36,6 @@ class ArifPayViewModel extends ReactiveViewModel {
busyObject: StateObjects.learnSubscription); busyObject: StateObjects.learnSubscription);
Future<void> _createLearnSubscriptionRequest(String phone) async { Future<void> _createLearnSubscriptionRequest(String phone) async {
print('MY SUMMARIES : PAYMENT');
if (await _statusChecker.checkConnection()) { if (await _statusChecker.checkConnection()) {
Map<String, dynamic> data = { Map<String, dynamic> data = {
'plan_id': 1, 'plan_id': 1,
@ -67,23 +53,4 @@ class ArifPayViewModel extends ReactiveViewModel {
} }
} }
// Update payment status
Future<void> updatePaymentStatus() async => await runBusyFuture(_updatePaymentStatus(),
busyObject: StateObjects.learnSubscription);
Future<void> _updatePaymentStatus() async {
Map<String, dynamic> response = {};
response = await _apiService.getProfileData(_user?.userId);
if (response['status'] == ResponseStatus.success) {
User user = response['data'] as User;
await _authenticationService.saveUserData(user);
}
}
} }

View File

@ -6,38 +6,14 @@ import '../../common/app_colors.dart';
import '../../common/enmus.dart'; import '../../common/enmus.dart';
import '../../common/ui_helpers.dart'; import '../../common/ui_helpers.dart';
import '../../widgets/custom_circular_progress_indicator.dart'; import '../../widgets/custom_circular_progress_indicator.dart';
import '../../widgets/finish_practice_sheet.dart';
import '../../widgets/learn_course_tile.dart'; import '../../widgets/learn_course_tile.dart';
import '../../widgets/small_app_bar.dart'; import '../../widgets/small_app_bar.dart';
import 'learn_course_viewmodel.dart'; import 'learn_course_viewmodel.dart';
class LearnCourseView extends StackedView<LearnCourseViewModel> { class LearnCourseView extends StackedView<LearnCourseViewModel> {
final int id; final int id;
const LearnCourseView({Key? key, required this.id}) : super(key: key); const LearnCourseView({Key? key, required this.id}) : super(key: key);
Future<void> _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<void> _showSheet({required BuildContext context,
required LearnCourseViewModel viewModel}) async =>
await showModalBottomSheet(
context: context,
backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel),
);
@override @override
void onViewModelReady(LearnCourseViewModel viewModel) async { void onViewModelReady(LearnCourseViewModel viewModel) async {
await viewModel.getLearnCourses(id); await viewModel.getLearnCourses(id);
@ -49,108 +25,88 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
LearnCourseViewModel(); LearnCourseViewModel();
@override @override
Widget builder(BuildContext context, Widget builder(
LearnCourseViewModel viewModel, BuildContext context,
Widget? child,) => LearnCourseViewModel viewModel,
_buildScaffoldWrapper(context: context,viewModel: viewModel); Widget? child,
) =>
_buildScaffoldWrapper(viewModel);
Widget _buildScaffoldWrapper({required BuildContext context, Widget _buildScaffoldWrapper(LearnCourseViewModel viewModel) => Scaffold(
required LearnCourseViewModel viewModel}) =>
Scaffold(
backgroundColor: kcBackgroundColor, backgroundColor: kcBackgroundColor,
body: _buildScaffoldContainer(context: context,viewModel: viewModel), body: _buildScaffoldContainer(viewModel),
); );
Widget _buildScaffoldContainer({required BuildContext context, Widget _buildScaffoldContainer(LearnCourseViewModel viewModel) => Container(
required LearnCourseViewModel viewModel}) =>
Container(
decoration: bgDecoration, decoration: bgDecoration,
child: _buildScaffold(context: context,viewModel: viewModel), child: _buildScaffold(viewModel),
); );
Widget _buildScaffold({required BuildContext context, Widget _buildScaffold(LearnCourseViewModel viewModel) =>
required LearnCourseViewModel viewModel}) => SafeArea(child: _buildBody(viewModel));
SafeArea(child: _buildBody(context: context,viewModel: viewModel));
Widget _buildBody({required BuildContext context, Widget _buildBody(LearnCourseViewModel viewModel) => Padding(
required LearnCourseViewModel viewModel}) =>
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: _buildColumn(context: context,viewModel: viewModel), child: _buildColumn(viewModel),
); );
Widget _buildColumn({required BuildContext context, Widget _buildColumn(LearnCourseViewModel viewModel) => Column(
required LearnCourseViewModel viewModel}) =>
Column(
children: [ children: [
verticalSpaceMedium, verticalSpaceMedium,
_buildAppBar(viewModel), _buildAppBar(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildCoursesColumnWrapper(context: context,viewModel: viewModel) _buildCoursesColumnWrapper(viewModel)
], ],
); );
Widget _buildAppBar(LearnCourseViewModel viewModel) => Widget _buildAppBar(LearnCourseViewModel viewModel) => SmallAppBar(
SmallAppBar(
onPop: viewModel.pop, onPop: viewModel.pop,
showBackButton: true, showBackButton: true,
); );
Widget _buildCoursesColumnWrapper({required BuildContext context, Widget _buildCoursesColumnWrapper(LearnCourseViewModel viewModel) =>
required LearnCourseViewModel viewModel}) => Expanded(child: _buildLevelsColumnScrollView(viewModel));
Expanded(child: _buildLevelsColumnScrollView(context: context,viewModel: viewModel));
Widget _buildLevelsColumnScrollView({required BuildContext context, Widget _buildLevelsColumnScrollView(LearnCourseViewModel viewModel) =>
required LearnCourseViewModel viewModel}) =>
SingleChildScrollView( SingleChildScrollView(
child: _buildListViewBuilder(context: context,viewModel: viewModel), child: _buildListViewBuilder(viewModel),
); );
Widget _buildListViewBuilder({required BuildContext context, Widget _buildListViewBuilder(LearnCourseViewModel viewModel) =>
required LearnCourseViewModel viewModel}) =>
viewModel.busy(StateObjects.learnCourses) viewModel.busy(StateObjects.learnCourses)
? _buildProgressIndicator() ? _buildProgressIndicator()
: _buildListView(context: context,viewModel: viewModel); : _buildListView(viewModel);
Widget _buildProgressIndicator() => Widget _buildProgressIndicator() => const Center(
const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor), child: CustomCircularProgressIndicator(color: kcPrimaryColor),
); );
Widget _buildListView({required BuildContext context, Widget _buildListView(LearnCourseViewModel viewModel) => ListView.separated(
required LearnCourseViewModel viewModel}) =>
ListView.separated(
shrinkWrap: true, shrinkWrap: true,
itemCount: viewModel.courses.length, itemCount: viewModel.courses.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => itemBuilder: (context, index) => _buildTile(
_buildTile( course: viewModel.courses[index],
course: viewModel.courses[index], onViewTap: () async =>
onPracticeTap: () async =>
await _onPractice(
context: context,
viewModel: viewModel,
course: viewModel.courses[index]
),
onViewTap: () async =>
await viewModel.navigateToLearnModule(viewModel.courses[index]), 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, separatorBuilder: (context, index) => verticalSpaceSmall,
); );
Widget _buildTile({ Widget _buildTile({
required LearnCourse course, required LearnCourse course,
required GestureTapCallback onViewTap, required GestureTapCallback onViewTap,
required GestureTapCallback onLockTap,
required GestureTapCallback onPracticeTap, required GestureTapCallback onPracticeTap,
}) => }) =>
LearnCourseTile( LearnCourseTile(
course: course, course: course,
onViewTap: onViewTap, onViewTap: onViewTap,
onLockTap: onLockTap,
onPracticeTap: onPracticeTap, onPracticeTap: onPracticeTap,
); );
Widget _buildSheet(LearnCourseViewModel viewModel) =>
FinishPracticeSheet(onTap: viewModel.pop);
} }

View File

@ -20,24 +20,6 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
const LearnLessonView({Key? key, required this.module}) : super(key: key); const LearnLessonView({Key? key, required this.module}) : super(key: key);
Future<void> _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 @override
void onViewModelReady(LearnLessonViewModel viewModel) async { void onViewModelReady(LearnLessonViewModel viewModel) async {
await viewModel.getLessons(module.id ?? 0); await viewModel.getLessons(module.id ?? 0);
@ -142,7 +124,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
verticalSpaceTiny, verticalSpaceTiny,
_buildSubtitle(), _buildSubtitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildModuleProgress(viewModel), _buildModuleProgress(),
verticalSpaceLarge, verticalSpaceLarge,
_buildMotivationCard(), _buildMotivationCard(),
verticalSpaceLarge, verticalSpaceLarge,
@ -161,19 +143,10 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
style: style14DG500, style: style14DG500,
); );
Widget _buildModuleProgress(LearnLessonViewModel viewModel) => ModuleProgress( Widget _buildModuleProgress() => ModuleProgress(
total: (viewModel.getUpdatedLearnModule(module.id ?? 0) ?? module) total: module.access?.totalCount ?? 0,
.access completed: module.access?.completedCount ?? 0,
?.totalCount ?? progress: module.access?.progressPercent ?? 0,
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(); Widget _buildMotivationCard() => const MotivationCard();
@ -199,16 +172,13 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
itemBuilder: (context, index) => _buildTile( itemBuilder: (context, index) => _buildTile(
index: index, index: index,
lesson: viewModel.lessons[index], lesson: viewModel.lessons[index],
onPracticeTap: () async => await _onPractice(
index: index,
viewModel: viewModel,
lesson: viewModel.lessons[index],
),
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail( onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(
module: module, module: module,
lesson: viewModel.lessons[index], lesson: viewModel.lessons[index],
hasPractice: hasPractice:
index != viewModel.lessons.length - 1 ? true : false), index != viewModel.lessons.length - 1 ? true : false),
onPracticeTap: () async => await viewModel
.navigateToLearnPractice(viewModel.lessons[index].id ?? 0),
), ),
); );

View File

@ -8,8 +8,6 @@ import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import '../../../app/app.locator.dart'; import '../../../app/app.locator.dart';
import '../../../models/learn_module.dart'; import '../../../models/learn_module.dart';
import '../../../models/user.dart';
import '../../../services/authentication_service.dart';
import '../../../services/learn_service.dart'; import '../../../services/learn_service.dart';
import '../../../services/status_checker_service.dart'; import '../../../services/status_checker_service.dart';
import '../../common/helper_functions.dart'; import '../../common/helper_functions.dart';
@ -22,19 +20,8 @@ class LearnLessonViewModel extends ReactiveViewModel {
final _navigationService = locator<NavigationService>(); final _navigationService = locator<NavigationService>();
final _authenticationService = locator<AuthenticationService>();
@override @override
List<ListenableServiceMixin> get listenableServices => [_learnService,_authenticationService]; List<ListenableServiceMixin> get listenableServices => [_learnService];
// Current user
User? get _user => _authenticationService.user;
User? get user => _user;
// Learn lessons // Learn lessons
@ -49,8 +36,6 @@ class LearnLessonViewModel extends ReactiveViewModel {
// Navigation // Navigation
void pop() => _navigationService.back(); void pop() => _navigationService.back();
Future<void> navigateToLearnPractice(int id) async => Future<void> navigateToLearnPractice(int id) async =>
await _navigationService.navigateToLearnPracticeView( await _navigationService.navigateToLearnPracticeView(
id: id, id: id,
@ -60,10 +45,6 @@ class LearnLessonViewModel extends ReactiveViewModel {
subtitle: LocaleKeys.ask_you_few_actions.tr(), subtitle: LocaleKeys.ask_you_few_actions.tr(),
); );
Future<void> navigateToLearnSubscription() async =>
await _navigationService.navigateToLearnSubscriptionView();
Future<void> navigateToLearnLessonDetail( Future<void> navigateToLearnLessonDetail(
{required bool hasPractice, {required bool hasPractice,
required LearnLesson lesson, required LearnLesson lesson,
@ -84,10 +65,6 @@ class LearnLessonViewModel extends ReactiveViewModel {
} }
} }
// Get module
LearnModule? getUpdatedLearnModule(int id) {
return _learnService.getLearnModuleById(id);
}
//Refresh image //Refresh image
Future<void> refreshLessonImages(List<LearnLesson> lessons) async { Future<void> refreshLessonImages(List<LearnLesson> lessons) async {
for (final lesson in lessons) { for (final lesson in lessons) {

View File

@ -11,35 +11,14 @@ import '../../common/app_colors.dart';
import '../../common/enmus.dart'; import '../../common/enmus.dart';
import '../../common/ui_helpers.dart'; import '../../common/ui_helpers.dart';
import '../../widgets/custom_circular_progress_indicator.dart'; import '../../widgets/custom_circular_progress_indicator.dart';
import '../../widgets/finish_practice_sheet.dart';
import '../../widgets/small_app_bar.dart'; import '../../widgets/small_app_bar.dart';
import 'learn_module_viewmodel.dart'; import 'learn_module_viewmodel.dart';
class LearnModuleView extends StackedView<LearnModuleViewModel> { class LearnModuleView extends StackedView<LearnModuleViewModel> {
final LearnCourse course; final LearnCourse course;
const LearnModuleView({Key? key, required this.course}) : super(key: key); const LearnModuleView({Key? key, required this.course}) : super(key: key);
Future<void> _onPractice(
{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<void> _showSheet(
{required BuildContext context,
required LearnModuleViewModel viewModel}) async =>
await showModalBottomSheet(
context: context,
backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel),
);
@override @override
void onViewModelReady(LearnModuleViewModel viewModel) async { void onViewModelReady(LearnModuleViewModel viewModel) async {
await viewModel.getLearnModules(course.id ?? 0); await viewModel.getLearnModules(course.id ?? 0);
@ -56,46 +35,32 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
LearnModuleViewModel viewModel, LearnModuleViewModel viewModel,
Widget? child, Widget? child,
) => ) =>
_buildScaffoldWrapper(context: context, viewModel: viewModel); _buildScaffoldWrapper(viewModel);
Widget _buildScaffoldWrapper( Widget _buildScaffoldWrapper(LearnModuleViewModel viewModel) => Scaffold(
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
Scaffold(
backgroundColor: kcBackgroundColor, backgroundColor: kcBackgroundColor,
body: _buildScaffoldContainer(context: context, viewModel: viewModel), body: _buildScaffoldContainer(viewModel),
); );
Widget _buildScaffoldContainer( Widget _buildScaffoldContainer(LearnModuleViewModel viewModel) => Container(
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
Container(
decoration: bgDecoration, decoration: bgDecoration,
child: _buildScaffold(context: context, viewModel: viewModel), child: _buildScaffold(viewModel),
); );
Widget _buildScaffold( Widget _buildScaffold(LearnModuleViewModel viewModel) =>
{required BuildContext context, SafeArea(child: _buildBody(viewModel));
required LearnModuleViewModel viewModel}) =>
SafeArea(child: _buildBody(context: context, viewModel: viewModel));
Widget _buildBody( Widget _buildBody(LearnModuleViewModel viewModel) => Padding(
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: _buildColumn(context: context, viewModel: viewModel), child: _buildColumn(viewModel),
); );
Widget _buildColumn( Widget _buildColumn(LearnModuleViewModel viewModel) => Column(
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
Column(
children: [ children: [
verticalSpaceMedium, verticalSpaceMedium,
_buildAppBar(viewModel), _buildAppBar(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildModulesColumnWrapper(context: context, viewModel: viewModel), _buildModulesColumnWrapper(viewModel),
], ],
); );
@ -104,41 +69,28 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
showBackButton: true, showBackButton: true,
); );
Widget _buildModulesColumnWrapper( Widget _buildModulesColumnWrapper(LearnModuleViewModel viewModel) =>
{required BuildContext context, Expanded(child: _buildLevelsColumnScrollView(viewModel));
required LearnModuleViewModel viewModel}) =>
Expanded(
child: _buildLevelsColumnScrollView(
context: context, viewModel: viewModel));
Widget _buildLevelsColumnScrollView( Widget _buildLevelsColumnScrollView(LearnModuleViewModel viewModel) =>
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
SingleChildScrollView( SingleChildScrollView(
child: _buildLevelsColumn(context: context, viewModel: viewModel), child: _buildLevelsColumn(viewModel),
); );
Widget _buildLevelsColumn( Widget _buildLevelsColumn(LearnModuleViewModel viewModel) => Column(
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: children: _buildLevelsColumnChildren(viewModel),
_buildLevelsColumnChildren(context: context, viewModel: viewModel),
); );
List<Widget> _buildLevelsColumnChildren( List<Widget> _buildLevelsColumnChildren(LearnModuleViewModel viewModel) => [
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
[
verticalSpaceSmall, verticalSpaceSmall,
_buildTitle(), _buildTitle(),
_buildSubtitle(), _buildSubtitle(),
verticalSpaceMedium, verticalSpaceMedium,
_buildOverallProgress(viewModel), _buildOverallProgress(),
verticalSpaceMedium, verticalSpaceMedium,
_buildListViewBuilder(context: context, viewModel: viewModel) _buildListViewBuilder(viewModel)
]; ];
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
@ -151,38 +103,30 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
style: style14P400, style: style14P400,
); );
Widget _buildOverallProgress(LearnModuleViewModel viewModel) => OverallProgress( Widget _buildOverallProgress() => OverallProgress(
indicatorBackgroundColor: kcWhite, indicatorBackgroundColor: kcWhite,
backgroundColor: kcPrimaryColor.withOpacity(0.1), progress: course.access?.progressPercent ?? 0,
progress: backgroundColor: kcPrimaryColor.withOpacity(0.1),
(viewModel.getUpdatedLearnCourse(course.id ?? 0) ?? course).access?.progressPercent ?? 0,
); );
Widget _buildListViewBuilder( Widget _buildListViewBuilder(LearnModuleViewModel viewModel) =>
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
viewModel.busy(StateObjects.learnModules) viewModel.busy(StateObjects.learnModules)
? _buildProgressIndicator() ? _buildProgressIndicator()
: _buildListView(context: context, viewModel: viewModel); : _buildListView(viewModel);
Widget _buildProgressIndicator() => const Center( Widget _buildProgressIndicator() => const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor), child: CustomCircularProgressIndicator(color: kcPrimaryColor),
); );
Widget _buildListView( Widget _buildListView(LearnModuleViewModel viewModel) => ListView.builder(
{required BuildContext context,
required LearnModuleViewModel viewModel}) =>
ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: viewModel.modules.length, itemCount: viewModel.modules.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildTile( itemBuilder: (context, index) => _buildTile(
module: viewModel.modules[index], module: viewModel.modules[index],
onPracticeTap: () async => await _onPractice( onPracticeTap: () async => await viewModel.navigateToLearnPractice(
context: context, id: viewModel.modules[index].id ?? 0,
viewModel: viewModel, module: viewModel.modules[index].name ?? ''),
module: viewModel.modules[index],
),
onModuleTap: () async => onModuleTap: () async =>
await viewModel.navigateToLearnLesson(viewModel.modules[index]), await viewModel.navigateToLearnLesson(viewModel.modules[index]),
), ),
@ -197,7 +141,4 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
module: module, module: module,
onModuleTap: onModuleTap, onModuleTap: onModuleTap,
onPracticeTap: onPracticeTap); onPracticeTap: onPracticeTap);
Widget _buildSheet(LearnModuleViewModel viewModel) =>
FinishPracticeSheet(onTap: viewModel.pop);
} }

View File

@ -6,7 +6,6 @@ import 'package:yimaru_app/models/learn_module.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart'; import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import '../../../app/app.locator.dart'; import '../../../app/app.locator.dart';
import '../../../models/learn_course.dart';
import '../../../services/learn_service.dart'; import '../../../services/learn_service.dart';
import '../../../services/status_checker_service.dart'; import '../../../services/status_checker_service.dart';
import '../../common/enmus.dart'; import '../../common/enmus.dart';
@ -62,11 +61,6 @@ class LearnModuleViewModel extends ReactiveViewModel {
} }
} }
// Get course
LearnCourse? getUpdatedLearnCourse(int id) {
return _learnService.getLearnCourseById(id);
}
//Refresh image //Refresh image
Future<void> refreshModuleImages(List<LearnModule> modules) async { Future<void> refreshModuleImages(List<LearnModule> modules) async {
for (final module in modules) { for (final module in modules) {

View File

@ -96,11 +96,12 @@ class LearnPracticeViewModel extends ReactiveViewModel {
// Learn practices // Learn practices
List<LearnPractice> _practices = []; List<LearnPractice> _practices = [];
List<LearnPractice> get practices => _practices; List<LearnPractice> get practices => _practices;
final Map<int, String> _refreshedImages = {}; final Map<int, String> _refreshedImages= {};
Map<int, String> get refreshedImages => _refreshedImages; Map<int, String> get refreshedImages => _refreshedImages;
@ -250,6 +251,7 @@ class LearnPracticeViewModel extends ReactiveViewModel {
); );
await playVoicePrompt(_questions[index]); await playVoicePrompt(_questions[index]);
} else { } else {
await completeLearnPractices();
goTo(3); goTo(3);
} }
} }
@ -281,11 +283,11 @@ class LearnPracticeViewModel extends ReactiveViewModel {
if (await _statusChecker.checkConnection()) { if (await _statusChecker.checkConnection()) {
if (practice == LearnPractices.course) { if (practice == LearnPractices.course) {
_practices = await _apiService.getLearnCoursePractices(id); _practices = await _apiService.getLearnCoursePractices(id);
// await refreshPracticeImages(_practices); // await refreshPracticeImages(_practices);
await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0);
} else if (practice == LearnPractices.module) { } else if (practice == LearnPractices.module) {
_practices = await _apiService.getLearnModulePractices(id); _practices = await _apiService.getLearnModulePractices(id);
// await refreshPracticeImages(_practices); // await refreshPracticeImages(_practices);
await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0); await _getLearnPracticeQuestions(_practices.first.questionSetId ?? 0);
} else { } else {
_practices = await _apiService.getLearnLessonPractices(id); _practices = await _apiService.getLearnLessonPractices(id);
@ -329,4 +331,5 @@ class LearnPracticeViewModel extends ReactiveViewModel {
String getPracticeImage(LearnPractice practice) => String getPracticeImage(LearnPractice practice) =>
getReadableUrl(_refreshedImages[practice.id] ?? '') ?? ''; getReadableUrl(_refreshedImages[practice.id] ?? '') ?? '';
} }

View File

@ -169,7 +169,6 @@ class InteractLearnPracticeScreen
Widget _buildSpeakingIndicator(LearnPracticeViewModel viewModel) => Widget _buildSpeakingIndicator(LearnPracticeViewModel viewModel) =>
WaveWrapper(height: 200, child: _buildSpinnerState(viewModel)); WaveWrapper(height: 200, child: _buildSpinnerState(viewModel));
Widget _buildSpinnerState(LearnPracticeViewModel viewModel) => Widget _buildSpinnerState(LearnPracticeViewModel viewModel) =>
viewModel.busy(StateObjects.recordLearnPracticeAnswer) || viewModel.busy(StateObjects.recordLearnPracticeAnswer) ||
viewModel.busy(StateObjects.finishLearnPracticeQuestion) viewModel.busy(StateObjects.finishLearnPracticeQuestion)

View File

@ -13,8 +13,8 @@ import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> { class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
const LearningGoalFormScreen({super.key}); const LearningGoalFormScreen({super.key});
IconData getIcon(int index) { IconData getIcon(int icon) {
switch (index) { switch (icon) {
case 0: case 0:
return Iconsax.book; return Iconsax.book;
case 1: case 1:
@ -25,31 +25,6 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
return Icons.book; return Icons.book;
} }
String getTitles(int index) {
switch (index) {
case 0:
return 'Learn to Speak English';
case 1:
return 'Practice Speaking English';
case 2:
return 'Skill-based Courses';
}
return '';
}
String getSubtitle(int index) {
switch (index) {
case 0:
return 'I know some English, but i want to learn to speak it';
case 1:
return 'I already speak English, but I want more practice.';
case 2:
return 'I want courses for IELTS, TOEFL, Duolingo, or work';
}
return '';
}
void _pop(OnboardingViewModel viewModel) { void _pop(OnboardingViewModel viewModel) {
viewModel.resetLearningGoalFormScreen(); viewModel.resetLearningGoalFormScreen();
viewModel.goBack(); viewModel.goBack();
@ -70,20 +45,17 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
Widget build(BuildContext context, OnboardingViewModel viewModel) => Widget build(BuildContext context, OnboardingViewModel viewModel) =>
_buildScaffoldWrapper(viewModel); _buildScaffoldWrapper(viewModel);
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
Scaffold(
backgroundColor: kcBackgroundColor, backgroundColor: kcBackgroundColor,
body: _buildScaffold(viewModel), body: _buildScaffold(viewModel),
); );
Widget _buildScaffold(OnboardingViewModel viewModel) => Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: _buildScaffoldChildren(viewModel), children: _buildScaffoldChildren(viewModel),
); );
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [
[
_buildAppBar(viewModel), _buildAppBar(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildExpandedBody(viewModel) _buildExpandedBody(viewModel)
@ -97,14 +69,12 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
child: _buildBodyWrapper(viewModel), child: _buildBodyWrapper(viewModel),
); );
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: _buildBody(viewModel), child: _buildBody(viewModel),
); );
Widget _buildBody(OnboardingViewModel viewModel) => Widget _buildBody(OnboardingViewModel viewModel) => Column(
Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _buildBodyChildren(viewModel), children: _buildBodyChildren(viewModel),
@ -113,23 +83,20 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) => List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)]; [_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: _buildUpperColumnChildren(viewModel), children: _buildUpperColumnChildren(viewModel),
); );
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
[
verticalSpaceMedium, verticalSpaceMedium,
_buildTitle(viewModel), _buildTitle(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildLearningGoals(viewModel) _buildLearningGoals(viewModel)
]; ];
Widget _buildAppBar(OnboardingViewModel viewModel) => Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
LargeAppBar(
showBackButton: true, showBackButton: true,
showLanguageSelection: true, showLanguageSelection: true,
onPop: () => _pop(viewModel), onPop: () => _pop(viewModel),
@ -139,11 +106,10 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
: viewModel.selectedLanguage['code'], : viewModel.selectedLanguage['code'],
); );
Widget _buildTitle(OnboardingViewModel viewModel) => Widget _buildTitle(OnboardingViewModel viewModel) => Text.rich(
Text.rich(
TextSpan( TextSpan(
text: text:
'${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},', '${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},',
style: style18P600.copyWith(fontSize: 22), style: style18P600.copyWith(fontSize: 22),
children: [ children: [
TextSpan( TextSpan(
@ -153,39 +119,30 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
]), ]),
); );
Widget _buildLearningGoals(OnboardingViewModel viewModel) => Widget _buildLearningGoals(OnboardingViewModel viewModel) => ListView.builder(
ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: 3,// viewModel.learningGoals.length, itemCount: viewModel.learningGoals.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => itemBuilder: (context, index) => _buildLearningGoal(
_buildLearningGoal( title: viewModel.learningGoals[index].label ?? '',
icon: getIcon(index), selected:
title: getTitles(index),
subtitle: getSubtitle(index),
selected:
viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]), viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]),
onTap: () => onTap: () =>
viewModel.setSelectedLearningGoal( viewModel.setSelectedLearningGoal(viewModel.learningGoals[index]),
viewModel.learningGoals[index]), ),
),
); );
Widget _buildLearningGoal({required String title, Widget _buildLearningGoal(
required bool selected, {required String title,
required IconData icon, required bool selected,
required String subtitle, required GestureTapCallback onTap}) =>
required GestureTapCallback onTap}) =>
CustomLargeRadioButton( CustomLargeRadioButton(
icon:icon,
title: title, title: title,
onTap: onTap, onTap: onTap,
subtitle: subtitle,
selected: selected, selected: selected,
); );
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
Padding(
padding: const EdgeInsets.only(bottom: 50), padding: const EdgeInsets.only(bottom: 50),
child: _buildContinueButton(viewModel), child: _buildContinueButton(viewModel),
); );

View File

@ -5,76 +5,58 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart';
class CustomLargeRadioButton extends StatelessWidget { class CustomLargeRadioButton extends StatelessWidget {
final String title; final String title;
final bool selected; final bool selected;
final IconData icon;
final String subtitle;
final GestureTapCallback? onTap; final GestureTapCallback? onTap;
const CustomLargeRadioButton( const CustomLargeRadioButton({
{super.key, super.key,
this.onTap, this.onTap,
required this.title, required this.title,
required this.icon, required this.selected,
required this.selected, });
required this.subtitle});
@override @override
Widget build(BuildContext context) => _buildButtonWrapper(); Widget build(BuildContext context) => _buildButtonWrapper();
Widget _buildButtonWrapper() => Container( Widget _buildButtonWrapper() => Container(
height: 125, height: 75,
width: double.maxFinite, width: double.maxFinite,
margin: const EdgeInsets.only(bottom: 15), margin: const EdgeInsets.only(bottom: 15),
child: _buildContainerWrapper(), child: _buildContainerWrapper(),
); );
Widget _buildContainerWrapper() => GestureDetector( Widget _buildContainerWrapper() => GestureDetector(
onTap: onTap, onTap: onTap,
child: _buildContainer(), child: _buildContainer(),
); );
Widget _buildContainer() => Container( Widget _buildContainer() => Container(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
color: selected ? kcPrimaryColor.withOpacity(0.1) : kcWhite, color: selected ? kcPrimaryColor.withOpacity(0.1) : kcWhite,
border: Border.all( border: Border.all(
color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75), color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75),
), ),
), ),
child: _buildButtonColumnWrapper(), child: _buildButtonRowWrapper(),
); );
Widget _buildButtonColumnWrapper() => Column( Widget _buildButtonRowWrapper() => Row(
crossAxisAlignment: CrossAxisAlignment.start, children: _buildButtonRowChildren(),
children: _buildButtonRowChildren(), );
);
List<Widget> _buildButtonRowChildren() => List<Widget> _buildButtonRowChildren() =>
[_buildIconSectionWrapper(), _buildTitle(), _buildSubtitle()]; [_buildTitleWrapper(), _buildSelectedCheckBox()];
Widget _buildIconSectionWrapper() => Row( Widget _buildTitleWrapper() => Expanded(
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: _buildTitle(),
children: _buildIconSectionChildren(), );
);
List<Widget> _buildIconSectionChildren() =>
[_buildLeadingIcon(), _buildSelectedCheckBox()];
Widget _buildLeadingIcon() => Icon(
icon,
size: 25,
color: kcPrimaryColor,
);
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
title, title,
style: style18DG700, maxLines: 1,
); style: style16DG400,
);
Widget _buildSubtitle() => Text(
subtitle,
style: const TextStyle(color: kcMediumGrey),
);
Widget _buildSelectedCheckBox() => Checkbox( Widget _buildSelectedCheckBox() => Checkbox(
value: selected, value: selected,

View File

@ -1,8 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:yimaru_app/ui/common/app_colors.dart'; import 'package:yimaru_app/ui/common/app_colors.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import 'package:yimaru_app/ui/common/ui_helpers.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart';
import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart'; import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart';
@ -10,7 +8,6 @@ import 'custom_elevated_button.dart';
class FinishPracticeSheet extends StatelessWidget { class FinishPracticeSheet extends StatelessWidget {
final GestureTapCallback? onTap; final GestureTapCallback? onTap;
const FinishPracticeSheet({super.key, this.onTap}); const FinishPracticeSheet({super.key, this.onTap});
@override @override
@ -23,7 +20,6 @@ class FinishPracticeSheet extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: _buildColumn(), child: _buildColumn(),
); );
Widget _buildColumn() => Column( Widget _buildColumn() => Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: _buildSheetChildren(), children: _buildSheetChildren(),
@ -44,7 +40,7 @@ class FinishPracticeSheet extends StatelessWidget {
); );
Widget _buildMessage() => Text( Widget _buildMessage() => Text(
LocaleKeys.finish_all_practice.tr(), 'Finish all the practices in the lessons to take this practice',
style: style16DG600, style: style16DG600,
textAlign: TextAlign.center, textAlign: TextAlign.center,
); );
@ -52,9 +48,9 @@ class FinishPracticeSheet extends StatelessWidget {
Widget _buildContinueButton() => CustomElevatedButton( Widget _buildContinueButton() => CustomElevatedButton(
height: 55, height: 55,
onTap: onTap, onTap: onTap,
text: 'Continue',
borderRadius: 12, borderRadius: 12,
foregroundColor: kcWhite, foregroundColor: kcWhite,
text: LocaleKeys.cont.tr(),
backgroundColor: kcPrimaryColor, backgroundColor: kcPrimaryColor,
); );
} }

View File

@ -13,20 +13,26 @@ import 'custom_elevated_button.dart';
class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> { class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
final LearnCourse course; final LearnCourse course;
final GestureTapCallback? onViewTap; final GestureTapCallback? onViewTap;
final GestureTapCallback? onLockTap;
final GestureTapCallback? onPracticeTap; final GestureTapCallback? onPracticeTap;
const LearnCourseTile({ const LearnCourseTile({
super.key, super.key,
this.onViewTap, this.onViewTap,
this.onLockTap,
this.onPracticeTap, this.onPracticeTap,
required this.course, required this.course,
}); });
@override @override
Widget build(BuildContext context, LearnCourseViewModel viewModel) => Widget build(BuildContext context, LearnCourseViewModel viewModel) =>
_buildExpansionTileCard(viewModel); _buildExpansionTileCardWrapper(viewModel);
Widget _buildExpansionTileCardWrapper(LearnCourseViewModel viewModel) =>
GestureDetector(
onTap: !(course.access?.isAccessible ?? false) ? onLockTap : null,
child: _buildExpansionTileCard(viewModel),
);
Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container( Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container(
margin: const EdgeInsets.only(bottom: 15), margin: const EdgeInsets.only(bottom: 15),

View File

@ -27,8 +27,6 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
required this.index, required this.index,
required this.lesson}); required this.lesson});
@override @override
Widget build(BuildContext context, LearnLessonViewModel viewModel) => Widget build(BuildContext context, LearnLessonViewModel viewModel) =>
_buildContainer(viewModel); _buildContainer(viewModel);

View File

@ -21,7 +21,14 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
const LearnModuleTile( const LearnModuleTile(
{super.key, this.onModuleTap, this.onPracticeTap, required this.module}); {super.key, this.onModuleTap, this.onPracticeTap, required this.module});
Future<void> _showSheet(
{required BuildContext context,
required LearnModuleViewModel viewModel}) async =>
await showModalBottomSheet(
context: context,
backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel),
);
@override @override
Widget build(BuildContext context, LearnModuleViewModel viewModel) => Widget build(BuildContext context, LearnModuleViewModel viewModel) =>
@ -214,7 +221,9 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
text: LocaleKeys.take_practice.tr(), text: LocaleKeys.take_practice.tr(),
); );
Widget _buildSheet(LearnModuleViewModel viewModel) => FinishPracticeSheet(
onTap: viewModel.pop,
);
Widget _buildContainerShaderState() => !(module.access?.isAccessible ?? false) Widget _buildContainerShaderState() => !(module.access?.isAccessible ?? false)
? _buildContainerShader() ? _buildContainerShader()

View File

@ -1,6 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import '../common/app_colors.dart'; import '../common/app_colors.dart';
import '../common/ui_helpers.dart'; import '../common/ui_helpers.dart';
@ -50,8 +48,8 @@ class OverallProgressWrapper extends StatelessWidget {
backgroundColor: kcVeryLightGrey, backgroundColor: kcVeryLightGrey,
); );
Widget _buildSubtitle() => Text( Widget _buildSubtitle() => const Text(
LocaleKeys.keep_up_the_great_work.tr(), 'Keep up the great work! You\'re doing amazing.',
style:style14DG400 , style: TextStyle(color: kcDarkGrey),
); );
} }

View File

@ -1,5 +1,5 @@
name: yimaru_app name: yimaru_app
version: 0.1.26+28 version: 0.1.25+27
publish_to: 'none' publish_to: 'none'
description: A new Flutter project. description: A new Flutter project.