fix(learn): Fix lesson lock logic issue

This commit is contained in:
BisratHailu 2026-05-29 16:14:31 +03:00
parent 8be9516338
commit b6872e2a3f
43 changed files with 705 additions and 660 deletions

View File

@ -501,6 +501,7 @@ class StackedRouter extends _i1.RouterBase {
return _i37.MaterialPageRoute<dynamic>( return _i37.MaterialPageRoute<dynamic>(
builder: (context) => _i21.LearnLessonDetailView( builder: (context) => _i21.LearnLessonDetailView(
key: args.key, key: args.key,
index: args.index,
lesson: args.lesson, lesson: args.lesson,
module: args.module, module: args.module,
hasPractice: args.hasPractice), hasPractice: args.hasPractice),
@ -1083,6 +1084,7 @@ class ForgetPasswordViewArguments {
class LearnLessonDetailViewArguments { class LearnLessonDetailViewArguments {
const LearnLessonDetailViewArguments({ const LearnLessonDetailViewArguments({
this.key, this.key,
required this.index,
required this.lesson, required this.lesson,
required this.module, required this.module,
required this.hasPractice, required this.hasPractice,
@ -1090,6 +1092,8 @@ class LearnLessonDetailViewArguments {
final _i37.Key? key; final _i37.Key? key;
final int index;
final _i40.LearnLesson lesson; final _i40.LearnLesson lesson;
final _i39.LearnModule module; final _i39.LearnModule module;
@ -1098,13 +1102,14 @@ class LearnLessonDetailViewArguments {
@override @override
String toString() { String toString() {
return '{"key": "$key", "lesson": "$lesson", "module": "$module", "hasPractice": "$hasPractice"}'; return '{"key": "$key", "index": "$index", "lesson": "$lesson", "module": "$module", "hasPractice": "$hasPractice"}';
} }
@override @override
bool operator ==(covariant LearnLessonDetailViewArguments other) { bool operator ==(covariant LearnLessonDetailViewArguments other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
return other.key == key && return other.key == key &&
other.index == index &&
other.lesson == lesson && other.lesson == lesson &&
other.module == module && other.module == module &&
other.hasPractice == hasPractice; other.hasPractice == hasPractice;
@ -1113,6 +1118,7 @@ class LearnLessonDetailViewArguments {
@override @override
int get hashCode { int get hashCode {
return key.hashCode ^ return key.hashCode ^
index.hashCode ^
lesson.hashCode ^ lesson.hashCode ^
module.hashCode ^ module.hashCode ^
hasPractice.hashCode; hasPractice.hashCode;
@ -1839,6 +1845,7 @@ extension NavigatorStateExtension on _i46.NavigationService {
Future<dynamic> navigateToLearnLessonDetailView({ Future<dynamic> navigateToLearnLessonDetailView({
_i37.Key? key, _i37.Key? key,
required int index,
required _i40.LearnLesson lesson, required _i40.LearnLesson lesson,
required _i39.LearnModule module, required _i39.LearnModule module,
required bool hasPractice, required bool hasPractice,
@ -1850,7 +1857,11 @@ extension NavigatorStateExtension on _i46.NavigationService {
}) async { }) async {
return navigateTo<dynamic>(Routes.learnLessonDetailView, return navigateTo<dynamic>(Routes.learnLessonDetailView,
arguments: LearnLessonDetailViewArguments( arguments: LearnLessonDetailViewArguments(
key: key, lesson: lesson, module: module, hasPractice: hasPractice), key: key,
index: index,
lesson: lesson,
module: module,
hasPractice: hasPractice),
id: routerId, id: routerId,
preventDuplicates: preventDuplicates, preventDuplicates: preventDuplicates,
parameters: parameters, parameters: parameters,
@ -2430,6 +2441,7 @@ extension NavigatorStateExtension on _i46.NavigationService {
Future<dynamic> replaceWithLearnLessonDetailView({ Future<dynamic> replaceWithLearnLessonDetailView({
_i37.Key? key, _i37.Key? key,
required int index,
required _i40.LearnLesson lesson, required _i40.LearnLesson lesson,
required _i39.LearnModule module, required _i39.LearnModule module,
required bool hasPractice, required bool hasPractice,
@ -2441,7 +2453,11 @@ extension NavigatorStateExtension on _i46.NavigationService {
}) async { }) async {
return replaceWith<dynamic>(Routes.learnLessonDetailView, return replaceWith<dynamic>(Routes.learnLessonDetailView,
arguments: LearnLessonDetailViewArguments( arguments: LearnLessonDetailViewArguments(
key: key, lesson: lesson, module: module, hasPractice: hasPractice), key: key,
index: index,
lesson: lesson,
module: module,
hasPractice: hasPractice),
id: routerId, id: routerId,
preventDuplicates: preventDuplicates, preventDuplicates: preventDuplicates,
parameters: parameters, parameters: parameters,

View File

@ -1,6 +1,7 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
part 'access.g.dart'; part 'access.g.dart';
@JsonSerializable() @JsonSerializable()
class Access { class Access {
final String? reason; final String? reason;
@ -48,15 +49,13 @@ class Access {
isCompleted: isCompleted ?? this.isCompleted, isCompleted: isCompleted ?? this.isCompleted,
isAccessible: isAccessible ?? this.isAccessible, isAccessible: isAccessible ?? this.isAccessible,
progressPercentPrecise: progressPercentPrecise:
progressPercentPrecise ?? this.progressPercentPrecise, progressPercentPrecise ?? this.progressPercentPrecise,
completedCount: completedCount ?? this.completedCount, completedCount: completedCount ?? this.completedCount,
progressPercent: progressPercent ?? this.progressPercent, progressPercent: progressPercent ?? this.progressPercent,
); );
} }
factory Access.fromJson(Map<String, dynamic> json) => factory Access.fromJson(Map<String, dynamic> json) => _$AccessFromJson(json);
_$AccessFromJson(json);
Map<String, dynamic> toJson() => _$AccessToJson(this); Map<String, dynamic> toJson() => _$AccessToJson(this);
} }

View File

@ -15,16 +15,14 @@ class CourseProgress {
final List<ModuleProgress>? modules; final List<ModuleProgress>? modules;
@JsonKey(name: 'program_id') @JsonKey(name: 'program_id')
final int? programId; final int? programId;
const CourseProgress( const CourseProgress(
{this.id,this.name,this.access,this.modules,this.programId}); {this.id, this.name, this.access, this.modules, this.programId});
factory CourseProgress.fromJson(Map<String, dynamic> json) => _$CourseProgressFromJson(json); factory CourseProgress.fromJson(Map<String, dynamic> json) =>
_$CourseProgressFromJson(json);
Map<String, dynamic> toJson() => _$CourseProgressToJson(this); Map<String, dynamic> toJson() => _$CourseProgressToJson(this);
} }

View File

@ -35,7 +35,6 @@ class LearnCourse {
int? sortOrder, int? sortOrder,
int? programId, int? programId,
String? description, String? description,
}) { }) {
return LearnCourse( return LearnCourse(
id: id ?? this.id, id: id ?? this.id,
@ -51,4 +50,4 @@ class LearnCourse {
_$LearnCourseFromJson(json); _$LearnCourseFromJson(json);
Map<String, dynamic> toJson() => _$LearnCourseToJson(this); Map<String, dynamic> toJson() => _$LearnCourseToJson(this);
} }

View File

@ -3,6 +3,7 @@ import 'package:json_annotation/json_annotation.dart';
import 'access.dart'; import 'access.dart';
part 'learn_lesson.g.dart'; part 'learn_lesson.g.dart';
@JsonSerializable() @JsonSerializable()
class LearnLesson { class LearnLesson {
final int? id; final int? id;
@ -44,7 +45,6 @@ class LearnLesson {
String? videoUrl, String? videoUrl,
String? thumbnail, String? thumbnail,
String? description, String? description,
}) { }) {
return LearnLesson( return LearnLesson(
id: id ?? this.id, id: id ?? this.id,
@ -62,4 +62,4 @@ class LearnLesson {
_$LearnLessonFromJson(json); _$LearnLessonFromJson(json);
Map<String, dynamic> toJson() => _$LearnLessonToJson(this); Map<String, dynamic> toJson() => _$LearnLessonToJson(this);
} }

View File

@ -2,6 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
import 'package:yimaru_app/models/access.dart'; import 'package:yimaru_app/models/access.dart';
part 'learn_module.g.dart'; part 'learn_module.g.dart';
@JsonSerializable() @JsonSerializable()
class LearnModule { class LearnModule {
final int? id; final int? id;
@ -43,7 +44,6 @@ class LearnModule {
int? programId, int? programId,
int? sortOrder, int? sortOrder,
String? description, String? description,
}) { }) {
return LearnModule( return LearnModule(
id: id ?? this.id, id: id ?? this.id,
@ -54,7 +54,6 @@ class LearnModule {
sortOrder: sortOrder ?? this.sortOrder, sortOrder: sortOrder ?? this.sortOrder,
programId: programId ?? this.programId, programId: programId ?? this.programId,
description: description ?? this.description, description: description ?? this.description,
); );
} }
@ -62,4 +61,4 @@ class LearnModule {
_$LearnModuleFromJson(json); _$LearnModuleFromJson(json);
Map<String, dynamic> toJson() => _$LearnModuleToJson(this); Map<String, dynamic> toJson() => _$LearnModuleToJson(this);
} }

View File

@ -2,6 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
import 'package:yimaru_app/models/access.dart'; import 'package:yimaru_app/models/access.dart';
part 'learn_program.g.dart'; part 'learn_program.g.dart';
@JsonSerializable() @JsonSerializable()
class LearnProgram { class LearnProgram {
final int? id; final int? id;
@ -43,4 +44,4 @@ class LearnProgram {
_$LearnProgramFromJson(json); _$LearnProgramFromJson(json);
Map<String, dynamic> toJson() => _$LearnProgramToJson(this); Map<String, dynamic> toJson() => _$LearnProgramToJson(this);
} }

View File

@ -15,11 +15,10 @@ class LessonProgress {
@JsonKey(name: 'module_id') @JsonKey(name: 'module_id')
final int? moduleId; final int? moduleId;
const LessonProgress({this.id, this.title, this.access, this.moduleId});
const LessonProgress( factory LessonProgress.fromJson(Map<String, dynamic> json) =>
{this.id,this.title,this.access,this.moduleId}); _$LessonProgressFromJson(json);
factory LessonProgress.fromJson(Map<String, dynamic> json) => _$LessonProgressFromJson(json);
Map<String, dynamic> toJson() => _$LessonProgressToJson(this); Map<String, dynamic> toJson() => _$LessonProgressToJson(this);
} }

View File

@ -15,10 +15,10 @@ class ProgressSummary {
final List<CourseProgress>? courses; final List<CourseProgress>? courses;
const ProgressSummary( const ProgressSummary({this.id, this.name, this.access, this.courses});
{this.id,this.name,this.access,this.courses});
factory ProgressSummary.fromJson(Map<String, dynamic> json) => _$ProgressSummaryFromJson(json); factory ProgressSummary.fromJson(Map<String, dynamic> json) =>
_$ProgressSummaryFromJson(json);
Map<String, dynamic> toJson() => _$ProgressSummaryToJson(this); Map<String, dynamic> toJson() => _$ProgressSummaryToJson(this);
} }

View File

@ -101,7 +101,6 @@ class AuthenticationService with ListenableServiceMixin {
await _secureService.setString('firstName', data.firstName ?? ''); await _secureService.setString('firstName', data.firstName ?? '');
await _secureService.setString('occupation', data.occupation ?? ''); await _secureService.setString('occupation', data.occupation ?? '');
_user = User( _user = User(
email: data.email, email: data.email,
gender: data.gender, gender: data.gender,

View File

@ -17,7 +17,7 @@ class LearnService with ListenableServiceMixin {
// Initialization // Initialization
learnService() { learnService() {
listenToReactiveValues([_programs,_courses, _lessons, _modules]); listenToReactiveValues([_programs, _courses, _lessons, _modules]);
} }
// Learn program // Learn program
@ -148,11 +148,10 @@ class LearnService with ListenableServiceMixin {
); );
}).toList(); }).toList();
print('MY SUMMARIES - COMPLETED COUNT: ${_modules.first.access?.completedCount}'); print(
'MY SUMMARIES - COMPLETED COUNT: ${_modules.first.access?.completedCount}');
print('PROGRESS PERCENT: ${_modules.first.access?.progressPercent}'); 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(
@ -169,8 +168,6 @@ class LearnService with ListenableServiceMixin {
} catch (_) { } catch (_) {
return null; return null;
} }
} }
LearnCourse? getLearnCourseById(int id) { LearnCourse? getLearnCourseById(int id) {
@ -179,7 +176,5 @@ class LearnService with ListenableServiceMixin {
} catch (_) { } catch (_) {
return null; return null;
} }
} }
} }

View File

@ -130,7 +130,7 @@ class NotificationService {
} }
Future<void> updateFCMToken() async { Future<void> updateFCMToken() async {
// print('DEVICE TOKEN: ${await _messaging.getToken()}'); // print('DEVICE TOKEN: ${await _messaging.getToken()}');
_messaging.onTokenRefresh.listen((newToken) { _messaging.onTokenRefresh.listen((newToken) {
// updateTokenOnServer(newToken); // updateTokenOnServer(newToken);
}); });

View File

@ -111,6 +111,5 @@ class OnboardingService with ListenableServiceMixin {
_regions = await _apiService.getEthiopiaRegions(); _regions = await _apiService.getEthiopiaRegions();
notifyListeners(); notifyListeners();
} }
} }

View File

@ -6,7 +6,7 @@ import 'dart:ui';
import 'package:easy_localization/easy_localization.dart' show AssetLoader; import 'package:easy_localization/easy_localization.dart' show AssetLoader;
class CodegenLoader extends AssetLoader{ class CodegenLoader extends AssetLoader {
const CodegenLoader(); const CodegenLoader();
@override @override
@ -14,379 +14,403 @@ class CodegenLoader extends AssetLoader{
return Future.value(mapLocales[locale.toString()]); return Future.value(mapLocales[locale.toString()]);
} }
static const Map<String,dynamic> _am = { static const Map<String, dynamic> _am = {
"loading": "በመጫን ላይ", "loading": "በመጫን ላይ",
"welcome_back": "እንኳን በደህና ተመለሱ", "welcome_back": "እንኳን በደህና ተመለሱ",
"checking_user_info": "የተጠቃሚ መረጃን በማረጋገጥ ላይ", "checking_user_info": "የተጠቃሚ መረጃን በማረጋገጥ ላይ",
"dont_have_account": "መለያ የለዎትም?", "dont_have_account": "መለያ የለዎትም?",
"email": "ኢሜይል", "email": "ኢሜይል",
"password": "የይለፍ ቃል", "password": "የይለፍ ቃል",
"forgot_password": "የይለፍ ቃል ረሱ?", "forgot_password": "የይለፍ ቃል ረሱ?",
"cont": "ቀጥል", "cont": "ቀጥል",
"register": "ይመዝገቡ", "register": "ይመዝገቡ",
"login_with_google": "በጉግል ይግቡ", "login_with_google": "በጉግል ይግቡ",
"or": "ወይም", "or": "ወይም",
"login_with_phone": "በስልክ ቁጥር ይግቡ", "login_with_phone": "በስልክ ቁጥር ይግቡ",
"create_account": "አዲስ መለያ ይፍጠሩ", "create_account": "አዲስ መለያ ይፍጠሩ",
"already_have_account": "መለያ አለዎት?", "already_have_account": "መለያ አለዎት?",
"login": " ይግቡ ", "login": " ይግቡ ",
"register_with_google": "በጉግል ይመዝገቡ", "register_with_google": "በጉግል ይመዝገቡ",
"register_with_phone": "በስልክ ቁጥር ይመዝገቡ", "register_with_phone": "በስልክ ቁጥር ይመዝገቡ",
"enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።", "enter_phone_number": "የስልክ ቁጥርዎን ያስገቡ። የማረጋገጫ ኮድ እንልክልዎታለን።",
"login_with_email": "በኢሜይል ይግቡ", "login_with_email": "በኢሜይል ይግቡ",
"create_password": "የይለፍ ቃል ይፍጠሩ", "create_password": "የይለፍ ቃል ይፍጠሩ",
"confirm_password": "የይለፍ ቃል ያረጋግጡ", "confirm_password": "የይለፍ ቃል ያረጋግጡ",
"eight_character_minimum": "ቢያንስ 8 ፊደላት", "eight_character_minimum": "ቢያንስ 8 ፊደላት",
"password_match": "የይለፍ ቃሉ ተመሳስሏል", "password_match": "የይለፍ ቃሉ ተመሳስሏል",
"sign_up_agreement": "‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።", "sign_up_agreement":
"terms_of_services": "የአገልግሎት ውሎች", "‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።",
"and": "እና", "terms_of_services": "የአገልግሎት ውሎች",
"privacy_policy": "የግላዊነት ፖሊሲ", "and": "እና",
"register_with_email": "በኢሜል ይመዝገቡ", "privacy_policy": "የግላዊነት ፖሊሲ",
"verification_code": "የማረጋገጫ ኮድ", "register_with_email": "በኢሜል ይመዝገቡ",
"resend_code": "ኮዱን እንደገና ላክ", "verification_code": "የማረጋገጫ ኮድ",
"code_sent_to_phone": "ኮዱ ወደ ስልክ ቁጥርዎ ተልኳል", "resend_code": "ኮዱን እንደገና ላክ",
"code_sent_to_email": "ኮዱ ወደ ኢሜል ተልኳል", "code_sent_to_phone": "ኮዱ ወደ ስልክ ቁጥርዎ ተልኳል",
"resend_code_in": "ኮዱን እንደገና ለመላክ የቀረው ጊዜ", "code_sent_to_email": "ኮዱ ወደ ኢሜል ተልኳል",
"reset_password": " የይለፍ ቃልን ይቀይሩ", "resend_code_in": "ኮዱን እንደገና ለመላክ የቀረው ጊዜ",
"enter_email_reset_code": "ኢሜይልዎን ያስገቡ። የይለፍ ቃል መለወጫ ኮድ እንልክልዎታለን።", "reset_password": " የይለፍ ቃልን ይቀይሩ",
"please_wait": "እባክዎ ይጠብቁ", "enter_email_reset_code": "ኢሜይልዎን ያስገቡ። የይለፍ ቃል መለወጫ ኮድ እንልክልዎታለን።",
"reset_code_sent": "የመቀየሪያ ኮድ በተሳካ ሁኔታ ተልኳል", "please_wait": "እባክዎ ይጠብቁ",
"reset_code": " የመቀየሪያ ኮድ ", "reset_code_sent": "የመቀየሪያ ኮድ በተሳካ ሁኔታ ተልኳል",
"new_password": "አዲስ የይለፍ ቃል", "reset_code": " የመቀየሪያ ኮድ ",
"logged_in_successfully": "በተሳካ ሁኔታ ገብተዋል", "new_password": "አዲስ የይለፍ ቃል",
"view_course": " ኮርሱን ይመልከቱ", "logged_in_successfully": "በተሳካ ሁኔታ ገብተዋል",
"continue_learning": "መማርን ይቀጥሉ", "view_course": " ኮርሱን ይመልከቱ",
"start_learning": "ትምህርትን ይጀምሩ", "continue_learning": "መማርን ይቀጥሉ",
"completed": "ተጠናቋል", "start_learning": "ትምህርትን ይጀምሩ",
"take_practice": "ልምምድ ያድርጉ", "completed": "ተጠናቋል",
"your_current_level": "የአሁኑ ደረጃዎ", "take_practice": "ልምምድ ያድርጉ",
"overall_progress": "አጠቃላይ እድገት", "your_current_level": "የአሁኑ ደረጃዎ",
"great_work": "በርቱ! በጣም ጥሩ እየሰሩ ነው", "overall_progress": "አጠቃላይ እድገት",
"view_module": "ሞጁሉን ይመልከቱ", "great_work": "በርቱ! በጣም ጥሩ እየሰሩ ነው",
"progress": "እድገት", "view_module": "ሞጁሉን ይመልከቱ",
"keep_going": "ይቀጥሉ - ከግማሽ በላይ ጨርሰዋል ", "progress": "እድገት",
"lessons_in_module": "በዚህ ሞጁል ውስጥ ያሉ ትምህርቶች ", "keep_going": "ይቀጥሉ - ከግማሽ በላይ ጨርሰዋል ",
"practice": "ልምምድ", "lessons_in_module": "በዚህ ሞጁል ውስጥ ያሉ ትምህርቶች ",
"start": "ጀምር", "practice": "ልምምድ",
"in_progress": "በሂደት ላይ", "start": "ጀምር",
"hello": "ሰላም", "in_progress": "በሂደት ላይ",
"ready_to_learn": " ዛሬ እንግሊዝኛ ለመማር ተዘጋጅተዋል? ", "hello": "ሰላም",
"learn": "ይማሩ ", "ready_to_learn": " ዛሬ እንግሊዝኛ ለመማር ተዘጋጅተዋል? ",
"course": "ኮርስ", "learn": "ይማሩ ",
"profile": " ፕሮፋይል ", "course": "ኮርስ",
"speaking_partner": "የንግግር ጓደኛ", "profile": " ፕሮፋይል ",
"practice_what_you_learned": "አሁን የተማሩትን እንለማመድ", "speaking_partner": "የንግግር ጓደኛ",
"practice_questions": "ጥቂት ጥያቄዎችን እጠይቃለሁ እና መልስ መስጠት ይችላሉ", "practice_what_you_learned": "አሁን የተማሩትን እንለማመድ",
"start_practice": "ልምምድ ጀምር", "practice_questions": "ጥቂት ጥያቄዎችን እጠይቃለሁ እና መልስ መስጠት ይችላሉ",
"almost_there": "ሊጨርሱ ተቃርበዋል", "start_practice": "ልምምድ ጀምር",
"finish_session": "እድገትዎን ለማየት ክፍለ ጊዜውን ያጠናቅቁ", "almost_there": "ሊጨርሱ ተቃርበዋል",
"continue_practice": "ልምምዱን ይቀጥሉ", "finish_session": "እድገትዎን ለማየት ክፍለ ጊዜውን ያጠናቅቁ",
"end_session": "ክፍለ ጊዜውን ያብቁ ", "continue_practice": "ልምምዱን ይቀጥሉ",
"tap_start_to_listen": "ለማዳመጥ የጀምር ቁልፉን ይጫኑ", "end_session": "ክፍለ ጊዜውን ያብቁ ",
"practice_speaking": "ንግግርን ይለማመዱ", "tap_start_to_listen": "ለማዳመጥ የጀምር ቁልፉን ይጫኑ",
"tap_microphone": "ለመናገር ማይክሮፎኑን ይጫኑ", "practice_speaking": "ንግግርን ይለማመዱ",
"reply": "እንደገና አዳምጥ", "tap_microphone": "ለመናገር ማይክሮፎኑን ይጫኑ",
"cancel": "ይቅር", "reply": "እንደገና አዳምጥ",
"you_are_speaking": "እየተናገሩ ነው", "cancel": "ይቅር",
"practice_completed": "ልምምዱ ተጠናቅቋል", "you_are_speaking": "እየተናገሩ ነው",
"great_improvement": "በዚህኛው በራስ መተማመንዎ ጨምሯል፤ ትልቅ መሻሻል ነው", "practice_completed": "ልምምዱ ተጠናቅቋል",
"practice_again": "እንደገና ይለማመዱ", "great_improvement": "በዚህኛው በራስ መተማመንዎ ጨምሯል፤ ትልቅ መሻሻል ነው",
"conversation_review": "የንግግር ግምገማ", "practice_again": "እንደገና ይለማመዱ",
"result": "ውጤት", "conversation_review": "የንግግር ግምገማ",
"quick_tip": "ጠቃሚ ምክር", "result": "ውጤት",
"retry": "እንደገና ይሞክሩ", "quick_tip": "ጠቃሚ ምክር",
"completed_a1": "እንኳን ደስ አለዎት! A1 ደረጃን አጠናቅቀዋል", "retry": "እንደገና ይሞክሩ",
"analyzing_speaking": "የንግግር ችሎታዎን እየገመገምን ነው", "completed_a1": "እንኳን ደስ አለዎት! A1 ደረጃን አጠናቅቀዋል",
"view_profile": "ፕሮፋይሎን ይመልከቱ ", "analyzing_speaking": "የንግግር ችሎታዎን እየገመገምን ነው",
"hi": "ሰላም", "view_profile": "ፕሮፋይሎን ይመልከቱ ",
"edit_profile": "መገለጫ ያስተካክሉ", "hi": "ሰላም",
"first_name": "የመጀመሪያ ስም", "edit_profile": "መገለጫ ያስተካክሉ",
"last_name": "የአባት ስም", "first_name": "የመጀመሪያ ስም",
"gender": "ፆታ", "last_name": "የአባት ስም",
"male": "ወንድ", "gender": "ፆታ",
"female": "ሴት", "male": "ወንድ",
"phone_number": "የስልክ ቁጥር", "female": "ሴት",
"country": "ሀገር", "phone_number": "የስልክ ቁጥር",
"region": "ክልል", "country": "ሀገር",
"select_region": "ክልል ይምረጡ", "region": "ክልል",
"enter_your_city": "ከተማዎን ያስገቡ", "select_region": "ክልል ይምረጡ",
"occupation": "የስራ መስክ", "enter_your_city": "ከተማዎን ያስገቡ",
"select_occupation": "ሙያዎን ይምረጡ", "occupation": "የስራ መስክ",
"save_changes": "ለውጦችን ያስቀምጡ", "select_occupation": "ሙያዎን ይምረጡ",
"my_progress": "የእኔ እድገት", "save_changes": "ለውጦችን ያስቀምጡ",
"track_your_achievement": "ስኬቶችዎን እና ተከታታይ የትምህርት ጉዞዎን ይከታተሉ", "my_progress": "የእኔ እድገት",
"account_and_privacy": "መለያ እና ግላዊነት", "track_your_achievement": "ስኬቶችዎን እና ተከታታይ የትምህርት ጉዞዎን ይከታተሉ",
"manage_settings": "ቅንብሮችን እና የመተግበሪያ ምርጫዎችን ያስተዳድሩ", "account_and_privacy": "መለያ እና ግላዊነት",
"support": "ድጋፍ", "manage_settings": "ቅንብሮችን እና የመተግበሪያ ምርጫዎችን ያስተዳድሩ",
"get_help": "በስልክ ወይም በቴሌግራም እገዛ ያግኙ", "support": "ድጋፍ",
"logout": "ውጣ", "get_help": "በስልክ ወይም በቴሌግራም እገዛ ያግኙ",
"app_settings": "የመተግበሪያ ቅንብሮች", "logout": "ውጣ",
"legal_and_information": "ሕጋዊ እና መረጃ", "app_settings": "የመተግበሪያ ቅንብሮች",
"change_language": "ቋንቋ ቀይር", "legal_and_information": "ሕጋዊ እና መረጃ",
"terms_and_conditions": "ውሎች እና ሁኔታዎች", "change_language": "ቋንቋ ቀይር",
"delete_account": "መለያ ሰርዝ", "terms_and_conditions": "ውሎች እና ሁኔታዎች",
"language_preference": "የቋንቋ ምርጫ", "delete_account": "መለያ ሰርዝ",
"choose_your_language": "ለውጦችን አስቀምጥ", "language_preference": "የቋንቋ ምርጫ",
"switch_language_anytime": "ቋንቋዎችን በማንኛውም ጊዜ መቀየር ይችላሉ", "choose_your_language": "ለውጦችን አስቀምጥ",
"need_help": "እገዛ ይፈልጋሉ?", "switch_language_anytime": "ቋንቋዎችን በማንኛውም ጊዜ መቀየር ይችላሉ",
"call_support": "የስልክ ድጋፍ", "need_help": "እገዛ ይፈልጋሉ?",
"talk_with_support": "በቀጥታ ከድጋፍ ቡድናችን ጋር ይነጋገሩ", "call_support": "የስልክ ድጋፍ",
"telegram_support": "የቴሌግራም ድጋፍ", "talk_with_support": "በቀጥታ ከድጋፍ ቡድናችን ጋር ይነጋገሩ",
"chat_via_telegram": "በቴሌግራም በፍጥነት ይወያዩ", "telegram_support": "የቴሌግራም ድጋፍ",
"call_our_support": "ከ3 ጠዋት እስከ 12 ማታ ድረስ የድጋፍ ቡድናችንን ይደውሉ", "chat_via_telegram": "በቴሌግራም በፍጥነት ይወያዩ",
"tap_to_call": "ለመደወል ይንኩ", "call_our_support": "ከ3 ጠዋት እስከ 12 ማታ ድረስ የድጋፍ ቡድናችንን ይደውሉ",
"join_telegram": "በቴሌግራም የይማሩ አካዳሚን ይቀላቀሉ", "tap_to_call": "ለመደወል ይንኩ",
"connect_with_support_team": "ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።", "join_telegram": "በቴሌግራም የይማሩ አካዳሚን ይቀላቀሉ",
"open_in_telegram": "በቴሌግራም ይክፈቱ", "connect_with_support_team":
"search_for": "ፈልጉት", "ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።",
"current_level": "የአሁኑ ደረጃ", "open_in_telegram": "በቴሌግራም ይክፈቱ",
"keep_up_the_great_work": "በጣም ጥሩ እየሰራህ ነው! ቀጥልበት፣ አስደናቂ ነህ።", "search_for": "ፈልጉት",
"no_practice_available": "ምንም ልምምድ አልተገኘም!", "current_level": "የአሁኑ ደረጃ",
"begin_module_practice": "የሞጁሉን ልምምድ ጀምር", "keep_up_the_great_work": "በጣም ጥሩ እየሰራህ ነው! ቀጥልበት፣ አስደናቂ ነህ።",
"lets_practice_lesson": "እንለማመድ", "no_practice_available": "ምንም ልምምድ አልተገኘም!",
"lets_quickly_review": "በዚህ ሞጁል ውስጥ የተማርከውን በፍጥነት እንከልስ!", "begin_module_practice": "የሞጁሉን ልምምድ ጀምር",
"lets_practice_module": "አሁን የተማርከውን እንለማመድ!", "lets_practice_lesson": "እንለማመድ",
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።", "lets_quickly_review": "በዚህ ሞጁል ውስጥ የተማርከውን በፍጥነት እንከልስ!",
"begin_level_practice": "የደረጃ ልምምድን ጀምር", "lets_practice_module": "አሁን የተማርከውን እንለማመድ!",
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ", "ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
"lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!", "begin_level_practice": "የደረጃ ልምምድን ጀምር",
"speaking": "እየተናገረ ነው", "lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ", "lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
"view_results": "ውጤቶቼን እይ", "speaking": "እየተናገረ ነው",
"sample_answer": "ናሙና መልስ", "you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
"your_answer": "መልስህ", "view_results": "ውጤቶቼን እይ",
"sound_confident": "በዚህ ጊዜ የበለጠ እምነት ያለህ ይመስላል — በጣም ጥሩ መሻሻል ነው!", "sample_answer": "ናሙና መልስ",
"you_have_completed": "አያይ! አጠናቀቅህ", "your_answer": "መልስህ",
"yes": "አዎ", "sound_confident": "በዚህ ጊዜ የበለጠ እምነት ያለህ ይመስላል — በጣም ጥሩ መሻሻል ነው!",
"no": "አይ", "you_have_completed": "አያይ! አጠናቀቅህ",
"want_to_quit": "ለመውጣት እርግጠኛ ነህ?", "yes": "አዎ",
"required_field": "ይህ መስክ ያስፈልጋል", "no": "አይ",
"enter_full_name": "ሙሉ ስምህን አስገባ", "want_to_quit": "ለመውጣት እርግጠኛ ነህ?",
"invalid_email": "የማይሰራ የኢሜይል ቅርጸት", "required_field": "ይህ መስክ ያስፈልጋል",
"phone_must_start_with": "የስልክ ቁጥር በ251 መጀመር አለበት", "enter_full_name": "ሙሉ ስምህን አስገባ",
"phone_must_be": "የስልክ ቁጥር 12 አሃዞች መሆን አለበት", "invalid_email": "የማይሰራ የኢሜይል ቅርጸት",
"what_should_we_call_you": "ምን ብለን እንጠራህ?", "phone_must_start_with": "የስልክ ቁጥር በ251 መጀመር አለበት",
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።", "phone_must_be": "የስልክ ቁጥር 12 አሃዞች መሆን አለበት",
"choose_your_gender": "ጾታህን ምረጥ", "what_should_we_call_you": "ምን ብለን እንጠራህ?",
"gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።", "name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
"age_range": "በየትኛው የእድሜ ክልል ውስጥ ነህ?", "choose_your_gender": "ጾታህን ምረጥ",
"age_for_personalization": "በእድሜህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።", "gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
"educational_background": "አሁን ያለህ የትምህርት ደረጃ ምንድን ነው?", "age_range": "በየትኛው የእድሜ ክልል ውስጥ ነህ?",
"education_for_personalization": "ይህ ትምህርቶችን ከልምድህ ጋር እንዲስማሙ ለማድረግ ይረዳናል።", "age_for_personalization": "በእድሜህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
"your_occupation": "ስራህ ምንድን ነው?", "educational_background": "አሁን ያለህ የትምህርት ደረጃ ምንድን ነው?",
"occupation_for_personalization": "በስራህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።", "education_for_personalization": "ይህ ትምህርቶችን ከልምድህ ጋር እንዲስማሙ ለማድረግ ይረዳናል።",
"location": "ከየት ነህ?", "your_occupation": "ስራህ ምንድን ነው?",
"select_country_region": "አገርህን እና ክልልህን ከተቆልቋይ ዝርዝሩ ምረጥ", "occupation_for_personalization": "በስራህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።",
"select_country": "አገር ምረጥ", "location": "ከየት ነህ?",
"learning_goal": "የመማር ዓላማህን ምረጥ", "select_country_region": "አገርህን እና ክልልህን ከተቆልቋይ ዝርዝሩ ምረጥ",
"language_goal": "እንግሊዝኛህን ለማሻሻል ዋና ዓላማህ ምንድን ነው?", "select_country": "አገር ምረጥ",
"your_goal": "ዓላማህ የመማር ጉዞህን እንዲስማማ ለማድረግ ይረዳናል።", "learning_goal": "የመማር ዓላማህን ምረጥ",
"write_your_goal": "ዓላማህን ጻፍ…", "language_goal": "እንግሊዝኛህን ለማሻሻል ዋና ዓላማህ ምንድን ነው?",
"challenge_you_face": "What challenge do you face most with English?", "your_goal": "ዓላማህ የመማር ጉዞህን እንዲስማማ ለማድረግ ይረዳናል።",
"evey_one_has_strugle": "ሁሉም ሰው ችግሮች አሉት፣ የአንተን እንጀምር እንፍታ", "write_your_goal": "ዓላማህን ጻፍ…",
"write_your_challenge": "ችግርህን ጻፍ…", "challenge_you_face": "What challenge do you face most with English?",
"topic_interest": "በጣም የሚስቡህ ርዕሶች የትኞቹ ናቸው?", "evey_one_has_strugle": "ሁሉም ሰው ችግሮች አሉት፣ የአንተን እንጀምር እንፍታ",
"favourite_topic": "የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።", "write_your_challenge": "ችግርህን ጻፍ…",
"your_interest": "ፍላጎትህን ጻፍ…", "topic_interest": "በጣም የሚስቡህ ርዕሶች የትኞቹ ናቸው?",
"want_quick_assessment": "የእንግሊዝኛ ደረጃህን ለማወቅ ፈጣን ግምገማ ትፈልጋለህ?", "favourite_topic":
"answer_quick_questions": "የእንግሊዝኛ ችሎታህን ለመረዳት ጥቂት ፈጣን ጥያቄዎችን መልስ።", "የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።",
"skip": "ዝለል", "your_interest": "ፍላጎትህን ጻፍ…",
"finish_level": "ደረጃውን አጠናቅቅ", "want_quick_assessment": "የእንግሊዝኛ ደረጃህን ለማወቅ ፈጣን ግምገማ ትፈልጋለህ?",
"likely_speaker": "አንተ ምናልባት ተናጋሪ ነህ", "answer_quick_questions": "የእንግሊዝኛ ችሎታህን ለመረዳት ጥቂት ፈጣን ጥያቄዎችን መልስ።",
"great_job": "በጣም ጥሩ ስራ! ለመሻሻል ቀጣዩ ደረጃህ ይኸው ነው።", "skip": "ዝለል",
"lets_start_practice": "ልምምድህን እንጀምር", "finish_level": "ደረጃውን አጠናቅቅ",
"welcome_abroad": "እንኳን ደህና መጣህ", "likely_speaker": "አንተ ምናልባት ተናጋሪ ነህ",
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።", "great_job": "በጣም ጥሩ ስራ! ለመሻሻል ቀጣዩ ደረጃህ ይኸው ነው።",
"finish": "አጠናቅቅ", "lets_start_practice": "ልምምድህን እንጀምር",
"finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።" "welcome_abroad": "እንኳን ደህና መጣህ",
}; "ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
static const Map<String,dynamic> _en = { "finish": "አጠናቅቅ",
"loading": "Loading", "finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።"
"welcome_back": "Welcome back", };
"checking_user_info": "Checking user info", static const Map<String, dynamic> _en = {
"dont_have_account": "Don't have an account?", "loading": "Loading",
"email": "Email", "welcome_back": "Welcome back",
"password": "Password", "checking_user_info": "Checking user info",
"forgot_password": "Forgot password?", "dont_have_account": "Don't have an account?",
"cont": "Continue", "email": "Email",
"register": "Register", "password": "Password",
"login_with_google": "Login with Google", "forgot_password": "Forgot password?",
"or": "Or", "cont": "Continue",
"login_with_phone": "Login with phone number", "register": "Register",
"create_account": "Create an account", "login_with_google": "Login with Google",
"already_have_account": "Already have an account?", "or": "Or",
"login": "Login", "login_with_phone": "Login with phone number",
"register_with_google": "Register with Google", "create_account": "Create an account",
"register_with_phone": "Register with phone number", "already_have_account": "Already have an account?",
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.", "login": "Login",
"login_with_email": "Login with email", "register_with_google": "Register with Google",
"create_password": "Create password", "register_with_phone": "Register with phone number",
"confirm_password": "Confirm password", "enter_phone_number":
"eight_character_minimum": "8 characters minimum", "Enter your phone number. We will send you a confirmation code there.",
"password_match": "password match", "login_with_email": "Login with email",
"sign_up_agreement": "By clicking Sign Up, you agree to our Terms of Service and Privacy Policy", "create_password": "Create password",
"terms_of_services": "Terms of Service", "confirm_password": "Confirm password",
"and": "and", "eight_character_minimum": "8 characters minimum",
"privacy_policy": "Privacy Policy", "password_match": "password match",
"register_with_email": "Register with email", "sign_up_agreement":
"verification_code": "Verification Code", "By clicking Sign Up, you agree to our Terms of Service and Privacy Policy",
"resend_code": "Resend Code", "terms_of_services": "Terms of Service",
"code_sent_to_phone": "Code sent to your number", "and": "and",
"code_sent_to_email": "Code sent to your email", "privacy_policy": "Privacy Policy",
"resend_code_in": "Resend code in", "register_with_email": "Register with email",
"reset_password": "Reset Password", "verification_code": "Verification Code",
"enter_email_reset_code": "Enter your email. We will send you a reset code.", "resend_code": "Resend Code",
"please_wait": "Please wait", "code_sent_to_phone": "Code sent to your number",
"reset_code_sent": "Reset code sent successfully", "code_sent_to_email": "Code sent to your email",
"reset_code": "Reset code", "resend_code_in": "Resend code in",
"new_password": "New password", "reset_password": "Reset Password",
"logged_in_successfully": "Logged in successfully", "enter_email_reset_code":
"continue_learning": "Continue Learning", "Enter your email. We will send you a reset code.",
"start_learning": "Start Learning", "please_wait": "Please wait",
"completed": "Completed", "reset_code_sent": "Reset code sent successfully",
"view_course": "View course", "reset_code": "Reset code",
"take_practice": "Take practice", "new_password": "New password",
"your_current_level": "Your current level", "logged_in_successfully": "Logged in successfully",
"overall_progress": "Overall progress", "continue_learning": "Continue Learning",
"great_work": "Keep up the great work! You're doing amazing", "start_learning": "Start Learning",
"view_module": "View module", "completed": "Completed",
"progress": "Progress", "view_course": "View course",
"keep_going": "Let's keep going - you're more than half there", "take_practice": "Take practice",
"lessons_in_module": "Lessons in this module", "your_current_level": "Your current level",
"practice": "Practice", "overall_progress": "Overall progress",
"start": "Start", "great_work": "Keep up the great work! You're doing amazing",
"in_progress": "In Progress", "view_module": "View module",
"hello": "Hello", "progress": "Progress",
"ready_to_learn": "Ready to keep learning English today", "keep_going": "Let's keep going - you're more than half there",
"learn": "Learn", "lessons_in_module": "Lessons in this module",
"course": "Course", "practice": "Practice",
"profile": "Profile", "start": "Start",
"speaking_partner": "Speaking partner", "in_progress": "In Progress",
"practice_what_you_learned": "Let's practice what you just learnt", "hello": "Hello",
"practice_questions": "I will ask you a few questions and you can respond", "ready_to_learn": "Ready to keep learning English today",
"start_practice": "Start practice", "learn": "Learn",
"almost_there": "You're almost there", "course": "Course",
"finish_session": "Finish the session to see your progress", "profile": "Profile",
"continue_practice": "Continue practice", "speaking_partner": "Speaking partner",
"end_session": "End session", "practice_what_you_learned": "Let's practice what you just learnt",
"tap_start_to_listen": "Tap the start button to listen", "practice_questions": "I will ask you a few questions and you can respond",
"practice_speaking": "Practice speaking", "start_practice": "Start practice",
"tap_microphone": "Tap the microphone to speak", "almost_there": "You're almost there",
"reply": "Reply", "finish_session": "Finish the session to see your progress",
"cancel": "Cancel", "continue_practice": "Continue practice",
"you_are_speaking": "You're speaking", "end_session": "End session",
"practice_completed": "Practice completed!", "tap_start_to_listen": "Tap the start button to listen",
"great_improvement": "You sound more confident this time, great improvement", "practice_speaking": "Practice speaking",
"practice_again": "Practice again", "tap_microphone": "Tap the microphone to speak",
"conversation_review": "Conversation review", "reply": "Reply",
"result": "Result", "cancel": "Cancel",
"quick_tip": "Quick tip", "you_are_speaking": "You're speaking",
"retry": "Retry", "practice_completed": "Practice completed!",
"completed_a1": "Yay, you've completed A1", "great_improvement":
"analyzing_speaking": "We're now analyzing your speaking skill", "You sound more confident this time, great improvement",
"view_profile": "View profile", "practice_again": "Practice again",
"hi": "Hi", "conversation_review": "Conversation review",
"edit_profile": "Edit profile", "result": "Result",
"first_name": "First name", "quick_tip": "Quick tip",
"last_name": "Last name", "retry": "Retry",
"gender": "Gender", "completed_a1": "Yay, you've completed A1",
"male": "Male", "analyzing_speaking": "We're now analyzing your speaking skill",
"female": "Female", "view_profile": "View profile",
"phone_number": "Phone number", "hi": "Hi",
"country": "Country", "edit_profile": "Edit profile",
"region": "Region", "first_name": "First name",
"select_region": "Select region", "last_name": "Last name",
"enter_your_city": "Enter your city", "gender": "Gender",
"occupation": "Occupation", "male": "Male",
"select_occupation": "Select occupation", "female": "Female",
"save_changes": "Save changes", "phone_number": "Phone number",
"my_progress": "My progress", "country": "Country",
"track_your_achievement": "Track your achievements and learning streak", "region": "Region",
"account_and_privacy": "Account & Privacy", "select_region": "Select region",
"manage_settings": "Manage settings and app preference", "enter_your_city": "Enter your city",
"support": "Support", "occupation": "Occupation",
"get_help": "Get help through phone or Telegram", "select_occupation": "Select occupation",
"logout": "Logout", "save_changes": "Save changes",
"app_settings": "App settings", "my_progress": "My progress",
"legal_and_information": "Legal & Information", "track_your_achievement": "Track your achievements and learning streak",
"change_language": "Change language", "account_and_privacy": "Account & Privacy",
"terms_and_conditions": "Terms & Conditions", "manage_settings": "Manage settings and app preference",
"delete_account": "Delete account", "support": "Support",
"language_preference": "Language preference", "get_help": "Get help through phone or Telegram",
"choose_your_language": "Choose your language", "logout": "Logout",
"switch_language_anytime": "You can switch languages anytime", "app_settings": "App settings",
"need_help": "Need help?", "legal_and_information": "Legal & Information",
"call_support": "Call support", "change_language": "Change language",
"talk_with_support": "Talk with our support team directly", "terms_and_conditions": "Terms & Conditions",
"telegram_support": "Telegram support", "delete_account": "Delete account",
"chat_via_telegram": "Chat instantly via Telegram", "language_preference": "Language preference",
"call_our_support": "Call our support team between 9 AM - 6 PM", "choose_your_language": "Choose your language",
"tap_to_call": "Tap to call", "switch_language_anytime": "You can switch languages anytime",
"join_telegram": "Join Yimaru Academy on Telegram", "need_help": "Need help?",
"connect_with_support_team": "Connect with our support team instantly on Telegram for quick assistance and community updates", "call_support": "Call support",
"open_in_telegram": "Open in Telegram", "talk_with_support": "Talk with our support team directly",
"search_for": "Search for", "telegram_support": "Telegram support",
"current_level": "Current Level", "chat_via_telegram": "Chat instantly via Telegram",
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.", "call_our_support": "Call our support team between 9 AM - 6 PM",
"no_practice_available": "No practice available!", "tap_to_call": "Tap to call",
"begin_module_practice": "Begin Module Practice", "join_telegram": "Join Yimaru Academy on Telegram",
"lets_practice_lesson": "Lets Practice", "connect_with_support_team":
"lets_quickly_review": "Lets quickly review what youve learned in this module!", "Connect with our support team instantly on Telegram for quick assistance and community updates",
"lets_practice_module": "Let's practice what you just learnt!", "open_in_telegram": "Open in Telegram",
"ask_you_few_actions": "Ill ask you a few questions, and you can respond naturally.", "search_for": "Search for",
"begin_level_practice": "Begin Level Practice", "current_level": "Current Level",
"lets_practice_course": "Lets Practice Course", "keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
"lets_quick_review": "Lets quickly review what youve learned in this level!", "no_practice_available": "No practice available!",
"speaking": "is speaking...", "begin_module_practice": "Begin Module Practice",
"you_have_finished_practice": "You have finished your practice", "lets_practice_lesson": "Lets Practice",
"view_results": "View My Results", "lets_quickly_review":
"sample_answer": "Sample Answer", "Lets quickly review what youve learned in this module!",
"your_answer": "Your Answer", "lets_practice_module": "Let's practice what you just learnt!",
"sound_confident": "You sound more confident this time - great improvement!", "ask_you_few_actions":
"you_have_completed": "Yay, youve completed", "Ill ask you a few questions, and you can respond naturally.",
"yes": "Yes", "begin_level_practice": "Begin Level Practice",
"no": "No", "lets_practice_course": "Lets Practice Course",
"want_to_quit": "Are you sure you want to quit?", "lets_quick_review":
"required_field": "The field is required", "Lets quickly review what youve learned in this level!",
"enter_full_name": "Enter your full name", "speaking": "is speaking...",
"invalid_email": "Invalid email format", "you_have_finished_practice": "You have finished your practice",
"phone_must_start_with": "Phone number must start with 251", "view_results": "View My Results",
"phone_must_be": "Phone number must be 12 digits", "sample_answer": "Sample Answer",
"what_should_we_call_you": "What should we call you?", "your_answer": "Your Answer",
"name_for_personalization": "Well use your name to personalize your learning journey.", "sound_confident":
"choose_your_gender": "Choose your gender?", "You sound more confident this time - great improvement!",
"gender_for_personalization": "Well personalize your learning experience based on your gender.", "you_have_completed": "Yay, youve completed",
"age_range": "Which age range are you in?", "yes": "Yes",
"age_for_personalization": "Well personalize your learning experience based on your age.", "no": "No",
"educational_background": "Whats your current educational level?", "want_to_quit": "Are you sure you want to quit?",
"education_for_personalization": "This helps us tailor your lessons to your experience.", "required_field": "The field is required",
"your_occupation": "Whats your occupation?", "enter_full_name": "Enter your full name",
"occupation_for_personalization": "Well personalize your learning experience based on your occupation.", "invalid_email": "Invalid email format",
"location": "Where are you from?", "phone_must_start_with": "Phone number must start with 251",
"select_country_region": "Select your country and region from the dropdown", "phone_must_be": "Phone number must be 12 digits",
"select_country": "Select country", "what_should_we_call_you": "What should we call you?",
"learning_goal": "Choose your learning goal.", "name_for_personalization":
"language_goal": "Whats your main goal for improving your English?", "Well use your name to personalize your learning journey.",
"your_goal": "Your goal helps us tailor your learning journey.", "choose_your_gender": "Choose your gender?",
"write_your_goal": "Write your goal…", "gender_for_personalization":
"challenge_you_face": "What challenge do you face most with English?", "Well personalize your learning experience based on your gender.",
"evey_one_has_strugle": "Everyone has struggles, lets start fixing yours", "age_range": "Which age range are you in?",
"write_your_challenge": "Write your challenge…", "age_for_personalization":
"topic_interest": "Which topics interest you most?", "Well personalize your learning experience based on your age.",
"favourite_topic": "Your favorite topics help us create fun, relatable lessons.", "educational_background": "Whats your current educational level?",
"your_interest": "Write your interest…", "education_for_personalization":
"want_quick_assessment": "Want a quick assessment to know your English level?", "This helps us tailor your lessons to your experience.",
"answer_quick_questions": "Answer a few quick questions to help us understand your English proficiency.", "your_occupation": "Whats your occupation?",
"skip": "Skip", "occupation_for_personalization":
"finish_level": "Finish Level", "Well personalize your learning experience based on your occupation.",
"likely_speaker": "Youre likely speaker of", "location": "Where are you from?",
"great_job": "Great Job! Heres your next step to keep improving.", "select_country_region": "Select your country and region from the dropdown",
"lets_start_practice": "Let's start your practice", "select_country": "Select country",
"welcome_abroad": "Welcome aboard", "learning_goal": "Choose your learning goal.",
"ready_to_explore": "Youre ready to explore your personalized lessons.", "language_goal": "Whats your main goal for improving your English?",
"finish": "Finish", "your_goal": "Your goal helps us tailor your learning journey.",
"finish_all_practice": "Finish all the practices in the lessons to take this practice" "write_your_goal": "Write your goal…",
}; "challenge_you_face": "What challenge do you face most with English?",
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en}; "evey_one_has_strugle": "Everyone has struggles, lets start fixing yours",
"write_your_challenge": "Write your challenge…",
"topic_interest": "Which topics interest you most?",
"favourite_topic":
"Your favorite topics help us create fun, relatable lessons.",
"your_interest": "Write your interest…",
"want_quick_assessment":
"Want a quick assessment to know your English level?",
"answer_quick_questions":
"Answer a few quick questions to help us understand your English proficiency.",
"skip": "Skip",
"finish_level": "Finish Level",
"likely_speaker": "Youre likely speaker of",
"great_job": "Great Job! Heres your next step to keep improving.",
"lets_start_practice": "Let's start your practice",
"welcome_abroad": "Welcome aboard",
"ready_to_explore": "Youre ready to explore your personalized lessons.",
"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
};
} }

View File

@ -2,7 +2,7 @@
// ignore_for_file: constant_identifier_names // ignore_for_file: constant_identifier_names
abstract class LocaleKeys { abstract class LocaleKeys {
static const loading = 'loading'; static const loading = 'loading';
static const welcome_back = 'welcome_back'; static const welcome_back = 'welcome_back';
static const checking_user_info = 'checking_user_info'; static const checking_user_info = 'checking_user_info';
@ -161,7 +161,8 @@ abstract class LocaleKeys {
static const educational_background = 'educational_background'; static const educational_background = 'educational_background';
static const education_for_personalization = 'education_for_personalization'; static const education_for_personalization = 'education_for_personalization';
static const your_occupation = 'your_occupation'; static const your_occupation = 'your_occupation';
static const occupation_for_personalization = 'occupation_for_personalization'; static const occupation_for_personalization =
'occupation_for_personalization';
static const location = 'location'; static const location = 'location';
static const select_country_region = 'select_country_region'; static const select_country_region = 'select_country_region';
static const select_country = 'select_country'; static const select_country = 'select_country';
@ -186,5 +187,4 @@ abstract class LocaleKeys {
static const ready_to_explore = 'ready_to_explore'; static const ready_to_explore = 'ready_to_explore';
static const finish = 'finish'; static const finish = 'finish';
static const finish_all_practice = 'finish_all_practice'; static const finish_all_practice = 'finish_all_practice';
} }

View File

@ -30,12 +30,11 @@ class AccountPrivacyView extends StackedView<AccountPrivacyViewModel> {
body: _buildScaffoldContainer(viewModel), body: _buildScaffoldContainer(viewModel),
); );
Widget _buildScaffoldContainer(AccountPrivacyViewModel viewModel) =>
Widget _buildScaffoldContainer( AccountPrivacyViewModel viewModel) => Container( Container(
decoration: bgDecoration, decoration: bgDecoration,
child: _buildScaffold( viewModel), child: _buildScaffold(viewModel),
); );
Widget _buildScaffold(AccountPrivacyViewModel viewModel) => Widget _buildScaffold(AccountPrivacyViewModel viewModel) =>
SafeArea(child: _buildBodyWrapper(viewModel)); SafeArea(child: _buildBodyWrapper(viewModel));

View File

@ -13,12 +13,9 @@ 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 _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.updatePaymentStatus(); await viewModel.updatePaymentStatus();
await viewModel.replaceWithHome(); await viewModel.replaceWithHome();
@ -49,8 +46,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));
@ -59,7 +54,8 @@ class ArifPayView extends StackedView<ArifPayViewModel> {
URLRequest(url: WebUri(viewModel.request?.paymentUrl ?? '')), URLRequest(url: WebUri(viewModel.request?.paymentUrl ?? '')),
onUpdateVisitedHistory: (controller, url, androidIsReload) async { onUpdateVisitedHistory: (controller, url, androidIsReload) async {
if (url.toString().contains(kSuccessUrl)) { if (url.toString().contains(kSuccessUrl)) {
showSuccessToast('Subscription successful, activation in progress!'); showSuccessToast(
'Subscription successful, activation in progress!');
_success(viewModel); _success(viewModel);
} else if (url.toString().contains(kErrorUrl)) { } else if (url.toString().contains(kErrorUrl)) {
_error(viewModel); _error(viewModel);

View File

@ -68,22 +68,18 @@ class ArifPayViewModel extends ReactiveViewModel {
} }
// Update payment status // Update payment status
Future<void> updatePaymentStatus() async => await runBusyFuture(_updatePaymentStatus(), Future<void> updatePaymentStatus() async =>
busyObject: StateObjects.learnSubscription); await runBusyFuture(_updatePaymentStatus(),
busyObject: StateObjects.learnSubscription);
Future<void> _updatePaymentStatus() async { Future<void> _updatePaymentStatus() async {
Map<String, dynamic> response = {};
Map<String, dynamic> response = {}; response = await _apiService.getProfileData(_user?.userId);
response = await _apiService.getProfileData(_user?.userId);
if (response['status'] == ResponseStatus.success) {
User user = response['data'] as User;
await _authenticationService.saveUserData(user);
}
if (response['status'] == ResponseStatus.success) {
User user = response['data'] as User;
await _authenticationService.saveUserData(user);
}
} }
} }

View File

@ -31,8 +31,7 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
body: _buildScaffoldContainer(viewModel), body: _buildScaffoldContainer(viewModel),
); );
Widget _buildScaffoldContainer(CallSupportViewModel viewModel) => Widget _buildScaffoldContainer(CallSupportViewModel viewModel) => Container(
Container(
decoration: bgDecoration, decoration: bgDecoration,
child: _buildScaffold(viewModel), child: _buildScaffold(viewModel),
); );

View File

@ -16,28 +16,27 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
const LearnCourseView({Key? key, required this.id}) : super(key: key); const LearnCourseView({Key? key, required this.id}) : super(key: key);
Future<void> _onPractice(
Future<void> _onPractice({required BuildContext context, {required BuildContext context,
required LearnCourse course, required LearnCourse course,
required LearnCourseViewModel viewModel}) async { required LearnCourseViewModel viewModel}) async {
if (course.access?.completedCount == course.access?.totalCount) { if (course.access?.completedCount == course.access?.totalCount) {
await viewModel.navigateToLearnPractice( await viewModel.navigateToLearnPractice(
id: course.id ?? 0, id: course.id ?? 0, level: course.name ?? '');
level: course.name ?? '');
} else { } else {
await _showSheet(context: context, viewModel: viewModel); await _showSheet(context: context, viewModel: viewModel);
} }
} }
Future<void> _showSheet({required BuildContext context, Future<void> _showSheet(
required LearnCourseViewModel viewModel}) async => {required BuildContext context,
required LearnCourseViewModel viewModel}) async =>
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
backgroundColor: kcTransparent, backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel), builder: (_) => _buildSheet(viewModel),
); );
@override @override
void onViewModelReady(LearnCourseViewModel viewModel) async { void onViewModelReady(LearnCourseViewModel viewModel) async {
await viewModel.getLearnCourses(id); await viewModel.getLearnCourses(id);
@ -49,93 +48,100 @@ 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(context: context, viewModel: viewModel);
Widget _buildScaffoldWrapper({required BuildContext context, Widget _buildScaffoldWrapper(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
required LearnCourseViewModel viewModel}) =>
Scaffold( Scaffold(
backgroundColor: kcBackgroundColor, backgroundColor: kcBackgroundColor,
body: _buildScaffoldContainer(context: context,viewModel: viewModel), body: _buildScaffoldContainer(context: context, viewModel: viewModel),
); );
Widget _buildScaffoldContainer({required BuildContext context, Widget _buildScaffoldContainer(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
required LearnCourseViewModel viewModel}) =>
Container( Container(
decoration: bgDecoration, decoration: bgDecoration,
child: _buildScaffold(context: context,viewModel: viewModel), child: _buildScaffold(context: context, viewModel: viewModel),
); );
Widget _buildScaffold({required BuildContext context, Widget _buildScaffold(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
SafeArea(child: _buildBody(context: context,viewModel: viewModel)); required LearnCourseViewModel viewModel}) =>
SafeArea(child: _buildBody(context: context, viewModel: viewModel));
Widget _buildBody({required BuildContext context, Widget _buildBody(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
required LearnCourseViewModel viewModel}) =>
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: _buildColumn(context: context,viewModel: viewModel), child: _buildColumn(context: context, viewModel: viewModel),
); );
Widget _buildColumn({required BuildContext context, Widget _buildColumn(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
required LearnCourseViewModel viewModel}) =>
Column( Column(
children: [ children: [
verticalSpaceMedium, verticalSpaceMedium,
_buildAppBar(viewModel), _buildAppBar(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildCoursesColumnWrapper(context: context,viewModel: viewModel) _buildCoursesColumnWrapper(context: context, viewModel: 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(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
Expanded(child: _buildLevelsColumnScrollView(context: context,viewModel: viewModel)); required LearnCourseViewModel viewModel}) =>
Expanded(
child: _buildLevelsColumnScrollView(
context: context, viewModel: viewModel));
Widget _buildLevelsColumnScrollView({required BuildContext context, Widget _buildLevelsColumnScrollView(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
required LearnCourseViewModel viewModel}) =>
SingleChildScrollView( SingleChildScrollView(
child: _buildListViewBuilder(context: context,viewModel: viewModel), child: _buildListViewBuilder(context: context, viewModel: viewModel),
); );
Widget _buildListViewBuilder({required BuildContext context, Widget _buildListViewBuilder(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
required LearnCourseViewModel viewModel}) =>
viewModel.busy(StateObjects.learnCourses) viewModel.busy(StateObjects.learnCourses)
? _buildProgressIndicator() ? _buildProgressIndicator()
: _buildListView(context: context,viewModel: viewModel); : _buildListView(context: context, viewModel: viewModel);
Widget _buildProgressIndicator() => Widget _buildProgressIndicator() => const Center(
const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor), child: CustomCircularProgressIndicator(color: kcPrimaryColor),
); );
Widget _buildListView({required BuildContext context, Widget _buildListView(
required LearnCourseViewModel viewModel}) => {required BuildContext context,
required LearnCourseViewModel viewModel}) =>
ListView.separated( 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], onPracticeTap: () async => await _onPractice(
context: context,
onPracticeTap: () async => viewModel: viewModel,
await _onPractice( course: viewModel.courses[index]),
context: context, onViewTap: () async =>
viewModel: viewModel,
course: viewModel.courses[index]
),
onViewTap: () async =>
await viewModel.navigateToLearnModule(viewModel.courses[index]), await viewModel.navigateToLearnModule(viewModel.courses[index]),
), ),
separatorBuilder: (context, index) => verticalSpaceSmall, separatorBuilder: (context, index) => verticalSpaceSmall,
); );
@ -150,7 +156,6 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
onPracticeTap: onPracticeTap, onPracticeTap: onPracticeTap,
); );
Widget _buildSheet(LearnCourseViewModel viewModel) => Widget _buildSheet(LearnCourseViewModel viewModel) =>
FinishPracticeSheet(onTap: viewModel.pop); FinishPracticeSheet(onTap: viewModel.pop);
} }

View File

@ -12,6 +12,7 @@ import 'package:yimaru_app/ui/widgets/motivation_card.dart';
import '../../common/app_colors.dart'; import '../../common/app_colors.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_lesson_viewmodel.dart'; import 'learn_lesson_viewmodel.dart';
@ -23,11 +24,15 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
Future<void> _onPractice( Future<void> _onPractice(
{required int index, {required int index,
required LearnLesson lesson, required LearnLesson lesson,
required BuildContext context,
required LearnLessonViewModel viewModel}) async { required LearnLessonViewModel viewModel}) async {
if (index > 1) { if (lesson.access?.isAccessible ?? false) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else {
await _showSheet(context: context, viewModel: viewModel);
}
print(index); /* if (index > 1) {
print(viewModel.user?.subscriptionStatus);
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') { if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') {
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else { } else {
@ -35,9 +40,18 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
} }
} else { } else {
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} }*/
} }
Future<void> _showSheet(
{required BuildContext context,
required LearnLessonViewModel viewModel}) async =>
await showModalBottomSheet(
context: context,
backgroundColor: kcTransparent,
builder: (_) => _buildSheet(viewModel),
);
@override @override
void onViewModelReady(LearnLessonViewModel viewModel) async { void onViewModelReady(LearnLessonViewModel viewModel) async {
await viewModel.getLessons(module.id ?? 0); await viewModel.getLessons(module.id ?? 0);
@ -148,7 +162,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
verticalSpaceLarge, verticalSpaceLarge,
_buildHeader(), _buildHeader(),
verticalSpaceMedium, verticalSpaceMedium,
_buildListViewBuilder(viewModel), _buildListViewBuilder(context: context,viewModel: viewModel),
]; ];
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
@ -183,16 +197,18 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
style: style18DG700, style: style18DG700,
); );
Widget _buildListViewBuilder(LearnLessonViewModel viewModel) => Widget _buildListViewBuilder( {required BuildContext context,
required LearnLessonViewModel viewModel}) =>
viewModel.busy(StateObjects.learnLessons) viewModel.busy(StateObjects.learnLessons)
? _buildProgressIndicator() ? _buildProgressIndicator()
: _buildListView(viewModel); : _buildListView(context: context,viewModel: viewModel);
Widget _buildProgressIndicator() => const Center( Widget _buildProgressIndicator() => const Center(
child: CustomCircularProgressIndicator(color: kcPrimaryColor), child: CustomCircularProgressIndicator(color: kcPrimaryColor),
); );
Widget _buildListView(LearnLessonViewModel viewModel) => ListView.builder( Widget _buildListView( {required BuildContext context,
required LearnLessonViewModel viewModel}) => ListView.builder(
shrinkWrap: true, shrinkWrap: true,
itemCount: viewModel.lessons.length, itemCount: viewModel.lessons.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
@ -201,10 +217,12 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
lesson: viewModel.lessons[index], lesson: viewModel.lessons[index],
onPracticeTap: () async => await _onPractice( onPracticeTap: () async => await _onPractice(
index: index, index: index,
context: context,
viewModel: viewModel, viewModel: viewModel,
lesson: viewModel.lessons[index], lesson: viewModel.lessons[index],
), ),
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail( onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(
index: index,
module: module, module: module,
lesson: viewModel.lessons[index], lesson: viewModel.lessons[index],
hasPractice: hasPractice:
@ -224,4 +242,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
onLessonTap: onLessonTap, onLessonTap: onLessonTap,
onPracticeTap: onPracticeTap, onPracticeTap: onPracticeTap,
); );
Widget _buildSheet(LearnLessonViewModel viewModel) =>
FinishPracticeSheet(onTap: viewModel.pop);
} }

View File

@ -24,12 +24,9 @@ class LearnLessonViewModel extends ReactiveViewModel {
final _authenticationService = locator<AuthenticationService>(); final _authenticationService = locator<AuthenticationService>();
@override @override
List<ListenableServiceMixin> get listenableServices => [_learnService,_authenticationService]; List<ListenableServiceMixin> get listenableServices =>
[_learnService, _authenticationService];
// Current user // Current user
User? get _user => _authenticationService.user; User? get _user => _authenticationService.user;
@ -49,8 +46,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,15 +55,17 @@ class LearnLessonViewModel extends ReactiveViewModel {
subtitle: LocaleKeys.ask_you_few_actions.tr(), subtitle: LocaleKeys.ask_you_few_actions.tr(),
); );
Future<void> navigateToLearnSubscription() async => Future<void> navigateToLearnSubscription() async =>
await _navigationService.navigateToLearnSubscriptionView(); await _navigationService.navigateToLearnSubscriptionView();
Future<void> navigateToLearnLessonDetail( Future<void> navigateToLearnLessonDetail(
{required bool hasPractice, {
required int index,
required bool hasPractice,
required LearnLesson lesson, required LearnLesson lesson,
required LearnModule module}) async => required LearnModule module}) async =>
await _navigationService.navigateToLearnLessonDetailView( await _navigationService.navigateToLearnLessonDetailView(
index: index,
lesson: lesson, module: module, hasPractice: hasPractice); lesson: lesson, module: module, hasPractice: hasPractice);
// Remote api call // Remote api call
@ -88,6 +85,7 @@ class LearnLessonViewModel extends ReactiveViewModel {
LearnModule? getUpdatedLearnModule(int id) { LearnModule? getUpdatedLearnModule(int id) {
return _learnService.getLearnModuleById(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

@ -15,20 +15,33 @@ import '../../widgets/small_app_bar.dart';
import 'learn_lesson_detail_viewmodel.dart'; import 'learn_lesson_detail_viewmodel.dart';
class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> { class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
final int index;
final bool hasPractice; final bool hasPractice;
final LearnModule module; final LearnModule module;
final LearnLesson lesson; final LearnLesson lesson;
const LearnLessonDetailView( const LearnLessonDetailView(
{Key? key, {Key? key,
required this.index,
required this.lesson, required this.lesson,
required this.module, required this.module,
required this.hasPractice}) required this.hasPractice})
: super(key: key); : super(key: key);
Future<void> _navigate(LearnLessonDetailViewModel viewModel) async { Future<void> _onPractice(
{required LearnLesson lesson,
required LearnLessonDetailViewModel viewModel}) async {
await viewModel.pause(); await viewModel.pause();
await viewModel.navigateToLearnPractice(lesson.id ?? 0); await viewModel.navigateToLearnPractice(lesson.id ?? 0);
/*if (index > 1) {
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else {
await viewModel.navigateToLearnSubscription();
}
} else {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
}*/
} }
@override @override
@ -193,6 +206,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
foregroundColor: kcWhite, foregroundColor: kcWhite,
backgroundColor: kcPrimaryColor, backgroundColor: kcPrimaryColor,
text: LocaleKeys.take_practice.tr(), text: LocaleKeys.take_practice.tr(),
onTap: () async => await _navigate(viewModel), onTap: () async =>
await _onPractice(lesson: lesson, viewModel: viewModel),
); );
} }

View File

@ -7,7 +7,9 @@ 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_lesson.dart'; import '../../../models/learn_lesson.dart';
import '../../../models/user.dart';
import '../../../services/api_service.dart'; import '../../../services/api_service.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 '../../../services/vimeo_service.dart'; import '../../../services/vimeo_service.dart';
@ -26,8 +28,16 @@ class LearnLessonDetailViewModel extends ReactiveViewModel {
final _navigationService = locator<NavigationService>(); final _navigationService = locator<NavigationService>();
final _authenticationService = locator<AuthenticationService>();
@override @override
List<ListenableServiceMixin> get listenableServices => [_learnService]; List<ListenableServiceMixin> get listenableServices =>
[_learnService, _authenticationService];
// Current user
User? get _user => _authenticationService.user;
User? get user => _user;
// Learn lessons // Learn lessons
List<LearnLesson> get _lessons => _learnService.lessons; List<LearnLesson> get _lessons => _learnService.lessons;
@ -121,6 +131,9 @@ class LearnLessonDetailViewModel extends ReactiveViewModel {
// Navigation // Navigation
void pop() => _navigationService.back(); void pop() => _navigationService.back();
Future<void> navigateToLearnSubscription() async =>
await _navigationService.navigateToLearnSubscriptionView();
Future<void> navigateToLearnPractice(int id) async => Future<void> navigateToLearnPractice(int id) async =>
await _navigationService.navigateToLearnPracticeView( await _navigationService.navigateToLearnPracticeView(
id: id, id: id,

View File

@ -151,11 +151,14 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
style: style14P400, style: style14P400,
); );
Widget _buildOverallProgress(LearnModuleViewModel viewModel) => OverallProgress( Widget _buildOverallProgress(LearnModuleViewModel viewModel) =>
OverallProgress(
indicatorBackgroundColor: kcWhite, indicatorBackgroundColor: kcWhite,
backgroundColor: kcPrimaryColor.withOpacity(0.1), backgroundColor: kcPrimaryColor.withOpacity(0.1),
progress: progress: (viewModel.getUpdatedLearnCourse(course.id ?? 0) ?? course)
(viewModel.getUpdatedLearnCourse(course.id ?? 0) ?? course).access?.progressPercent ?? 0, .access
?.progressPercent ??
0,
); );
Widget _buildListViewBuilder( Widget _buildListViewBuilder(

View File

@ -85,6 +85,5 @@ class LearnModuleViewModel extends ReactiveViewModel {
} }
String getModuleImage(LearnModule module) => String getModuleImage(LearnModule module) =>
getReadableUrl(_refreshedIcons[module.id] ?? '') ?? ''; getReadableUrl(_refreshedIcons[module.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

@ -15,7 +15,6 @@ class LearnPracticeAppreciationScreen
extends ViewModelWidget<LearnPracticeViewModel> { extends ViewModelWidget<LearnPracticeViewModel> {
const LearnPracticeAppreciationScreen({super.key}); const LearnPracticeAppreciationScreen({super.key});
Future<void> _cancel(LearnPracticeViewModel viewModel) async { Future<void> _cancel(LearnPracticeViewModel viewModel) async {
await viewModel.stopRecording(); await viewModel.stopRecording();
viewModel.pop(); viewModel.pop();

View File

@ -163,13 +163,10 @@ class LearnPracticeDescriptionScreen
Widget _buildImage(LearnPracticeViewModel viewModel) => CachedNetworkImage( Widget _buildImage(LearnPracticeViewModel viewModel) => CachedNetworkImage(
fit: BoxFit.cover, fit: BoxFit.cover,
width: double.maxFinite, width: double.maxFinite,
imageUrl: imageUrl:
getReadableUrl( viewModel.practices.first.storyImage ?? '') ?? '', getReadableUrl(viewModel.practices.first.storyImage ?? '') ?? '',
); );
Widget _buildContinueButtonWrapper(LearnPracticeViewModel viewModel) => Widget _buildContinueButtonWrapper(LearnPracticeViewModel viewModel) =>
Padding( Padding(
padding: const EdgeInsets.only(bottom: 50), padding: const EdgeInsets.only(bottom: 50),

View File

@ -126,7 +126,8 @@ class OnboardingView extends StackedView<OnboardingViewModel>
Widget _buildOccupationForm() => const OccupationFormScreen(); Widget _buildOccupationForm() => const OccupationFormScreen();
Widget _buildCountryRegionForm() => CountryRegionFormScreen(regionController: regionController); Widget _buildCountryRegionForm() =>
CountryRegionFormScreen(regionController: regionController);
Widget _buildLearningGoalForm() => const LearningGoalFormScreen(); Widget _buildLearningGoalForm() => const LearningGoalFormScreen();

View File

@ -49,7 +49,6 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
return ''; return '';
} }
void _pop(OnboardingViewModel viewModel) { void _pop(OnboardingViewModel viewModel) {
viewModel.resetLearningGoalFormScreen(); viewModel.resetLearningGoalFormScreen();
viewModel.goBack(); viewModel.goBack();
@ -70,20 +69,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 +93,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 +107,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 +130,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 +143,36 @@ 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: 3, // viewModel.learningGoals.length,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => itemBuilder: (context, index) => _buildLearningGoal(
_buildLearningGoal( icon: getIcon(index),
icon: getIcon(index), title: getTitles(index),
title: getTitles(index), subtitle: getSubtitle(index),
subtitle: getSubtitle(index), selected:
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 IconData icon,
required GestureTapCallback onTap}) => required String subtitle,
required GestureTapCallback onTap}) =>
CustomLargeRadioButton( CustomLargeRadioButton(
icon:icon, icon: icon,
title: title, title: title,
onTap: onTap, onTap: onTap,
subtitle: subtitle, 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

@ -101,8 +101,7 @@ class PrivacyPolicyView extends StackedView<PrivacyPolicyViewModel> {
body: _buildScaffoldContainer(viewModel), body: _buildScaffoldContainer(viewModel),
); );
Widget _buildScaffoldContainer(PrivacyPolicyViewModel viewModel) => Widget _buildScaffoldContainer(PrivacyPolicyViewModel viewModel) => Container(
Container(
decoration: bgDecoration, decoration: bgDecoration,
child: _buildScaffold(viewModel), child: _buildScaffold(viewModel),
); );

View File

@ -55,11 +55,13 @@ class ProfileView extends StackedView<ProfileViewModel> {
body: _buildScaffoldContainer(context: context, viewModel: viewModel), body: _buildScaffoldContainer(context: context, viewModel: viewModel),
); );
Widget _buildScaffoldContainer( {required BuildContext context, Widget _buildScaffoldContainer(
required ProfileViewModel viewModel}) => Container( {required BuildContext context,
decoration: bgDecoration, required ProfileViewModel viewModel}) =>
child: _buildScaffold(context: context, viewModel: viewModel), Container(
); decoration: bgDecoration,
child: _buildScaffold(context: context, viewModel: viewModel),
);
Widget _buildScaffold( Widget _buildScaffold(
{required BuildContext context, {required BuildContext context,

View File

@ -56,7 +56,6 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
'birth_day': DateFormat('yyyy-MM-dd').format(DateTime.now()), 'birth_day': DateFormat('yyyy-MM-dd').format(DateTime.now()),
}; };
viewModel.addUserData(data); viewModel.addUserData(data);
await viewModel.updateProfile(); await viewModel.updateProfile();
@ -110,7 +109,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
} }
@override @override
void onViewModelReady(ProfileDetailViewModel viewModel) async{ void onViewModelReady(ProfileDetailViewModel viewModel) async {
await viewModel.getProfileDetailFields(); await viewModel.getProfileDetailFields();
_onModelReady(viewModel); _onModelReady(viewModel);
syncFormWithViewModel(viewModel); syncFormWithViewModel(viewModel);
@ -138,19 +137,19 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
); );
Widget _buildScaffoldState( Widget _buildScaffoldState(
{required BuildContext context, {required BuildContext context,
required ProfileDetailViewModel viewModel}) => required ProfileDetailViewModel viewModel}) =>
viewModel.busy(StateObjects.profileDetail) viewModel.busy(StateObjects.profileDetail)
? const PageLoadingIndicator() ? const PageLoadingIndicator()
: _buildScaffoldContainer(context: context, viewModel: viewModel); : _buildScaffoldContainer(context: context, viewModel: viewModel);
Widget _buildScaffoldContainer(
Widget _buildScaffoldContainer( {required BuildContext context, {required BuildContext context,
required ProfileDetailViewModel viewModel}) => Container( required ProfileDetailViewModel viewModel}) =>
decoration: bgDecoration, Container(
child: _buildScaffoldStack(context: context, viewModel: viewModel), decoration: bgDecoration,
); child: _buildScaffoldStack(context: context, viewModel: viewModel),
);
Widget _buildScaffoldStack( Widget _buildScaffoldStack(
{required BuildContext context, {required BuildContext context,

View File

@ -164,7 +164,6 @@ class ProfileDetailViewModel extends ReactiveViewModel
return false; return false;
} }
void setRegionFocus() { void setRegionFocus() {
_focusRegion = true; _focusRegion = true;
rebuildUi(); rebuildUi();
@ -258,7 +257,8 @@ class ProfileDetailViewModel extends ReactiveViewModel
// Profile detail fields // Profile detail fields
Future<void> getProfileDetailFields() async => Future<void> getProfileDetailFields() async =>
await runBusyFuture(_getProfileDetailFields(),busyObject: StateObjects.profileDetail); await runBusyFuture(_getProfileDetailFields(),
busyObject: StateObjects.profileDetail);
Future<void> _getProfileDetailFields() async { Future<void> _getProfileDetailFields() async {
await _onboardingService.getProfileDetailFields(); await _onboardingService.getProfileDetailFields();

View File

@ -28,8 +28,7 @@ class SupportView extends StackedView<SupportViewModel> {
body: _buildScaffoldContainer(viewModel), body: _buildScaffoldContainer(viewModel),
); );
Widget _buildScaffoldContainer(SupportViewModel viewModel) => Widget _buildScaffoldContainer(SupportViewModel viewModel) => Container(
Container(
decoration: bgDecoration, decoration: bgDecoration,
child: _buildScaffold(viewModel), child: _buildScaffold(viewModel),
); );

View File

@ -32,7 +32,6 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
body: _buildScaffoldContainer(viewModel), body: _buildScaffoldContainer(viewModel),
); );
Widget _buildScaffoldContainer(TelegramSupportViewModel viewModel) => Widget _buildScaffoldContainer(TelegramSupportViewModel viewModel) =>
Container( Container(
decoration: bgDecoration, decoration: bgDecoration,

View File

@ -11,70 +11,70 @@ class CustomLargeRadioButton extends StatelessWidget {
const CustomLargeRadioButton( const CustomLargeRadioButton(
{super.key, {super.key,
this.onTap, this.onTap,
required this.title, required this.title,
required this.icon, required this.icon,
required this.selected, required this.selected,
required this.subtitle}); required this.subtitle});
@override @override
Widget build(BuildContext context) => _buildButtonWrapper(); Widget build(BuildContext context) => _buildButtonWrapper();
Widget _buildButtonWrapper() => Container( Widget _buildButtonWrapper() => Container(
height: 125, height: 125,
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: _buildButtonColumnWrapper(),
); );
Widget _buildButtonColumnWrapper() => Column( Widget _buildButtonColumnWrapper() => Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: _buildButtonRowChildren(), children: _buildButtonRowChildren(),
); );
List<Widget> _buildButtonRowChildren() => List<Widget> _buildButtonRowChildren() =>
[_buildIconSectionWrapper(), _buildTitle(), _buildSubtitle()]; [_buildIconSectionWrapper(), _buildTitle(), _buildSubtitle()];
Widget _buildIconSectionWrapper() => Row( Widget _buildIconSectionWrapper() => Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: _buildIconSectionChildren(), children: _buildIconSectionChildren(),
); );
List<Widget> _buildIconSectionChildren() => List<Widget> _buildIconSectionChildren() =>
[_buildLeadingIcon(), _buildSelectedCheckBox()]; [_buildLeadingIcon(), _buildSelectedCheckBox()];
Widget _buildLeadingIcon() => Icon( Widget _buildLeadingIcon() => Icon(
icon, icon,
size: 25, size: 25,
color: kcPrimaryColor, color: kcPrimaryColor,
); );
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
title, title,
style: style18DG700, style: style18DG700,
); );
Widget _buildSubtitle() => Text( Widget _buildSubtitle() => Text(
subtitle, subtitle,
style: const TextStyle(color: kcMediumGrey), style: const TextStyle(color: kcMediumGrey),
); );
Widget _buildSelectedCheckBox() => Checkbox( Widget _buildSelectedCheckBox() => Checkbox(
value: selected, value: selected,

View File

@ -26,8 +26,6 @@ class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
Widget build(BuildContext context, LearnCourseViewModel viewModel) => Widget build(BuildContext context, LearnCourseViewModel viewModel) =>
_buildExpansionTileCard(viewModel); _buildExpansionTileCard(viewModel);
Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container( Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container(
margin: const EdgeInsets.only(bottom: 15), margin: const EdgeInsets.only(bottom: 15),
decoration: BoxDecoration( decoration: BoxDecoration(

View File

@ -27,12 +27,14 @@ 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); _buildContainerWrapper(viewModel);
Widget _buildContainerWrapper(LearnLessonViewModel viewModel)=> GestureDetector(
onTap: !(lesson.access?.isAccessible ?? false) ? onPracticeTap:null,
child: _buildContainer(viewModel),
);
Widget _buildContainer(LearnLessonViewModel viewModel) => Container( Widget _buildContainer(LearnLessonViewModel viewModel) => Container(
width: double.maxFinite, width: double.maxFinite,
margin: const EdgeInsets.only(bottom: 15), margin: const EdgeInsets.only(bottom: 15),
@ -72,7 +74,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
? kcGreen.withOpacity(0.1) ? kcGreen.withOpacity(0.1)
: kcPrimaryColor.withOpacity(0.1), : kcPrimaryColor.withOpacity(0.1),
childrenPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15), childrenPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15),
initiallyExpanded: (lesson.access?.isAccessible ?? false) && initiallyExpanded: (lesson.access?.isAccessible ?? false) &&
!(lesson.access?.isCompleted ?? false), !(lesson.access?.isCompleted ?? false),
collapsedBackgroundColor: (lesson.access?.isCompleted ?? false) collapsedBackgroundColor: (lesson.access?.isCompleted ?? false)
? kcGreen.withOpacity(0.1) ? kcGreen.withOpacity(0.1)
@ -80,8 +82,8 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
children: _buildExpansionTileChildren(viewModel), children: _buildExpansionTileChildren(viewModel),
); );
Widget _buildLeadingWrapper(LearnLessonViewModel viewModel) => MiniThumbnail( Widget _buildLeadingWrapper(LearnLessonViewModel viewModel) =>
thumbnail: getReadableUrl(lesson.thumbnail ?? '') ?? ''); MiniThumbnail(thumbnail: getReadableUrl(lesson.thumbnail ?? '') ?? '');
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
lesson.title ?? '', lesson.title ?? '',

View File

@ -21,8 +21,6 @@ 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});
@override @override
Widget build(BuildContext context, LearnModuleViewModel viewModel) => Widget build(BuildContext context, LearnModuleViewModel viewModel) =>
_buildExpansionTileCard(context: context, viewModel: viewModel); _buildExpansionTileCard(context: context, viewModel: viewModel);
@ -86,20 +84,17 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
child: _buildIconClipper(viewModel), child: _buildIconClipper(viewModel),
); );
Widget _buildIconClipper(LearnModuleViewModel viewModel)=> ClipRRect( Widget _buildIconClipper(LearnModuleViewModel viewModel) => ClipRRect(
child: _buildIcon(viewModel), child: _buildIcon(viewModel),
); );
Widget _buildIcon(LearnModuleViewModel viewModel) => Widget _buildIcon(LearnModuleViewModel viewModel) => CachedNetworkImage(
CachedNetworkImage(
width: 25, width: 25,
height: 25, height: 25,
cacheKey: viewModel.getModuleImage(module), cacheKey: viewModel.getModuleImage(module),
imageUrl: viewModel.getModuleImage(module), imageUrl: viewModel.getModuleImage(module),
); );
Widget _buildTitleWrapper() => Padding( Widget _buildTitleWrapper() => Padding(
padding: const EdgeInsets.symmetric(vertical: 10), padding: const EdgeInsets.symmetric(vertical: 10),
child: _buildTitle(), child: _buildTitle(),
@ -214,8 +209,6 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
text: LocaleKeys.take_practice.tr(), text: LocaleKeys.take_practice.tr(),
); );
Widget _buildContainerShaderState() => !(module.access?.isAccessible ?? false) Widget _buildContainerShaderState() => !(module.access?.isAccessible ?? false)
? _buildContainerShader() ? _buildContainerShader()
: Container(); : Container();

View File

@ -50,8 +50,8 @@ class OverallProgressWrapper extends StatelessWidget {
backgroundColor: kcVeryLightGrey, backgroundColor: kcVeryLightGrey,
); );
Widget _buildSubtitle() => Text( Widget _buildSubtitle() => Text(
LocaleKeys.keep_up_the_great_work.tr(), LocaleKeys.keep_up_the_great_work.tr(),
style:style14DG400 , style: style14DG400,
); );
} }

View File

@ -1,5 +1,5 @@
name: yimaru_app name: yimaru_app
version: 0.1.27+29 version: 0.1.28+30
publish_to: 'none' publish_to: 'none'
description: A new Flutter project. description: A new Flutter project.