Merge remote-tracking branch 'origin/main' into test-ios

This commit is contained in:
Kerod-Fresenbet-Gebremedhin2660 2026-06-01 11:22:07 +03:00
commit a9389070bf
27 changed files with 900 additions and 716 deletions

View File

@ -187,6 +187,14 @@
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ", "finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ", "finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
"finish_all_practice_previouse_module": "ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ", "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", "loading": "Loading",
"welcome_back": "Welcome back", "welcome_back": "Welcome back",
"checking_user_info": "Checking user info", "checking_user_info": "Checking user info",
"dont_have_account": "Don't have an account?", "dont_have_account": "Don't have an account?",
"email": "Email", "email": "Email",
"password": "Password", "password": "Password",
"forgot_password": "Forgot password?", "forgot_password": "Forgot password?",
"cont": "Continue", "cont": "Continue",
"register": "Register", "register": "Register",
"login_with_google": "Login with Google", "login_with_google": "Login with Google",
"or": "Or", "or": "Or",
"login_with_phone": "Login with phone number", "login_with_phone": "Login with phone number",
"create_account": "Create an account", "create_account": "Create an account",
"already_have_account": "Already have an account?", "already_have_account": "Already have an account?",
"login": "Login", "login": "Login",
"register_with_google": "Register with Google", "register_with_google": "Register with Google",
"register_with_phone": "Register with phone number", "register_with_phone": "Register with phone number",
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.", "enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
"login_with_email": "Login with email", "login_with_email": "Login with email",
"create_password": "Create password", "create_password": "Create password",
"confirm_password": "Confirm password", "confirm_password": "Confirm password",
"eight_character_minimum": "8 characters minimum", "eight_character_minimum": "8 characters minimum",
"password_match": "password match", "password_match": "password match",
"sign_up_agreement": "By clicking Sign Up, you agree to our Terms of Service and Privacy Policy", "sign_up_agreement": "By clicking Sign Up, you agree to our Terms of Service and Privacy Policy",
"terms_of_services": "Terms of Service", "terms_of_services": "Terms of Service",
"and": "and", "and": "and",
"privacy_policy": "Privacy Policy", "privacy_policy": "Privacy Policy",
"register_with_email": "Register with email", "register_with_email": "Register with email",
"verification_code": "Verification Code", "verification_code": "Verification Code",
"resend_code": "Resend Code", "resend_code": "Resend Code",
"code_sent_to_phone": "Code sent to your number", "code_sent_to_phone": "Code sent to your number",
"code_sent_to_email": "Code sent to your email", "code_sent_to_email": "Code sent to your email",
"resend_code_in": "Resend code in", "resend_code_in": "Resend code in",
"reset_password": "Reset Password", "reset_password": "Reset Password",
"enter_email_reset_code": "Enter your email. We will send you a reset code.", "enter_email_reset_code": "Enter your email. We will send you a reset code.",
"please_wait": "Please wait", "please_wait": "Please wait",
"reset_code_sent": "Reset code sent successfully", "reset_code_sent": "Reset code sent successfully",
"reset_code": "Reset code", "reset_code": "Reset code",
"new_password": "New password", "new_password": "New password",
"logged_in_successfully": "Logged in successfully", "logged_in_successfully": "Logged in successfully",
"continue_learning": "Continue Learning", "continue_learning": "Continue Learning",
"start_learning": "Start Learning", "start_learning": "Start Learning",
"completed": "Completed", "completed": "Completed",
"view_course": "View course", "view_course": "View course",
"take_practice": "Take practice", "take_practice": "Take practice",
"your_current_level": "Your current level", "your_current_level": "Your current level",
"overall_progress": "Overall progress", "overall_progress": "Overall progress",
"great_work": "Keep up the great work! You're doing amazing", "great_work": "Keep up the great work! You're doing amazing",
"view_module": "View module", "view_module": "View module",
"progress": "Progress", "progress": "Progress",
"keep_going": "Let's keep going - you're more than half there", "keep_going": "Let's keep going - you're more than half there",
"lessons_in_module": "Lessons in this module", "lessons_in_module": "Lessons in this module",
"practice": "Practice", "practice": "Practice",
"start": "Start", "start": "Start",
"in_progress": "In Progress", "in_progress": "In Progress",
"hello": "Hello", "hello": "Hello",
"ready_to_learn": "Ready to keep learning English today", "ready_to_learn": "Ready to keep learning English today",
"learn": "Learn", "learn": "Learn",
"course": "Course", "course": "Course",
"profile": "Profile", "profile": "Profile",
"speaking_partner": "Speaking partner", "speaking_partner": "Speaking partner",
"practice_what_you_learned": "Let's practice what you just learnt", "practice_what_you_learned": "Let's practice what you just learnt",
"practice_questions": "I will ask you a few questions and you can respond", "practice_questions": "I will ask you a few questions and you can respond",
"start_practice": "Start practice", "start_practice": "Start practice",
"almost_there": "You're almost there", "almost_there": "You're almost there",
"finish_session": "Finish the session to see your progress", "finish_session": "Finish the session to see your progress",
"continue_practice": "Continue practice", "continue_practice": "Continue practice",
"end_session": "End session", "end_session": "End session",
"tap_start_to_listen": "Tap the start button to listen", "tap_start_to_listen": "Tap the start button to listen",
"practice_speaking": "Practice speaking", "practice_speaking": "Practice speaking",
"tap_microphone": "Tap the microphone to speak", "tap_microphone": "Tap the microphone to speak",
"reply": "Reply", "reply": "Reply",
"cancel": "Cancel", "cancel": "Cancel",
"you_are_speaking": "You're speaking", "you_are_speaking": "You're speaking",
"practice_completed": "Practice completed!", "practice_completed": "Practice completed!",
"great_improvement": "You sound more confident this time, great improvement", "great_improvement": "You sound more confident this time, great improvement",
"practice_again": "Practice again", "practice_again": "Practice again",
"conversation_review": "Conversation review", "conversation_review": "Conversation review",
"result": "Result", "result": "Result",
"quick_tip": "Quick tip", "quick_tip": "Quick tip",
"retry": "Retry", "retry": "Retry",
"completed_a1": "Yay, you've completed A1", "completed_a1": "Yay, you've completed A1",
"analyzing_speaking": "We're now analyzing your speaking skill", "analyzing_speaking": "We're now analyzing your speaking skill",
"view_profile": "View profile", "view_profile": "View profile",
"hi": "Hi", "hi": "Hi",
"edit_profile": "Edit profile", "edit_profile": "Edit profile",
"first_name": "First name", "first_name": "First name",
"last_name": "Last name", "last_name": "Last name",
"gender": "Gender", "gender": "Gender",
"male": "Male", "male": "Male",
"female": "Female", "female": "Female",
"phone_number": "Phone number", "phone_number": "Phone number",
"country": "Country", "country": "Country",
"region": "Region", "region": "Region",
"select_region": "Select region", "select_region": "Select region",
"enter_your_city": "Enter your city", "enter_your_city": "Enter your city",
"occupation": "Occupation", "occupation": "Occupation",
"select_occupation": "Select occupation", "select_occupation": "Select occupation",
"save_changes": "Save changes", "save_changes": "Save changes",
"my_progress": "My progress", "my_progress": "My progress",
"track_your_achievement": "Track your achievements and learning streak", "track_your_achievement": "Track your achievements and learning streak",
"account_and_privacy": "Account & Privacy", "account_and_privacy": "Account & Privacy",
"manage_settings": "Manage settings and app preference", "manage_settings": "Manage settings and app preference",
"support": "Support", "support": "Support",
"get_help": "Get help through phone or Telegram", "get_help": "Get help through phone or Telegram",
"logout": "Logout", "logout": "Logout",
"app_settings": "App settings", "app_settings": "App settings",
"legal_and_information": "Legal & Information", "legal_and_information": "Legal & Information",
"change_language": "Change language", "change_language": "Change language",
"terms_and_conditions":"Terms & Conditions", "terms_and_conditions": "Terms & Conditions",
"delete_account": "Delete account", "delete_account": "Delete account",
"language_preference": "Language preference", "language_preference": "Language preference",
"choose_your_language": "Choose your language", "choose_your_language": "Choose your language",
"switch_language_anytime": "You can switch languages anytime", "switch_language_anytime": "You can switch languages anytime",
"need_help": "Need help?", "need_help": "Need help?",
"call_support": "Call support", "call_support": "Call support",
"talk_with_support": "Talk with our support team directly", "talk_with_support": "Talk with our support team directly",
"telegram_support": "Telegram support", "telegram_support": "Telegram support",
"chat_via_telegram" :"Chat instantly via Telegram", "chat_via_telegram": "Chat instantly via Telegram",
"call_our_support": "Call our support team between 9 AM - 6 PM", "call_our_support": "Call our support team between 9 AM - 6 PM",
"tap_to_call": "Tap to call", "tap_to_call": "Tap to call",
"join_telegram": "Join Yimaru Academy on Telegram", "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", "connect_with_support_team": "Connect with our support team instantly on Telegram for quick assistance and community updates",
"open_in_telegram": "Open in Telegram", "open_in_telegram": "Open in Telegram",
"search_for": "Search for", "search_for": "Search for",
"current_level": "Current Level", "current_level": "Current Level",
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.", "keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
"no_practice_available": "No practice available!", "no_practice_available": "No practice available!",
"begin_module_practice": "Begin Module Practice", "begin_module_practice": "Begin Module Practice",
"lets_practice_lesson": "Lets Practice", "lets_practice_lesson": "Lets Practice",
"lets_quickly_review": "Lets quickly review what youve learned in this module!", "lets_quickly_review": "Lets quickly review what youve learned in this module!",
"lets_practice_module": "Let's practice what you just learnt!", "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.", "ask_you_few_actions": "Ill ask you a few questions, and you can respond naturally.",
"begin_level_practice": "Begin Level Practice", "begin_level_practice": "Begin Level Practice",
"lets_practice_course": "Lets Practice Course", "lets_practice_course": "Lets Practice Course",
"lets_quick_review": "Lets quickly review what youve learned in this level!", "lets_quick_review": "Lets quickly review what youve learned in this level!",
"speaking": "is speaking...", "speaking": "is speaking...",
"you_have_finished_practice": "You have finished your practice", "you_have_finished_practice": "You have finished your practice",
"view_results": "View My Results", "view_results": "View My Results",
"sample_answer": "Sample Answer", "sample_answer": "Sample Answer",
"your_answer": "Your Answer", "your_answer": "Your Answer",
"sound_confident": "You sound more confident this time - great improvement!", "sound_confident": "You sound more confident this time - great improvement!",
"you_have_completed": "Yay, youve completed", "you_have_completed": "Yay, youve completed",
"yes": "Yes", "yes": "Yes",
"no": "No", "no": "No",
"want_to_quit": "Are you sure you want to quit?", "want_to_quit": "Are you sure you want to quit?",
"required_field": "The field is required", "required_field": "The field is required",
"enter_full_name": "Enter your full name", "enter_full_name": "Enter your full name",
"invalid_email": "Invalid email format", "invalid_email": "Invalid email format",
"phone_must_start_with": "Phone number must start with 251", "phone_must_start_with": "Phone number must start with 251",
"phone_must_be": "Phone number must be 12 digits", "phone_must_be": "Phone number must be 12 digits",
"what_should_we_call_you": "What should we call you?", "what_should_we_call_you": "What should we call you?",
"name_for_personalization": "Well use your name to personalize your learning journey.", "name_for_personalization": "Well use your name to personalize your learning journey.",
"choose_your_gender": "Choose your gender?", "choose_your_gender": "Choose your gender?",
"gender_for_personalization": "Well personalize your learning experience based on your gender.", "gender_for_personalization": "Well personalize your learning experience based on your gender.",
"age_range": "Which age range are you in?", "age_range": "Which age range are you in?",
"age_for_personalization": "Well personalize your learning experience based on your age.", "age_for_personalization": "Well personalize your learning experience based on your age.",
"educational_background": "Whats your current educational level?", "educational_background": "Whats your current educational level?",
"education_for_personalization": "This helps us tailor your lessons to your experience.", "education_for_personalization": "This helps us tailor your lessons to your experience.",
"your_occupation": "Whats your occupation?", "your_occupation": "Whats your occupation?",
"occupation_for_personalization": "Well personalize your learning experience based on your occupation.", "occupation_for_personalization": "Well personalize your learning experience based on your occupation.",
"location": "Where are you from?", "location": "Where are you from?",
"select_country_region": "Select your country and region from the dropdown", "select_country_region": "Select your country and region from the dropdown",
"select_country": "Select country", "select_country": "Select country",
"learning_goal": "Choose your learning goal.", "learning_goal": "Choose your learning goal.",
"language_goal": "Whats your main goal for improving your English?", "language_goal": "Whats your main goal for improving your English?",
"your_goal": "Your goal helps us tailor your learning journey.", "your_goal": "Your goal helps us tailor your learning journey.",
"write_your_goal": "Write your goal…", "write_your_goal": "Write your goal…",
"challenge_you_face": "What challenge do you face most with English?", "challenge_you_face": "What challenge do you face most with English?",
"evey_one_has_strugle": "Everyone has struggles, lets start fixing yours", "evey_one_has_strugle": "Everyone has struggles, lets start fixing yours",
"write_your_challenge": "Write your challenge…", "write_your_challenge": "Write your challenge…",
"topic_interest": "Which topics interest you most?", "topic_interest": "Which topics interest you most?",
"favourite_topic": "Your favorite topics help us create fun, relatable lessons.", "favourite_topic": "Your favorite topics help us create fun, relatable lessons.",
"your_interest": "Write your interest…", "your_interest": "Write your interest…",
"want_quick_assessment": "Want a quick assessment to know your English level?", "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.", "answer_quick_questions": "Answer a few quick questions to help us understand your English proficiency.",
"skip": "Skip", "skip": "Skip",
"finish_level": "Finish Level", "finish_level": "Finish Level",
"likely_speaker": "Youre likely speaker of", "likely_speaker": "Youre likely speaker of",
"great_job": "Great Job! Heres your next step to keep improving.", "great_job": "Great Job! Heres your next step to keep improving.",
"lets_start_practice": "Let's start your practice", "lets_start_practice": "Let's start your practice",
"welcome_abroad": "Welcome aboard", "welcome_abroad": "Welcome aboard",
"ready_to_explore": "Youre ready to explore your personalized lessons.", "ready_to_explore": "Youre ready to explore your personalized lessons.",
"finish": "Finish", "finish": "Finish",
"finish_all_practice_lesson": "Finish the previous lesson practice to take this practice", "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_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_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_module": "Finish the previous Module practice to take this practice",
"finish_all_practice_previouse_course": "Finish the previous course practice to take this" "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/app/app.locator.dart';
import 'package:yimaru_app/models/user.dart'; import 'package:yimaru_app/models/user.dart';
import 'package:yimaru_app/services/secure_storage_service.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'; import 'localization_service.dart';
class AuthenticationService with ListenableServiceMixin { class AuthenticationService with ListenableServiceMixin {
// Dependency injection // Dependency injection
final _secureService = locator<SecureStorageService>(); final _secureService = locator<SecureStorageService>();
final _googleAuthService = locator<GoogleAuthService>();
final _localizationService = locator<LocalizationService>(); final _localizationService = locator<LocalizationService>();
// User data // User data
@ -18,9 +23,15 @@ class AuthenticationService with ListenableServiceMixin {
// Initialization // Initialization
AuthenticationService() { AuthenticationService() {
listenToReactiveValues([_user, _localizationService]); listenToReactiveValues([_user,_state, _localizationService]);
} }
// Logout state
StateObjects _state = StateObjects.none;
StateObjects get state => _state;
// Check user logged in // Check user logged in
Future<bool> userLoggedIn() async { Future<bool> userLoggedIn() async {
if (await _secureService.getString('userId') != null) { if (await _secureService.getString('userId') != null) {
@ -179,13 +190,20 @@ class AuthenticationService with ListenableServiceMixin {
// Logout // Logout
Future<void> logout() async { Future<void> logout() async {
_state = StateObjects.logout;
notifyListeners();
bool firstTimeInstall = await isFirstTimeInstall(); bool firstTimeInstall = await isFirstTimeInstall();
String language = await _localizationService.selectedLanguage['code']; String language = await _localizationService.selectedLanguage['code'];
_user = null; _user = null;
await _secureService.clear(); await _secureService.clear();
await _googleAuthService.logout();
await setFirstTimeInstall(firstTimeInstall); await setFirstTimeInstall(firstTimeInstall);
await _secureService.setString('language', language); await _secureService.setString('language', language);
_state = StateObjects.none;
notifyListeners(); notifyListeners();
} }
} }

View File

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

View File

@ -5,39 +5,53 @@ import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import '../app/app.locator.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'; import 'dio_service.dart';
class ImageDownloaderService { class ImageDownloaderService {
// Dependency injection // Dependency injection
final _service = locator<DioService>(); final _service = locator<DioService>();
final _apiService = locator<ApiService>();
final Dio _dio = Dio();
// Image downloader // Image downloader
Future<String> downloader(String? networkImage) async { Future<String?> downloader(String? networkImage) async {
late File image; try {
File? image;
late String profileImage; String? profileImage = networkImage;
final Directory appDir = await getApplicationDocumentsDirectory(); final Directory appDir = await getApplicationDocumentsDirectory();
if (networkImage != null) { Map<String, dynamic> data = {'reference': profileImage};
profileImage = networkImage.contains('https://lh3.googleusercontent.com') Map<String, dynamic> response = await _apiService.refreshObject(data);
? networkImage
: '$kBaseUrl$networkImage'; 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: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/models/refresh_object.dart';
import 'package:yimaru_app/ui/common/enmus.dart'; import 'package:yimaru_app/ui/common/enmus.dart';
@ -17,9 +19,25 @@ class LearnService with ListenableServiceMixin {
// Initialization // Initialization
learnService() { 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 // Learn program
List<LearnProgram> _programs = []; List<LearnProgram> _programs = [];
@ -40,10 +58,7 @@ class LearnService with ListenableServiceMixin {
List<LearnLesson> get lessons => _lessons; List<LearnLesson> get lessons => _lessons;
// Learn progress
final List<ProgressSummary> _summaries = [];
List<ProgressSummary> get summaries => _summaries;
// Learn programs // Learn programs
Future<String?> refreshObject(String url) async { Future<String?> refreshObject(String url) async {
@ -87,7 +102,7 @@ class LearnService with ListenableServiceMixin {
} }
// Learn progress // Learn progress
Future<void> getLearnProgressSummary() async { Future<void> getLearnProgress() async {
final summaries = await _apiService.getProgressSummary(); final summaries = await _apiService.getProgressSummary();
/// PROGRAM ACCESS MAP /// PROGRAM ACCESS MAP
@ -148,10 +163,6 @@ class LearnService with ListenableServiceMixin {
); );
}).toList(); }).toList();
print(
'MY SUMMARIES - COMPLETED COUNT: ${_modules.first.access?.completedCount}');
print('PROGRESS PERCENT: ${_modules.first.access?.progressPercent}');
/// UPDATE LESSONS /// UPDATE LESSONS
_lessons = _lessons.map((lesson) { _lessons = _lessons.map((lesson) {
return lesson.copyWith( return lesson.copyWith(
@ -177,4 +188,30 @@ class LearnService with ListenableServiceMixin {
return null; 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 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 = 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 // State object
enum StateObjects { enum StateObjects {
none, none,
logout,
courses, courses,
register, register,
verifyOtp, verifyOtp,
@ -55,6 +56,7 @@ enum StateObjects {
loginWithGoogle, loginWithGoogle,
loadLessonVideo, loadLessonVideo,
loadCourseVideo, loadCourseVideo,
progressSummary,
requestResetCode, requestResetCode,
profileCompletion, profileCompletion,
learnSubscription, learnSubscription,

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

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,8 +161,7 @@ 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 = static const occupation_for_personalization = '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';
@ -189,8 +188,13 @@ abstract class LocaleKeys {
static const finish_all_practice_lesson = 'finish_all_practice_lesson'; 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_module = 'finish_all_practice_module';
static const finish_all_practice_course = 'finish_all_practice_course'; static const finish_all_practice_course = 'finish_all_practice_course';
static const finish_all_practice_previouse_module = static const finish_all_practice_previouse_module = '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_course = static const track_journey = 'track_journey';
'finish_all_practice_previouse_course'; 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:flutter/material.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:yimaru_app/ui/common/app_colors.dart'; import 'package:yimaru_app/ui/common/app_colors.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import 'package:yimaru_app/ui/common/translations/locale_keys.g.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/learn_program/learn_program_view.dart';
import 'package:yimaru_app/ui/views/profile/profile_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 '../../widgets/coming_soon.dart';
import 'home_viewmodel.dart'; import 'home_viewmodel.dart';
class HomeView extends StackedView<HomeViewModel> { class HomeView extends StackedView<HomeViewModel> {
const HomeView({Key? key}) : super(key: key); const HomeView({Key? key}) : super(key: key);
@override @override
void onViewModelReady(HomeViewModel viewModel) async { void onViewModelReady(HomeViewModel viewModel) async {
await viewModel.inAppUpdate(); await viewModel.inAppUpdate();
@ -23,7 +26,13 @@ class HomeView extends StackedView<HomeViewModel> {
@override @override
Widget builder( Widget builder(
BuildContext context, HomeViewModel viewModel, Widget? child) => 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( Widget _buildScaffold(HomeViewModel viewModel) => Scaffold(
body: getViewForIndex(viewModel.currentPage), body: getViewForIndex(viewModel.currentPage),
@ -77,4 +86,9 @@ class HomeView extends StackedView<HomeViewModel> {
return const ProfileView(); 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:yimaru_app/ui/common/app_strings.dart';
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart'; import 'package:stacked_services/stacked_services.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../services/authentication_service.dart'; import '../../../services/authentication_service.dart';
import '../../../services/in_app_update_service.dart'; import '../../../services/in_app_update_service.dart';
@ -12,8 +13,13 @@ import '../../../services/in_app_update_service.dart';
class HomeViewModel extends ReactiveViewModel { class HomeViewModel extends ReactiveViewModel {
// Dependency injection // Dependency injection
final _statusChecker = locator<StatusCheckerService>(); final _statusChecker = locator<StatusCheckerService>();
final _navigationService = locator<NavigationService>();
final _bottomSheetService = locator<BottomSheetService>(); final _bottomSheetService = locator<BottomSheetService>();
final _inAppUpdateService = locator<InAppUpdateService>(); final _inAppUpdateService = locator<InAppUpdateService>();
final _authenticationService = locator<AuthenticationService>(); final _authenticationService = locator<AuthenticationService>();
@override @override
@ -25,6 +31,11 @@ class HomeViewModel extends ReactiveViewModel {
User? get user => _user; User? get user => _user;
// Logout state
StateObjects get _state => _authenticationService.state;
StateObjects get state => _state;
// Bottom navigation // Bottom navigation
int _currentPage = 0; int _currentPage = 0;
@ -44,6 +55,8 @@ class HomeViewModel extends ReactiveViewModel {
rebuildUi(); rebuildUi();
} }
// Remote api calls // Remote api calls
// In-app update // In-app update

View File

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

View File

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

View File

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

View File

@ -306,7 +306,7 @@ class LearnPracticeViewModel extends ReactiveViewModel {
Future<void> _completeLearnPractices() async { Future<void> _completeLearnPractices() async {
if (await _statusChecker.checkConnection()) { if (await _statusChecker.checkConnection()) {
await _apiService.completeLearnPractice(_practices.first.id ?? 0); 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) { void setSelectedCountry(FieldOption? value) {
_selectedCountry = value; _selectedCountry = value;
if (value?.label?.toLowerCase().trim() == 'ethiopia') { if (value?.code?.toLowerCase().trim() == 'et') {
_dropdownRegion = true; _dropdownRegion = true;
_selectedRegion = _regions _selectedRegion = _regions
.firstWhere((e) => e.label?.toLowerCase().trim() == 'addis ababa'); .firstWhere((e) => e.code?.toLowerCase().trim().contains('addis_ababa') ?? false);
} else { } else {
_dropdownRegion = false; _dropdownRegion = false;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,40 @@
import 'package:stacked/stacked.dart'; import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.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 '../../../app/app.locator.dart';
import '../../../models/progress_summary.dart';
class ProgressViewModel extends BaseViewModel { class ProgressViewModel extends ReactiveViewModel {
// Dependency injection // Dependency injection
final _learnService = locator<LearnService>();
final _navigationService = locator<NavigationService>(); 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 // Courses
final List<Map<String, dynamic>> _courses = [ final List<Map<String, dynamic>> _courses = [
{ {
@ -21,4 +49,17 @@ class ProgressViewModel extends BaseViewModel {
// Navigation // Navigation
void pop() => _navigationService.back(); 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); await _authenticationService.saveUserData(user);
String image = String? image =
await _imageDownloaderService.downloader(user.profilePicture); 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/views/learn_module/learn_module_viewmodel.dart';
import 'package:yimaru_app/ui/widgets/custom_container_shader.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/custom_linear_progress_indicator.dart';
import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart';
import '../common/app_colors.dart'; import '../common/app_colors.dart';
import '../common/ui_helpers.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: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 'package:yimaru_app/ui/widgets/custom_column.dart';
import '../common/app_colors.dart'; import '../common/app_colors.dart';
@ -6,45 +11,46 @@ import '../common/ui_helpers.dart';
import 'custom_elevated_button.dart'; import 'custom_elevated_button.dart';
import 'custom_linear_progress_indicator.dart'; import 'custom_linear_progress_indicator.dart';
class LearningProgressCard extends StatelessWidget { class LearningProgressCard extends ViewModelWidget<ProgressViewModel> {
final GestureTapCallback? onTap; final GestureTapCallback? onTap;
const LearningProgressCard({super.key, this.onTap}); const LearningProgressCard({super.key, this.onTap});
@override @override
Widget build(BuildContext context) => _buildContainerWrapper(); Widget build(BuildContext context, ProgressViewModel viewModel) =>
_buildContainerWrapper(viewModel);
Widget _buildContainerWrapper() => GestureDetector( Widget _buildContainerWrapper(ProgressViewModel viewModel) => GestureDetector(
onTap: onTap, onTap: onTap,
child: _buildContainer(), child: _buildContainer(viewModel),
); );
Widget _buildContainer() => Container( Widget _buildContainer(ProgressViewModel viewModel) => Container(
height: 320, height: 320,
padding: const EdgeInsets.all(15), padding: const EdgeInsets.all(15),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5), borderRadius: BorderRadius.circular(5),
color: kcPrimaryColor.withOpacity(0.1), color: kcPrimaryColor.withOpacity(0.1),
), ),
child: _buildColumn(), child: _buildColumn(viewModel),
); );
Widget _buildColumn() => Column( Widget _buildColumn(ProgressViewModel viewModel) => Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: _buildColumnChildren(), children: _buildColumnChildren(viewModel),
); );
List<Widget> _buildColumnChildren() => [ List<Widget> _buildColumnChildren(ProgressViewModel viewModel) => [
_buildIcon(), _buildIcon(),
verticalSpaceSmall, verticalSpaceSmall,
_buildTitle(), _buildTitle(),
verticalSpaceTiny, verticalSpaceTiny,
_buildSubtitle(), _buildSubtitle(),
verticalSpaceSmall, verticalSpaceSmall,
_buildProgressIndicator(), _buildProgressIndicator(viewModel),
verticalSpaceSmall, verticalSpaceSmall,
_buildLearningStatus(), _buildLearningStatus(viewModel),
verticalSpaceMedium, verticalSpaceMedium,
_buildActionButton(), _buildActionButton(),
]; ];
@ -56,47 +62,64 @@ class LearningProgressCard extends StatelessWidget {
); );
Widget _buildTitle() => Text( Widget _buildTitle() => Text(
'Learn English', LocaleKeys.learn_english.tr(),
style: style16DG600, style: style16DG600,
); );
Widget _buildSubtitle() => const Text( Widget _buildSubtitle() => Text(
'Great job! Keep the momentum.', LocaleKeys.keep_momentum.tr(),
maxLines: 2, maxLines: 2,
style: TextStyle(color: kcMediumGrey), style: style14MG400,
); );
Widget _buildProgressIndicator() => const CustomLinearProgressIndicator( Widget _buildProgressIndicator(ProgressViewModel viewModel) =>
progress: 0, CustomLinearProgressIndicator(
activeColor: kcPrimaryColor, activeColor: kcPrimaryColor,
backgroundColor: kcVeryLightGrey, backgroundColor: kcVeryLightGrey,
progress: viewModel.busy(StateObjects.progressSummary)
? 0
: viewModel.totalProgress / 100,
); );
Widget _buildLearningStatus() => Row( Widget _buildLearningStatus(ProgressViewModel viewModel) => Row(
children: _buildLearningStatusChildren(), children: _buildLearningStatusChildren(viewModel),
); );
List<Widget> _buildLearningStatusChildren() => [ List<Widget> _buildLearningStatusChildren(ProgressViewModel viewModel) => [
_buildWatchedVideos(), _buildCompletedPractices(viewModel),
horizontalSpaceSmall, horizontalSpaceSmall,
_buildCompletedPractices(), _buildTotalPractices(viewModel),
horizontalSpaceSmall, horizontalSpaceSmall,
_buildTakenQuizzes() _buildProgressPercentage(viewModel),
]; ];
Widget _buildWatchedVideos() => const Expanded( Widget _buildCompletedPractices(ProgressViewModel viewModel) => Expanded(
child: CustomColumn(title: '0', subtitle: 'Videos Watched')); child: CustomColumn(
Widget _buildCompletedPractices() => const Expanded( title: viewModel.busy(StateObjects.progressSummary)
child: CustomColumn(title: '0', subtitle: 'Practices Completed')); ? '-'
Widget _buildTakenQuizzes() => const Expanded( : viewModel.completedCount.toString(),
child: CustomColumn(title: '0', subtitle: 'Quizzes Taken')); 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, height: 15,
width: 200, width: 200,
borderRadius: 12, borderRadius: 12,
text: 'Continue Learning',
foregroundColor: kcWhite, foregroundColor: kcWhite,
backgroundColor: kcPrimaryColor, backgroundColor: kcPrimaryColor,
text: LocaleKeys.continue_learning.tr(),
); );
} }

View File

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