Compare commits

...

4 Commits

Author SHA1 Message Date
6ad151c82d Merge tag '0.1.31' into develop
-feat(progress): Integrat my progress section with api.
-fix(localization): Localization state issue fixed.
-fix(profile_image): Fix profile image downloading issue.
2026-06-01 01:39:21 +03:00
723fa38497 Merge branch 'release/0.1.31'
-feat(progress): Integrat my progress section with api.                                                                                                                          -fix(localization): Localization state issue fixed.
-fix(profile_image): Fix profile image downloading issue.
2026-06-01 01:38:11 +03:00
bf34ca9937 -feat(progress): Integrat my progress section with api.
-fix(localization): Localization state issue fixed.
-fix(profile_image): Fix profile image downloading issue.
2026-06-01 01:36:47 +03:00
7f6a5f1d34 -feat(progress): Integrat my progress section with api.
-fix(localization): Localization state issue fixed.
-fix(profile_image): Fix profile image downloading issue.
2026-06-01 01:34:15 +03:00
27 changed files with 900 additions and 716 deletions

View File

@ -187,6 +187,14 @@
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
"finish_all_practice_previouse_module": "ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ"
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ",
"track_journey": "የትምህርት ጉዞዎን ይከታተሉ እና በጊዜ ሂደት ያሳዩትን እድገት ይመልከቱ።",
"learn_english": "እንግሊዝኛ ይማሩ",
"keep_momentum":"በጣም ጥሩ ስራ! በዚሁ ብርታት ይቀጥሉ።",
"completed_practices": "የተጠናቀቁ ልምምዶች",
"total_practices": "ጠቅላላ ልምምዶች",
"progress_percentage": "የእድገት መቶኛ"
}

View File

@ -1,192 +1,197 @@
{"loading": "Loading",
"welcome_back": "Welcome back",
"checking_user_info": "Checking user info",
"dont_have_account": "Don't have an account?",
"email": "Email",
"password": "Password",
"forgot_password": "Forgot password?",
"cont": "Continue",
"register": "Register",
"login_with_google": "Login with Google",
"or": "Or",
"login_with_phone": "Login with phone number",
"create_account": "Create an account",
"already_have_account": "Already have an account?",
"login": "Login",
"register_with_google": "Register with Google",
"register_with_phone": "Register with phone number",
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
"login_with_email": "Login with email",
"create_password": "Create password",
"confirm_password": "Confirm password",
"eight_character_minimum": "8 characters minimum",
"password_match": "password match",
"sign_up_agreement": "By clicking Sign Up, you agree to our Terms of Service and Privacy Policy",
"terms_of_services": "Terms of Service",
"and": "and",
"privacy_policy": "Privacy Policy",
"register_with_email": "Register with email",
"verification_code": "Verification Code",
"resend_code": "Resend Code",
"code_sent_to_phone": "Code sent to your number",
"code_sent_to_email": "Code sent to your email",
"resend_code_in": "Resend code in",
"reset_password": "Reset Password",
"enter_email_reset_code": "Enter your email. We will send you a reset code.",
"please_wait": "Please wait",
"reset_code_sent": "Reset code sent successfully",
"reset_code": "Reset code",
"new_password": "New password",
"logged_in_successfully": "Logged in successfully",
"continue_learning": "Continue Learning",
"start_learning": "Start Learning",
"completed": "Completed",
"view_course": "View course",
"take_practice": "Take practice",
"your_current_level": "Your current level",
"overall_progress": "Overall progress",
"great_work": "Keep up the great work! You're doing amazing",
"view_module": "View module",
"progress": "Progress",
"keep_going": "Let's keep going - you're more than half there",
"lessons_in_module": "Lessons in this module",
"practice": "Practice",
"start": "Start",
"in_progress": "In Progress",
"hello": "Hello",
"ready_to_learn": "Ready to keep learning English today",
"learn": "Learn",
"course": "Course",
"profile": "Profile",
"speaking_partner": "Speaking partner",
"practice_what_you_learned": "Let's practice what you just learnt",
"practice_questions": "I will ask you a few questions and you can respond",
"start_practice": "Start practice",
"almost_there": "You're almost there",
"finish_session": "Finish the session to see your progress",
"continue_practice": "Continue practice",
"end_session": "End session",
"tap_start_to_listen": "Tap the start button to listen",
"practice_speaking": "Practice speaking",
"tap_microphone": "Tap the microphone to speak",
"reply": "Reply",
"cancel": "Cancel",
"you_are_speaking": "You're speaking",
"practice_completed": "Practice completed!",
"great_improvement": "You sound more confident this time, great improvement",
"practice_again": "Practice again",
"conversation_review": "Conversation review",
"result": "Result",
"quick_tip": "Quick tip",
"retry": "Retry",
"completed_a1": "Yay, you've completed A1",
"analyzing_speaking": "We're now analyzing your speaking skill",
"view_profile": "View profile",
"hi": "Hi",
"edit_profile": "Edit profile",
"first_name": "First name",
"last_name": "Last name",
"gender": "Gender",
"male": "Male",
"female": "Female",
"phone_number": "Phone number",
"country": "Country",
"region": "Region",
"select_region": "Select region",
"enter_your_city": "Enter your city",
"occupation": "Occupation",
"select_occupation": "Select occupation",
"save_changes": "Save changes",
"my_progress": "My progress",
"track_your_achievement": "Track your achievements and learning streak",
"account_and_privacy": "Account & Privacy",
"manage_settings": "Manage settings and app preference",
"support": "Support",
"get_help": "Get help through phone or Telegram",
"logout": "Logout",
"app_settings": "App settings",
"legal_and_information": "Legal & Information",
"change_language": "Change language",
"terms_and_conditions":"Terms & Conditions",
"delete_account": "Delete account",
"language_preference": "Language preference",
"choose_your_language": "Choose your language",
"switch_language_anytime": "You can switch languages anytime",
"need_help": "Need help?",
"call_support": "Call support",
"talk_with_support": "Talk with our support team directly",
"telegram_support": "Telegram support",
"chat_via_telegram" :"Chat instantly via Telegram",
"call_our_support": "Call our support team between 9 AM - 6 PM",
"tap_to_call": "Tap to call",
"join_telegram": "Join Yimaru Academy on Telegram",
"connect_with_support_team": "Connect with our support team instantly on Telegram for quick assistance and community updates",
"open_in_telegram": "Open in Telegram",
"search_for": "Search for",
"current_level": "Current Level",
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
"no_practice_available": "No practice available!",
"begin_module_practice": "Begin Module Practice",
"lets_practice_lesson": "Lets Practice",
"lets_quickly_review": "Lets quickly review what youve learned in this module!",
"lets_practice_module": "Let's practice what you just learnt!",
"ask_you_few_actions": "Ill ask you a few questions, and you can respond naturally.",
"begin_level_practice": "Begin Level Practice",
"lets_practice_course": "Lets Practice Course",
"lets_quick_review": "Lets quickly review what youve learned in this level!",
"speaking": "is speaking...",
"you_have_finished_practice": "You have finished your practice",
"view_results": "View My Results",
"sample_answer": "Sample Answer",
"your_answer": "Your Answer",
"sound_confident": "You sound more confident this time - great improvement!",
"you_have_completed": "Yay, youve completed",
"yes": "Yes",
"no": "No",
"want_to_quit": "Are you sure you want to quit?",
"required_field": "The field is required",
"enter_full_name": "Enter your full name",
"invalid_email": "Invalid email format",
"phone_must_start_with": "Phone number must start with 251",
"phone_must_be": "Phone number must be 12 digits",
"what_should_we_call_you": "What should we call you?",
"name_for_personalization": "Well use your name to personalize your learning journey.",
"choose_your_gender": "Choose your gender?",
"gender_for_personalization": "Well personalize your learning experience based on your gender.",
"age_range": "Which age range are you in?",
"age_for_personalization": "Well personalize your learning experience based on your age.",
"educational_background": "Whats your current educational level?",
"education_for_personalization": "This helps us tailor your lessons to your experience.",
"your_occupation": "Whats your occupation?",
"occupation_for_personalization": "Well personalize your learning experience based on your occupation.",
"location": "Where are you from?",
"select_country_region": "Select your country and region from the dropdown",
"select_country": "Select country",
"learning_goal": "Choose your learning goal.",
"language_goal": "Whats your main goal for improving your English?",
"your_goal": "Your goal helps us tailor your learning journey.",
"write_your_goal": "Write your goal…",
"challenge_you_face": "What challenge do you face most with English?",
"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_lesson": "Finish the previous lesson practice to take this practice",
"finish_all_practice_module": "Finish the lesson practices to take the Module Practice",
"finish_all_practice_course": "Finish the Module practices to take the Course practice",
"finish_all_practice_previouse_module": "Finish the previous Module practice to take this practice",
"finish_all_practice_previouse_course": "Finish the previous course practice to take this"
}
{
"loading": "Loading",
"welcome_back": "Welcome back",
"checking_user_info": "Checking user info",
"dont_have_account": "Don't have an account?",
"email": "Email",
"password": "Password",
"forgot_password": "Forgot password?",
"cont": "Continue",
"register": "Register",
"login_with_google": "Login with Google",
"or": "Or",
"login_with_phone": "Login with phone number",
"create_account": "Create an account",
"already_have_account": "Already have an account?",
"login": "Login",
"register_with_google": "Register with Google",
"register_with_phone": "Register with phone number",
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
"login_with_email": "Login with email",
"create_password": "Create password",
"confirm_password": "Confirm password",
"eight_character_minimum": "8 characters minimum",
"password_match": "password match",
"sign_up_agreement": "By clicking Sign Up, you agree to our Terms of Service and Privacy Policy",
"terms_of_services": "Terms of Service",
"and": "and",
"privacy_policy": "Privacy Policy",
"register_with_email": "Register with email",
"verification_code": "Verification Code",
"resend_code": "Resend Code",
"code_sent_to_phone": "Code sent to your number",
"code_sent_to_email": "Code sent to your email",
"resend_code_in": "Resend code in",
"reset_password": "Reset Password",
"enter_email_reset_code": "Enter your email. We will send you a reset code.",
"please_wait": "Please wait",
"reset_code_sent": "Reset code sent successfully",
"reset_code": "Reset code",
"new_password": "New password",
"logged_in_successfully": "Logged in successfully",
"continue_learning": "Continue Learning",
"start_learning": "Start Learning",
"completed": "Completed",
"view_course": "View course",
"take_practice": "Take practice",
"your_current_level": "Your current level",
"overall_progress": "Overall progress",
"great_work": "Keep up the great work! You're doing amazing",
"view_module": "View module",
"progress": "Progress",
"keep_going": "Let's keep going - you're more than half there",
"lessons_in_module": "Lessons in this module",
"practice": "Practice",
"start": "Start",
"in_progress": "In Progress",
"hello": "Hello",
"ready_to_learn": "Ready to keep learning English today",
"learn": "Learn",
"course": "Course",
"profile": "Profile",
"speaking_partner": "Speaking partner",
"practice_what_you_learned": "Let's practice what you just learnt",
"practice_questions": "I will ask you a few questions and you can respond",
"start_practice": "Start practice",
"almost_there": "You're almost there",
"finish_session": "Finish the session to see your progress",
"continue_practice": "Continue practice",
"end_session": "End session",
"tap_start_to_listen": "Tap the start button to listen",
"practice_speaking": "Practice speaking",
"tap_microphone": "Tap the microphone to speak",
"reply": "Reply",
"cancel": "Cancel",
"you_are_speaking": "You're speaking",
"practice_completed": "Practice completed!",
"great_improvement": "You sound more confident this time, great improvement",
"practice_again": "Practice again",
"conversation_review": "Conversation review",
"result": "Result",
"quick_tip": "Quick tip",
"retry": "Retry",
"completed_a1": "Yay, you've completed A1",
"analyzing_speaking": "We're now analyzing your speaking skill",
"view_profile": "View profile",
"hi": "Hi",
"edit_profile": "Edit profile",
"first_name": "First name",
"last_name": "Last name",
"gender": "Gender",
"male": "Male",
"female": "Female",
"phone_number": "Phone number",
"country": "Country",
"region": "Region",
"select_region": "Select region",
"enter_your_city": "Enter your city",
"occupation": "Occupation",
"select_occupation": "Select occupation",
"save_changes": "Save changes",
"my_progress": "My progress",
"track_your_achievement": "Track your achievements and learning streak",
"account_and_privacy": "Account & Privacy",
"manage_settings": "Manage settings and app preference",
"support": "Support",
"get_help": "Get help through phone or Telegram",
"logout": "Logout",
"app_settings": "App settings",
"legal_and_information": "Legal & Information",
"change_language": "Change language",
"terms_and_conditions": "Terms & Conditions",
"delete_account": "Delete account",
"language_preference": "Language preference",
"choose_your_language": "Choose your language",
"switch_language_anytime": "You can switch languages anytime",
"need_help": "Need help?",
"call_support": "Call support",
"talk_with_support": "Talk with our support team directly",
"telegram_support": "Telegram support",
"chat_via_telegram": "Chat instantly via Telegram",
"call_our_support": "Call our support team between 9 AM - 6 PM",
"tap_to_call": "Tap to call",
"join_telegram": "Join Yimaru Academy on Telegram",
"connect_with_support_team": "Connect with our support team instantly on Telegram for quick assistance and community updates",
"open_in_telegram": "Open in Telegram",
"search_for": "Search for",
"current_level": "Current Level",
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
"no_practice_available": "No practice available!",
"begin_module_practice": "Begin Module Practice",
"lets_practice_lesson": "Lets Practice",
"lets_quickly_review": "Lets quickly review what youve learned in this module!",
"lets_practice_module": "Let's practice what you just learnt!",
"ask_you_few_actions": "Ill ask you a few questions, and you can respond naturally.",
"begin_level_practice": "Begin Level Practice",
"lets_practice_course": "Lets Practice Course",
"lets_quick_review": "Lets quickly review what youve learned in this level!",
"speaking": "is speaking...",
"you_have_finished_practice": "You have finished your practice",
"view_results": "View My Results",
"sample_answer": "Sample Answer",
"your_answer": "Your Answer",
"sound_confident": "You sound more confident this time - great improvement!",
"you_have_completed": "Yay, youve completed",
"yes": "Yes",
"no": "No",
"want_to_quit": "Are you sure you want to quit?",
"required_field": "The field is required",
"enter_full_name": "Enter your full name",
"invalid_email": "Invalid email format",
"phone_must_start_with": "Phone number must start with 251",
"phone_must_be": "Phone number must be 12 digits",
"what_should_we_call_you": "What should we call you?",
"name_for_personalization": "Well use your name to personalize your learning journey.",
"choose_your_gender": "Choose your gender?",
"gender_for_personalization": "Well personalize your learning experience based on your gender.",
"age_range": "Which age range are you in?",
"age_for_personalization": "Well personalize your learning experience based on your age.",
"educational_background": "Whats your current educational level?",
"education_for_personalization": "This helps us tailor your lessons to your experience.",
"your_occupation": "Whats your occupation?",
"occupation_for_personalization": "Well personalize your learning experience based on your occupation.",
"location": "Where are you from?",
"select_country_region": "Select your country and region from the dropdown",
"select_country": "Select country",
"learning_goal": "Choose your learning goal.",
"language_goal": "Whats your main goal for improving your English?",
"your_goal": "Your goal helps us tailor your learning journey.",
"write_your_goal": "Write your goal…",
"challenge_you_face": "What challenge do you face most with English?",
"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_lesson": "Finish the previous lesson practice to take this practice",
"finish_all_practice_module": "Finish the lesson practices to take the Module Practice",
"finish_all_practice_course": "Finish the Module practices to take the Course practice",
"finish_all_practice_previouse_module": "Finish the previous Module practice to take this practice",
"finish_all_practice_previouse_course": "Finish the previous course practice to take this",
"track_journey": "Track your learning journey and see your growth over time.",
"learn_english": "Learn English",
"keep_momentum":"Great job! Keep the momentum.",
"completed_practices": "Completed Practices",
"total_practices": "Total Practices",
"progress_percentage": "Progress Percentage"
}

View File

@ -2,13 +2,18 @@ import 'package:stacked/stacked.dart';
import 'package:yimaru_app/app/app.locator.dart';
import 'package:yimaru_app/models/user.dart';
import 'package:yimaru_app/services/secure_storage_service.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'google_auth_service.dart';
import 'localization_service.dart';
class AuthenticationService with ListenableServiceMixin {
// Dependency injection
final _secureService = locator<SecureStorageService>();
final _googleAuthService = locator<GoogleAuthService>();
final _localizationService = locator<LocalizationService>();
// User data
@ -18,9 +23,15 @@ class AuthenticationService with ListenableServiceMixin {
// Initialization
AuthenticationService() {
listenToReactiveValues([_user, _localizationService]);
listenToReactiveValues([_user,_state, _localizationService]);
}
// Logout state
StateObjects _state = StateObjects.none;
StateObjects get state => _state;
// Check user logged in
Future<bool> userLoggedIn() async {
if (await _secureService.getString('userId') != null) {
@ -179,13 +190,20 @@ class AuthenticationService with ListenableServiceMixin {
// Logout
Future<void> logout() async {
_state = StateObjects.logout;
notifyListeners();
bool firstTimeInstall = await isFirstTimeInstall();
String language = await _localizationService.selectedLanguage['code'];
_user = null;
await _secureService.clear();
await _googleAuthService.logout();
await setFirstTimeInstall(firstTimeInstall);
await _secureService.setString('language', language);
_state = StateObjects.none;
notifyListeners();
}
}

View File

@ -19,7 +19,6 @@ class GoogleAuthService with ListenableServiceMixin {
Future<void> logout() async {
await _signIn.signOut();
_googleUser = null;
notifyListeners();
}
// Google authentication
@ -30,10 +29,7 @@ class GoogleAuthService with ListenableServiceMixin {
_googleUser ??=
await _signIn.authenticate(scopeHint: ['email', 'profile']);
print('GOOGLE AUTH');
print(_googleUser?.email);
print(_googleUser?.displayName);
print(_googleUser?.authentication.idToken);
});
notifyListeners();
} catch (e) {

View File

@ -5,39 +5,53 @@ import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import '../app/app.locator.dart';
import '../ui/common/app_constants.dart';
import '../models/refresh_object.dart';
import '../ui/common/enmus.dart';
import 'api_service.dart';
import 'dio_service.dart';
class ImageDownloaderService {
// Dependency injection
final _service = locator<DioService>();
final _apiService = locator<ApiService>();
final Dio _dio = Dio();
// Image downloader
Future<String> downloader(String? networkImage) async {
late File image;
Future<String?> downloader(String? networkImage) async {
try {
File? image;
late String profileImage;
String? profileImage = networkImage;
final Directory appDir = await getApplicationDocumentsDirectory();
final Directory appDir = await getApplicationDocumentsDirectory();
if (networkImage != null) {
profileImage = networkImage.contains('https://lh3.googleusercontent.com')
? networkImage
: '$kBaseUrl$networkImage';
Map<String, dynamic> data = {'reference': profileImage};
Map<String, dynamic> response = await _apiService.refreshObject(data);
if (response['status'] == ResponseStatus.success) {
RefreshObject object = response['data'] as RefreshObject;
profileImage = object.url;
}
if (profileImage != null) {
final Response profileImageResponse = await _dio.get<List<int>>(
profileImage,
options: Options(
responseType: ResponseType.bytes,
),
);
final localImagePath = join(appDir.path, 'profile.jpg');
image = File(localImagePath);
image.writeAsBytes(profileImageResponse.data);
return image.path;
}
return null;
} catch (e) {
return null;
}
final Response profileImageResponse = await _service.dio.get(
profileImage,
options: Options(
followRedirects: false,
responseType: ResponseType.bytes,
),
);
final imageName = basename(networkImage ?? '');
final localImagePath = join(appDir.path, imageName);
image = File(localImagePath);
image.writeAsBytes(profileImageResponse.data);
return image.path;
}
}

View File

@ -1,4 +1,6 @@
import 'package:stacked/stacked.dart';
import 'package:yimaru_app/models/course_progress.dart';
import 'package:yimaru_app/models/module_progress.dart';
import 'package:yimaru_app/models/refresh_object.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
@ -17,9 +19,25 @@ class LearnService with ListenableServiceMixin {
// Initialization
learnService() {
listenToReactiveValues([_programs, _courses, _lessons, _modules]);
listenToReactiveValues(
[_programs, _courses, _lessons, _modules, _totalCount]);
}
// Completed count
int _completedCount = 0;
int get completedCount => _completedCount;
// Total count
int _totalCount = 0;
int get totalCount => _totalCount;
// Total progress
int _totalProgress = 0;
int get totalProgress => _totalProgress;
// Learn program
List<LearnProgram> _programs = [];
@ -40,10 +58,7 @@ class LearnService with ListenableServiceMixin {
List<LearnLesson> get lessons => _lessons;
// Learn progress
final List<ProgressSummary> _summaries = [];
List<ProgressSummary> get summaries => _summaries;
// Learn programs
Future<String?> refreshObject(String url) async {
@ -87,7 +102,7 @@ class LearnService with ListenableServiceMixin {
}
// Learn progress
Future<void> getLearnProgressSummary() async {
Future<void> getLearnProgress() async {
final summaries = await _apiService.getProgressSummary();
/// PROGRAM ACCESS MAP
@ -148,10 +163,6 @@ class LearnService with ListenableServiceMixin {
);
}).toList();
print(
'MY SUMMARIES - COMPLETED COUNT: ${_modules.first.access?.completedCount}');
print('PROGRESS PERCENT: ${_modules.first.access?.progressPercent}');
/// UPDATE LESSONS
_lessons = _lessons.map((lesson) {
return lesson.copyWith(
@ -177,4 +188,30 @@ class LearnService with ListenableServiceMixin {
return null;
}
}
Future<void> getProgressSummary() async {
final summaries = await _apiService.getProgressSummary();
for (final ProgressSummary summary in summaries) {
_totalCount = _totalCount + (summary.access?.totalCount ?? 0);
_completedCount = _completedCount + (summary.access?.completedCount ?? 0);
for (final CourseProgress course in summary.courses ?? []) {
_totalCount = _totalCount + (course.access?.totalCount ?? 0);
_completedCount =
_completedCount + (course.access?.completedCount ?? 0);
for (final ModuleProgress module in course.modules ?? []) {
_totalCount = _totalCount + (module.access?.totalCount ?? 0);
_completedCount =
_completedCount + (module.access?.completedCount ?? 0);
}
}
}
_totalProgress = summaries.fold(
0, (sum, progress) => sum + (progress.access?.progressPercent ?? 0));
notifyListeners();
}
}

View File

@ -122,7 +122,7 @@ String kTelegramSupport = '@yimaruacademy2026';
String kTelegramSupportLink = 'https://t.me/yimaruacademy2026';
String kErrorUrl = 'https://yimaru.net/api/v1/payments/chapa/error';
String kErrorUrl = 'https://api.yimaruacademy.com/payment/error';
String kSuccessUrl =
'https://api.yimaruacademy.com/api/v1/payments/chapa/success';
'https://api.yimaruacademy.com/payment/success';

View File

@ -31,6 +31,7 @@ enum PracticeReason { course, module, lesson, previousModule, previousCourse }
// State object
enum StateObjects {
none,
logout,
courses,
register,
verifyOtp,
@ -55,6 +56,7 @@ enum StateObjects {
loginWithGoogle,
loadLessonVideo,
loadCourseVideo,
progressSummary,
requestResetCode,
profileCompletion,
learnSubscription,

View File

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

View File

@ -2,7 +2,7 @@
// ignore_for_file: constant_identifier_names
abstract class LocaleKeys {
abstract class LocaleKeys {
static const loading = 'loading';
static const welcome_back = 'welcome_back';
static const checking_user_info = 'checking_user_info';
@ -161,8 +161,7 @@ abstract class LocaleKeys {
static const educational_background = 'educational_background';
static const education_for_personalization = 'education_for_personalization';
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 select_country_region = 'select_country_region';
static const select_country = 'select_country';
@ -189,8 +188,13 @@ abstract class LocaleKeys {
static const finish_all_practice_lesson = 'finish_all_practice_lesson';
static const finish_all_practice_module = 'finish_all_practice_module';
static const finish_all_practice_course = 'finish_all_practice_course';
static const finish_all_practice_previouse_module =
'finish_all_practice_previouse_module';
static const finish_all_practice_previouse_course =
'finish_all_practice_previouse_course';
static const finish_all_practice_previouse_module = 'finish_all_practice_previouse_module';
static const finish_all_practice_previouse_course = 'finish_all_practice_previouse_course';
static const track_journey = 'track_journey';
static const learn_english = 'learn_english';
static const keep_momentum = 'keep_momentum';
static const completed_practices = 'completed_practices';
static const total_practices = 'total_practices';
static const progress_percentage = 'progress_percentage';
}

View File

@ -2,15 +2,18 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:yimaru_app/ui/common/app_colors.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import 'package:yimaru_app/ui/views/learn_program/learn_program_view.dart';
import 'package:yimaru_app/ui/views/profile/profile_view.dart';
import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart';
import '../../widgets/coming_soon.dart';
import 'home_viewmodel.dart';
class HomeView extends StackedView<HomeViewModel> {
const HomeView({Key? key}) : super(key: key);
@override
void onViewModelReady(HomeViewModel viewModel) async {
await viewModel.inAppUpdate();
@ -23,7 +26,13 @@ class HomeView extends StackedView<HomeViewModel> {
@override
Widget builder(
BuildContext context, HomeViewModel viewModel, Widget? child) =>
_buildScaffold(viewModel);
KeyedSubtree(
key: ValueKey(context.locale.languageCode),
child: _buildScaffoldStack(viewModel));
Widget _buildScaffoldStack(HomeViewModel viewModel) => Stack(
children: [_buildScaffold(viewModel), _buildLogoutState(viewModel)],
);
Widget _buildScaffold(HomeViewModel viewModel) => Scaffold(
body: getViewForIndex(viewModel.currentPage),
@ -77,4 +86,9 @@ class HomeView extends StackedView<HomeViewModel> {
return const ProfileView();
}
}
Widget _buildLogoutState(HomeViewModel viewModel) =>
viewModel.state == StateObjects.logout
? const PageLoadingIndicator()
: Container();
}

View File

@ -5,6 +5,7 @@ import 'package:yimaru_app/services/status_checker_service.dart';
import 'package:yimaru_app/ui/common/app_strings.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../services/authentication_service.dart';
import '../../../services/in_app_update_service.dart';
@ -12,8 +13,13 @@ import '../../../services/in_app_update_service.dart';
class HomeViewModel extends ReactiveViewModel {
// Dependency injection
final _statusChecker = locator<StatusCheckerService>();
final _navigationService = locator<NavigationService>();
final _bottomSheetService = locator<BottomSheetService>();
final _inAppUpdateService = locator<InAppUpdateService>();
final _authenticationService = locator<AuthenticationService>();
@override
@ -25,6 +31,11 @@ class HomeViewModel extends ReactiveViewModel {
User? get user => _user;
// Logout state
StateObjects get _state => _authenticationService.state;
StateObjects get state => _state;
// Bottom navigation
int _currentPage = 0;
@ -44,6 +55,8 @@ class HomeViewModel extends ReactiveViewModel {
rebuildUi();
}
// Remote api calls
// In-app update

View File

@ -29,9 +29,12 @@ class LanguageViewModel extends ReactiveViewModel {
Future<void> setSelectedLanguage(
{required BuildContext context,
required Map<String, dynamic> title}) async =>
await _localizationService.setSelectedLanguage(
context: context, title: title);
required Map<String, dynamic> title}) async {
await _localizationService.setSelectedLanguage(
context: context, title: title);
rebuildUi();
}
// Navigation
void pop() => _navigationService.back();

View File

@ -26,12 +26,12 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
required LearnLesson lesson,
required BuildContext context,
required LearnLessonViewModel viewModel}) async {
if (lesson.access?.isAccessible ?? false) {
/* if (lesson.access?.isAccessible ?? false) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else {
await _showSheet(context: context, viewModel: viewModel);
}
/* if (index > 1) {
}*/
if (index > 1) {
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') {
if (lesson.access?.isAccessible ?? false) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
@ -47,7 +47,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
} else {
await _showSheet(context: context, viewModel: viewModel);
}
}*/
}
}
Future<void> _showSheet(

View File

@ -31,10 +31,10 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
Future<void> _onPractice(
{required LearnLesson lesson,
required LearnLessonDetailViewModel viewModel}) async {
await viewModel.pause();
/* await viewModel.pause();
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
/* if (index > 1) {
*/
if (index > 1) {
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') {
await viewModel.pause();
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
@ -45,7 +45,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
} else {
await viewModel.pause();
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
}*/
}
}
@override

View File

@ -306,7 +306,7 @@ class LearnPracticeViewModel extends ReactiveViewModel {
Future<void> _completeLearnPractices() async {
if (await _statusChecker.checkConnection()) {
await _apiService.completeLearnPractice(_practices.first.id ?? 0);
await _learnService.getLearnProgressSummary();
await _learnService.getLearnProgress();
}
}

View File

@ -203,10 +203,10 @@ class OnboardingViewModel extends ReactiveViewModel
void setSelectedCountry(FieldOption? value) {
_selectedCountry = value;
if (value?.label?.toLowerCase().trim() == 'ethiopia') {
if (value?.code?.toLowerCase().trim() == 'et') {
_dropdownRegion = true;
_selectedRegion = _regions
.firstWhere((e) => e.label?.toLowerCase().trim() == 'addis ababa');
.firstWhere((e) => e.code?.toLowerCase().trim().contains('addis_ababa') ?? false);
} else {
_dropdownRegion = false;
}

View File

@ -166,7 +166,7 @@ class ProfileView extends StackedView<ProfileViewModel> {
List<Widget> _buildSettingsChildren(ProfileViewModel viewModel) => [
// _buildDownloadsCard(viewModel),
// _buildProgressCard(viewModel),
_buildProgressCard(viewModel),
_buildAccountCard(viewModel),
_buildSupportCard(viewModel)
];

View File

@ -68,10 +68,10 @@ class ProfileViewModel extends ReactiveViewModel {
DialogResponse? response = await _dialogService.showDialog(
barrierDismissible: true,
cancelTitleColor: kcDarkGrey,
buttonTitleColor: kcPrimaryColor,
title: LocaleKeys.logout.tr(),
cancelTitle: LocaleKeys.no.tr(),
buttonTitle: LocaleKeys.yes.tr(),
buttonTitleColor: kcPrimaryColor,
description: LocaleKeys.want_to_quit.tr(),
);
return response?.confirmed;
@ -119,7 +119,6 @@ class ProfileViewModel extends ReactiveViewModel {
}
Future<void> _logout() async {
await _googleAuthService.logout();
await _authenticationService.logout();
await navigateToLogin();
}

View File

@ -93,6 +93,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
}
void _onModelReady(ProfileDetailViewModel viewModel) {
print('MY RESPONSE: ${viewModel.user?.region}');
phoneNumberController.text = '251900000000';
emailController.text = viewModel.user?.email ?? '';
lastNameController.text = viewModel.user?.lastName ?? '';
@ -103,9 +104,14 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
viewModel.setSelectedOccupation(viewModel.occupations
.where((e) => (e.code ?? '') == viewModel.user?.occupation)
.first);
viewModel.setSelectedCountry(viewModel.countries
viewModel.setSelectedCountry(viewModel.countries
.where((e) => (e.code ?? '') == viewModel.user?.country)
.first);
if (viewModel.user?.country?.toLowerCase() == 'et') {
viewModel.setEthiopianRegion(viewModel.user?.region ?? '');
} else {
regionController.text = viewModel.user?.region ?? '';
}
}
@override
@ -665,6 +671,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
Icons.search,
color: kcPrimaryColor,
);
Widget _buildLowerColumn(ProfileDetailViewModel viewModel) => Column(
mainAxisSize: MainAxisSize.min,
children: _buildLowerColumnChildren(viewModel),

View File

@ -134,12 +134,20 @@ class ProfileDetailViewModel extends ReactiveViewModel
List<FieldOption> get countries => _countries;
void setEthiopianRegion(String region) {
_dropdownRegion = true;
_selectedRegion =
_regions.firstWhere((r) => r.code?.toLowerCase() == region.toLowerCase());
rebuildUi();
}
void setSelectedCountry(FieldOption? value) {
_selectedCountry = value;
if (value?.label?.toLowerCase().trim() == 'ethiopia') {
if (value?.code?.toLowerCase().trim().contains('et') ?? false) {
_dropdownRegion = true;
_selectedRegion = _regions
.firstWhere((e) => e.label?.toLowerCase().trim() == 'addis ababa');
_selectedRegion = _regions.firstWhere(
(e) => e.code?.toLowerCase().trim().contains('addis_ababa') ?? false);
} else {
_dropdownRegion = false;
}

View File

@ -1,5 +1,7 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import '../../common/app_colors.dart';
import '../../common/ui_helpers.dart';
@ -11,6 +13,12 @@ import 'progress_viewmodel.dart';
class ProgressView extends StackedView<ProgressViewModel> {
const ProgressView({Key? key}) : super(key: key);
@override
void onViewModelReady(ProgressViewModel viewModel) async {
await viewModel.getProgressSummary();
super.onViewModelReady(viewModel);
}
@override
ProgressViewModel viewModelBuilder(BuildContext context) =>
ProgressViewModel();
@ -54,9 +62,9 @@ class ProgressView extends StackedView<ProgressViewModel> {
);
Widget _buildAppbar(ProgressViewModel viewModel) => SmallAppBar(
title: 'My Progress',
showBackButton: true,
onPop: viewModel.pop,
title: LocaleKeys.my_progress.tr(),
);
Widget _buildContentScrollViewWrapper(ProgressViewModel viewModel) =>
@ -81,12 +89,12 @@ class ProgressView extends StackedView<ProgressViewModel> {
verticalSpaceMedium,
_buildLearningProgressCard(),
verticalSpaceMedium,
_buildCourseProgressSection()
// _buildCourseProgressSection()
];
Widget _buildText() => const Text(
'Track your learning journey and see your growth over time.',
style: TextStyle(color: kcDarkGrey),
Widget _buildText() => Text(
LocaleKeys.track_journey.tr(),
style: style14DG400,
);
Widget _buildLearningProgressCard() => const LearningProgressCard();

View File

@ -1,12 +1,40 @@
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:yimaru_app/services/learn_service.dart';
import 'package:yimaru_app/services/status_checker_service.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../app/app.locator.dart';
import '../../../models/progress_summary.dart';
class ProgressViewModel extends BaseViewModel {
class ProgressViewModel extends ReactiveViewModel {
// Dependency injection
final _learnService = locator<LearnService>();
final _navigationService = locator<NavigationService>();
final _statusCheckerService = locator<StatusCheckerService>();
@override
List<ListenableServiceMixin> get listenableServices => [_learnService];
// Total practice count
int get _totalCount => _learnService.totalCount;
int get totalCount => _totalCount;
// Completed practice count
int get _completedCount => _learnService.completedCount;
int get completedCount => _completedCount;
// Total progress
int get _totalProgress => _learnService.totalProgress;
int get totalProgress => _totalProgress;
// Courses
final List<Map<String, dynamic>> _courses = [
{
@ -21,4 +49,17 @@ class ProgressViewModel extends BaseViewModel {
// Navigation
void pop() => _navigationService.back();
// Remote api
// Learning progress
Future<void> getProgressSummary() async => runBusyFuture(_getProgressSummary(),
busyObject: StateObjects.progressSummary);
Future<void> _getProgressSummary() async {
if (await _statusCheckerService.checkConnection()) {
await _learnService.getProgressSummary();
}
}
}

View File

@ -122,10 +122,12 @@ class StartupViewModel extends ReactiveViewModel {
await _authenticationService.saveUserData(user);
String image =
String? image =
await _imageDownloaderService.downloader(user.profilePicture);
await _authenticationService.saveProfilePicture(image);
if (image != null) {
await _authenticationService.saveProfilePicture(image);
}
}
}
}

View File

@ -7,7 +7,6 @@ import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import 'package:yimaru_app/ui/views/learn_module/learn_module_viewmodel.dart';
import 'package:yimaru_app/ui/widgets/custom_container_shader.dart';
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart';
import '../common/app_colors.dart';
import '../common/ui_helpers.dart';

View File

@ -1,4 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
import 'package:yimaru_app/ui/views/progress/progress_viewmodel.dart';
import 'package:yimaru_app/ui/widgets/custom_column.dart';
import '../common/app_colors.dart';
@ -6,45 +11,46 @@ import '../common/ui_helpers.dart';
import 'custom_elevated_button.dart';
import 'custom_linear_progress_indicator.dart';
class LearningProgressCard extends StatelessWidget {
class LearningProgressCard extends ViewModelWidget<ProgressViewModel> {
final GestureTapCallback? onTap;
const LearningProgressCard({super.key, this.onTap});
@override
Widget build(BuildContext context) => _buildContainerWrapper();
Widget build(BuildContext context, ProgressViewModel viewModel) =>
_buildContainerWrapper(viewModel);
Widget _buildContainerWrapper() => GestureDetector(
Widget _buildContainerWrapper(ProgressViewModel viewModel) => GestureDetector(
onTap: onTap,
child: _buildContainer(),
child: _buildContainer(viewModel),
);
Widget _buildContainer() => Container(
Widget _buildContainer(ProgressViewModel viewModel) => Container(
height: 320,
padding: const EdgeInsets.all(15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: kcPrimaryColor.withOpacity(0.1),
),
child: _buildColumn(),
child: _buildColumn(viewModel),
);
Widget _buildColumn() => Column(
Widget _buildColumn(ProgressViewModel viewModel) => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: _buildColumnChildren(),
children: _buildColumnChildren(viewModel),
);
List<Widget> _buildColumnChildren() => [
List<Widget> _buildColumnChildren(ProgressViewModel viewModel) => [
_buildIcon(),
verticalSpaceSmall,
_buildTitle(),
verticalSpaceTiny,
_buildSubtitle(),
verticalSpaceSmall,
_buildProgressIndicator(),
_buildProgressIndicator(viewModel),
verticalSpaceSmall,
_buildLearningStatus(),
_buildLearningStatus(viewModel),
verticalSpaceMedium,
_buildActionButton(),
];
@ -56,47 +62,64 @@ class LearningProgressCard extends StatelessWidget {
);
Widget _buildTitle() => Text(
'Learn English',
LocaleKeys.learn_english.tr(),
style: style16DG600,
);
Widget _buildSubtitle() => const Text(
'Great job! Keep the momentum.',
Widget _buildSubtitle() => Text(
LocaleKeys.keep_momentum.tr(),
maxLines: 2,
style: TextStyle(color: kcMediumGrey),
style: style14MG400,
);
Widget _buildProgressIndicator() => const CustomLinearProgressIndicator(
progress: 0,
Widget _buildProgressIndicator(ProgressViewModel viewModel) =>
CustomLinearProgressIndicator(
activeColor: kcPrimaryColor,
backgroundColor: kcVeryLightGrey,
progress: viewModel.busy(StateObjects.progressSummary)
? 0
: viewModel.totalProgress / 100,
);
Widget _buildLearningStatus() => Row(
children: _buildLearningStatusChildren(),
Widget _buildLearningStatus(ProgressViewModel viewModel) => Row(
children: _buildLearningStatusChildren(viewModel),
);
List<Widget> _buildLearningStatusChildren() => [
_buildWatchedVideos(),
List<Widget> _buildLearningStatusChildren(ProgressViewModel viewModel) => [
_buildCompletedPractices(viewModel),
horizontalSpaceSmall,
_buildCompletedPractices(),
_buildTotalPractices(viewModel),
horizontalSpaceSmall,
_buildTakenQuizzes()
_buildProgressPercentage(viewModel),
];
Widget _buildWatchedVideos() => const Expanded(
child: CustomColumn(title: '0', subtitle: 'Videos Watched'));
Widget _buildCompletedPractices() => const Expanded(
child: CustomColumn(title: '0', subtitle: 'Practices Completed'));
Widget _buildTakenQuizzes() => const Expanded(
child: CustomColumn(title: '0', subtitle: 'Quizzes Taken'));
Widget _buildCompletedPractices(ProgressViewModel viewModel) => Expanded(
child: CustomColumn(
title: viewModel.busy(StateObjects.progressSummary)
? '-'
: viewModel.completedCount.toString(),
subtitle: LocaleKeys.completed_practices.tr()));
Widget _buildActionButton() => const CustomElevatedButton(
Widget _buildTotalPractices(ProgressViewModel viewModel) => Expanded(
child: CustomColumn(
title: viewModel.busy(StateObjects.progressSummary)
? '-'
: viewModel.totalCount.toString(),
subtitle: LocaleKeys.total_practices.tr()));
Widget _buildProgressPercentage(ProgressViewModel viewModel) => Expanded(
child: CustomColumn(
title: viewModel.busy(StateObjects.progressSummary)
? '-'
: '${viewModel.totalProgress.toString()}%',
subtitle: LocaleKeys.progress_percentage.tr()));
Widget _buildActionButton() => CustomElevatedButton(
height: 15,
width: 200,
borderRadius: 12,
text: 'Continue Learning',
foregroundColor: kcWhite,
backgroundColor: kcPrimaryColor,
text: LocaleKeys.continue_learning.tr(),
);
}

View File

@ -1,5 +1,5 @@
name: yimaru_app
version: 0.1.30+32
version: 0.1.31+33
publish_to: 'none'
description: A new Flutter project.