Merge branch 'release/0.1.22'
-fix: Apply fix on onboarding issue
This commit is contained in:
commit
f71220fa80
|
|
@ -2,7 +2,7 @@
|
||||||
"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": "የይለፍ ቃል ረሱ?",
|
||||||
|
|
@ -43,14 +43,14 @@
|
||||||
"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": "በሂደት ላይ",
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
||||||
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
||||||
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
||||||
"lets_quick_practice": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
"lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
||||||
"speaking": "እየተናገረ ነው",
|
"speaking": "እየተናገረ ነው",
|
||||||
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
||||||
"view_results": "ውጤቶቼን እይ",
|
"view_results": "ውጤቶቼን እይ",
|
||||||
|
|
@ -153,15 +153,36 @@
|
||||||
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
||||||
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
||||||
"choose_your_gender": "ጾታህን ምረጥ",
|
"choose_your_gender": "ጾታህን ምረጥ",
|
||||||
"gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።"
|
"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": "አጠናቅቅ"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
{"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? Register",
|
"dont_have_account": "Don't have an account?",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"forgot_password": "Forgot password?",
|
"forgot_password": "Forgot password?",
|
||||||
|
|
@ -153,7 +153,34 @@
|
||||||
"what_should_we_call_you": "What should we call you?",
|
"what_should_we_call_you": "What should we call you?",
|
||||||
"name_for_personalization": "We’ll use your name to personalize your learning journey.",
|
"name_for_personalization": "We’ll use your name to personalize your learning journey.",
|
||||||
"choose_your_gender": "Choose your gender?",
|
"choose_your_gender": "Choose your gender?",
|
||||||
"gender_for_personalization": "We’ll personalize your learning experience based on your gender."
|
"gender_for_personalization": "We’ll personalize your learning experience based on your gender.",
|
||||||
|
"age_range": "Which age range are you in?",
|
||||||
|
"age_for_personalization": "We’ll personalize your learning experience based on your age.",
|
||||||
|
"educational_background": "What’s your current educational level?",
|
||||||
|
"education_for_personalization": "This helps us tailor your lessons to your experience.",
|
||||||
|
"your_occupation": "What’s your occupation?",
|
||||||
|
"occupation_for_personalization": "We’ll 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": "What’s 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, let’s 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": "You’re likely speaker of",
|
||||||
|
"great_job": "Great Job! Here’s your next step to keep improving.",
|
||||||
|
"lets_start_practice": "Let's start your practice",
|
||||||
|
"welcome_abroad": "Welcome aboard",
|
||||||
|
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
||||||
|
"finish": "Finish"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ import 'package:yimaru_app/services/audio_player_service.dart';
|
||||||
import 'package:yimaru_app/services/voice_recorder_service.dart';
|
import 'package:yimaru_app/services/voice_recorder_service.dart';
|
||||||
import 'package:yimaru_app/services/in_app_update_service.dart';
|
import 'package:yimaru_app/services/in_app_update_service.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/learn_course/learn_course_view.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart';
|
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart';
|
||||||
import 'package:yimaru_app/services/vimeo_service.dart';
|
import 'package:yimaru_app/services/vimeo_service.dart';
|
||||||
import 'package:yimaru_app/services/url_launcher_service.dart';
|
import 'package:yimaru_app/services/url_launcher_service.dart';
|
||||||
|
|
@ -57,6 +56,8 @@ import 'package:yimaru_app/ui/views/course_unit/course_unit_view.dart';
|
||||||
import 'package:yimaru_app/services/localization_service.dart';
|
import 'package:yimaru_app/services/localization_service.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/landing_view.dart';
|
import 'package:yimaru_app/ui/views/landing/landing_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
||||||
|
import 'package:yimaru_app/services/onboarding_service.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart';
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
||||||
@StackedApp(
|
@StackedApp(
|
||||||
|
|
@ -88,7 +89,6 @@ import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
||||||
MaterialRoute(page: DuolingoView),
|
MaterialRoute(page: DuolingoView),
|
||||||
MaterialRoute(page: CourseView),
|
MaterialRoute(page: CourseView),
|
||||||
MaterialRoute(page: LearnProgramView),
|
MaterialRoute(page: LearnProgramView),
|
||||||
MaterialRoute(page: LearnCourseView),
|
|
||||||
MaterialRoute(page: AssessmentView),
|
MaterialRoute(page: AssessmentView),
|
||||||
MaterialRoute(page: LearnSubscriptionView),
|
MaterialRoute(page: LearnSubscriptionView),
|
||||||
MaterialRoute(page: ArifPayView),
|
MaterialRoute(page: ArifPayView),
|
||||||
|
|
@ -123,6 +123,7 @@ import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
||||||
LazySingleton(classType: PhoneCallerService),
|
LazySingleton(classType: PhoneCallerService),
|
||||||
LazySingleton(classType: LearnService),
|
LazySingleton(classType: LearnService),
|
||||||
LazySingleton(classType: LocalizationService),
|
LazySingleton(classType: LocalizationService),
|
||||||
|
LazySingleton(classType: OnboardingService),
|
||||||
// @stacked-service
|
// @stacked-service
|
||||||
],
|
],
|
||||||
bottomsheets: [
|
bottomsheets: [
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import '../services/in_app_update_service.dart';
|
||||||
import '../services/learn_service.dart';
|
import '../services/learn_service.dart';
|
||||||
import '../services/localization_service.dart';
|
import '../services/localization_service.dart';
|
||||||
import '../services/notification_service.dart';
|
import '../services/notification_service.dart';
|
||||||
|
import '../services/onboarding_service.dart';
|
||||||
import '../services/permission_handler_service.dart';
|
import '../services/permission_handler_service.dart';
|
||||||
import '../services/phone_caller_service.dart';
|
import '../services/phone_caller_service.dart';
|
||||||
import '../services/secure_storage_service.dart';
|
import '../services/secure_storage_service.dart';
|
||||||
|
|
@ -65,4 +66,5 @@ Future<void> setupLocator(
|
||||||
locator.registerLazySingleton(() => PhoneCallerService());
|
locator.registerLazySingleton(() => PhoneCallerService());
|
||||||
locator.registerLazySingleton(() => LearnService());
|
locator.registerLazySingleton(() => LearnService());
|
||||||
locator.registerLazySingleton(() => LocalizationService());
|
locator.registerLazySingleton(() => LocalizationService());
|
||||||
|
locator.registerLazySingleton(() => OnboardingService());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'package:flutter/material.dart' as _i37;
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/material.dart' as _i37;
|
||||||
import 'package:stacked/stacked.dart' as _i1;
|
import 'package:stacked/stacked.dart' as _i1;
|
||||||
import 'package:stacked_services/stacked_services.dart' as _i46;
|
import 'package:stacked_services/stacked_services.dart' as _i46;
|
||||||
import 'package:yimaru_app/models/course.dart' as _i42;
|
import 'package:yimaru_app/models/course.dart' as _i42;
|
||||||
|
|
@ -20,30 +20,30 @@ import 'package:yimaru_app/models/learn_module.dart' as _i39;
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart' as _i41;
|
import 'package:yimaru_app/ui/common/enmus.dart' as _i41;
|
||||||
import 'package:yimaru_app/ui/views/account_privacy/account_privacy_view.dart'
|
import 'package:yimaru_app/ui/views/account_privacy/account_privacy_view.dart'
|
||||||
as _i9;
|
as _i9;
|
||||||
import 'package:yimaru_app/ui/views/arif_pay/arif_pay_view.dart' as _i32;
|
import 'package:yimaru_app/ui/views/arif_pay/arif_pay_view.dart' as _i31;
|
||||||
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i30;
|
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i29;
|
||||||
import 'package:yimaru_app/ui/views/call_support/call_support_view.dart'
|
import 'package:yimaru_app/ui/views/call_support/call_support_view.dart'
|
||||||
as _i12;
|
as _i12;
|
||||||
import 'package:yimaru_app/ui/views/course/course_view.dart' as _i27;
|
import 'package:yimaru_app/ui/views/course/course_view.dart' as _i27;
|
||||||
import 'package:yimaru_app/ui/views/course_catalog/course_catalog_view.dart'
|
import 'package:yimaru_app/ui/views/course_catalog/course_catalog_view.dart'
|
||||||
as _i33;
|
as _i32;
|
||||||
import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart'
|
import 'package:yimaru_app/ui/views/course_lesson_detail/course_lesson_detail_view.dart'
|
||||||
as _i25;
|
as _i25;
|
||||||
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart'
|
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart'
|
||||||
as _i36;
|
as _i35;
|
||||||
import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart'
|
import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart'
|
||||||
as _i23;
|
as _i23;
|
||||||
import 'package:yimaru_app/ui/views/course_unit/course_unit_view.dart' as _i34;
|
import 'package:yimaru_app/ui/views/course_unit/course_unit_view.dart' as _i33;
|
||||||
import 'package:yimaru_app/ui/views/downloads/downloads_view.dart' as _i7;
|
import 'package:yimaru_app/ui/views/downloads/downloads_view.dart' as _i7;
|
||||||
import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart' as _i26;
|
import 'package:yimaru_app/ui/views/duolingo/duolingo_view.dart' as _i26;
|
||||||
import 'package:yimaru_app/ui/views/failure/failure_view.dart' as _i24;
|
import 'package:yimaru_app/ui/views/failure/failure_view.dart' as _i24;
|
||||||
import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart'
|
import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart'
|
||||||
as _i20;
|
as _i20;
|
||||||
import 'package:yimaru_app/ui/views/home/home_view.dart' as _i2;
|
import 'package:yimaru_app/ui/views/home/home_view.dart' as _i2;
|
||||||
import 'package:yimaru_app/ui/views/landing/landing_view.dart' as _i35;
|
import 'package:yimaru_app/ui/views/landing/landing_view.dart' as _i34;
|
||||||
import 'package:yimaru_app/ui/views/language/language_view.dart' as _i13;
|
import 'package:yimaru_app/ui/views/language/language_view.dart' as _i13;
|
||||||
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart'
|
import 'package:yimaru_app/ui/views/learn_course/learn_course_view.dart'
|
||||||
as _i29;
|
as _i36;
|
||||||
import 'package:yimaru_app/ui/views/learn_lesson/learn_lesson_view.dart'
|
import 'package:yimaru_app/ui/views/learn_lesson/learn_lesson_view.dart'
|
||||||
as _i19;
|
as _i19;
|
||||||
import 'package:yimaru_app/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart'
|
import 'package:yimaru_app/ui/views/learn_lesson_detail/learn_lesson_detail_view.dart'
|
||||||
|
|
@ -55,7 +55,7 @@ import 'package:yimaru_app/ui/views/learn_practice/learn_practice_view.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'
|
||||||
as _i28;
|
as _i28;
|
||||||
import 'package:yimaru_app/ui/views/learn_subscription/learn_subscription_view.dart'
|
import 'package:yimaru_app/ui/views/learn_subscription/learn_subscription_view.dart'
|
||||||
as _i31;
|
as _i30;
|
||||||
import 'package:yimaru_app/ui/views/login/login_view.dart' as _i17;
|
import 'package:yimaru_app/ui/views/login/login_view.dart' as _i17;
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.dart' as _i3;
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.dart' as _i3;
|
||||||
import 'package:yimaru_app/ui/views/privacy_policy/privacy_policy_view.dart'
|
import 'package:yimaru_app/ui/views/privacy_policy/privacy_policy_view.dart'
|
||||||
|
|
@ -127,8 +127,6 @@ class Routes {
|
||||||
|
|
||||||
static const learnProgramView = '/learn-program-view';
|
static const learnProgramView = '/learn-program-view';
|
||||||
|
|
||||||
static const learnCourseView = '/learn-course-view';
|
|
||||||
|
|
||||||
static const assessmentView = '/assessment-view';
|
static const assessmentView = '/assessment-view';
|
||||||
|
|
||||||
static const learnSubscriptionView = '/learn-subscription-view';
|
static const learnSubscriptionView = '/learn-subscription-view';
|
||||||
|
|
@ -143,6 +141,7 @@ class Routes {
|
||||||
|
|
||||||
static const courseModuleView = '/course-module-view';
|
static const courseModuleView = '/course-module-view';
|
||||||
|
|
||||||
|
static const learnCourseView = '/learn-course-view';
|
||||||
|
|
||||||
static const all = <String>{
|
static const all = <String>{
|
||||||
homeView,
|
homeView,
|
||||||
|
|
@ -172,7 +171,6 @@ class Routes {
|
||||||
duolingoView,
|
duolingoView,
|
||||||
courseView,
|
courseView,
|
||||||
learnProgramView,
|
learnProgramView,
|
||||||
learnCourseView,
|
|
||||||
assessmentView,
|
assessmentView,
|
||||||
learnSubscriptionView,
|
learnSubscriptionView,
|
||||||
arifPayView,
|
arifPayView,
|
||||||
|
|
@ -180,6 +178,7 @@ class Routes {
|
||||||
courseUnitView,
|
courseUnitView,
|
||||||
landingView,
|
landingView,
|
||||||
courseModuleView,
|
courseModuleView,
|
||||||
|
learnCourseView,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,41 +292,37 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
Routes.learnProgramView,
|
Routes.learnProgramView,
|
||||||
page: _i28.LearnProgramView,
|
page: _i28.LearnProgramView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
|
||||||
Routes.learnCourseView,
|
|
||||||
page: _i29.LearnCourseView,
|
|
||||||
),
|
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.assessmentView,
|
Routes.assessmentView,
|
||||||
page: _i30.AssessmentView,
|
page: _i29.AssessmentView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.learnSubscriptionView,
|
Routes.learnSubscriptionView,
|
||||||
page: _i31.LearnSubscriptionView,
|
page: _i30.LearnSubscriptionView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.arifPayView,
|
Routes.arifPayView,
|
||||||
page: _i32.ArifPayView,
|
page: _i31.ArifPayView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.courseCatalogView,
|
Routes.courseCatalogView,
|
||||||
page: _i33.CourseCatalogView,
|
page: _i32.CourseCatalogView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.courseUnitView,
|
Routes.courseUnitView,
|
||||||
page: _i34.CourseUnitView,
|
page: _i33.CourseUnitView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.landingView,
|
Routes.landingView,
|
||||||
page: _i35.LandingView,
|
page: _i34.LandingView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.courseModuleView,
|
Routes.courseModuleView,
|
||||||
page: _i36.CourseModuleView,
|
page: _i35.CourseModuleView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
_i1.RouteDef(
|
||||||
Routes.learnCourseView,
|
Routes.learnCourseView,
|
||||||
page: _i29.LearnCourseView,
|
page: _i36.LearnCourseView,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -577,72 +572,72 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i29.LearnCourseView: (data) {
|
_i29.AssessmentView: (data) {
|
||||||
final args = data.getArgs<LearnCourseViewArguments>(nullOk: false);
|
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
|
||||||
builder: (context) => _i29.LearnCourseView(key: args.key, id: args.id),
|
|
||||||
settings: data,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_i30.AssessmentView: (data) {
|
|
||||||
final args = data.getArgs<AssessmentViewArguments>(nullOk: false);
|
final args = data.getArgs<AssessmentViewArguments>(nullOk: false);
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
_i30.AssessmentView(key: args.key, data: args.data),
|
_i29.AssessmentView(key: args.key, data: args.data),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i31.LearnSubscriptionView: (data) {
|
_i30.LearnSubscriptionView: (data) {
|
||||||
final args = data.getArgs<LearnSubscriptionViewArguments>(
|
final args = data.getArgs<LearnSubscriptionViewArguments>(
|
||||||
orElse: () => const LearnSubscriptionViewArguments(),
|
orElse: () => const LearnSubscriptionViewArguments(),
|
||||||
);
|
);
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => _i31.LearnSubscriptionView(key: args.key),
|
builder: (context) => _i30.LearnSubscriptionView(key: args.key),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i32.ArifPayView: (data) {
|
_i31.ArifPayView: (data) {
|
||||||
final args = data.getArgs<ArifPayViewArguments>(nullOk: false);
|
final args = data.getArgs<ArifPayViewArguments>(nullOk: false);
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
_i32.ArifPayView(key: args.key, phone: args.phone),
|
_i31.ArifPayView(key: args.key, phone: args.phone),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i33.CourseCatalogView: (data) {
|
_i32.CourseCatalogView: (data) {
|
||||||
final args = data.getArgs<CourseCatalogViewArguments>(
|
final args = data.getArgs<CourseCatalogViewArguments>(
|
||||||
orElse: () => const CourseCatalogViewArguments(),
|
orElse: () => const CourseCatalogViewArguments(),
|
||||||
);
|
);
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => _i33.CourseCatalogView(key: args.key),
|
builder: (context) => _i32.CourseCatalogView(key: args.key),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i34.CourseUnitView: (data) {
|
_i33.CourseUnitView: (data) {
|
||||||
final args = data.getArgs<CourseUnitViewArguments>(nullOk: false);
|
final args = data.getArgs<CourseUnitViewArguments>(nullOk: false);
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
_i34.CourseUnitView(key: args.key, catalog: args.catalog),
|
_i33.CourseUnitView(key: args.key, catalog: args.catalog),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i35.LandingView: (data) {
|
_i34.LandingView: (data) {
|
||||||
final args = data.getArgs<LandingViewArguments>(
|
final args = data.getArgs<LandingViewArguments>(
|
||||||
orElse: () => const LandingViewArguments(),
|
orElse: () => const LandingViewArguments(),
|
||||||
);
|
);
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => _i35.LandingView(key: args.key),
|
builder: (context) => _i34.LandingView(key: args.key),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i36.CourseModuleView: (data) {
|
_i35.CourseModuleView: (data) {
|
||||||
final args = data.getArgs<CourseModuleViewArguments>(nullOk: false);
|
final args = data.getArgs<CourseModuleViewArguments>(nullOk: false);
|
||||||
return _i37.MaterialPageRoute<dynamic>(
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => _i36.CourseModuleView(
|
builder: (context) => _i35.CourseModuleView(
|
||||||
key: args.key, module: args.module, catalog: args.catalog),
|
key: args.key, module: args.module, catalog: args.catalog),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
_i36.LearnCourseView: (data) {
|
||||||
|
final args = data.getArgs<LearnCourseViewArguments>(nullOk: false);
|
||||||
|
return _i37.MaterialPageRoute<dynamic>(
|
||||||
|
builder: (context) => _i36.LearnCourseView(key: args.key, id: args.id),
|
||||||
|
settings: data,
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -1328,33 +1323,6 @@ class LearnProgramViewArguments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LearnCourseViewArguments {
|
|
||||||
const LearnCourseViewArguments({
|
|
||||||
this.key,
|
|
||||||
required this.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
final _i37.Key? key;
|
|
||||||
|
|
||||||
final int id;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return '{"key": "$key", "id": "$id"}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(covariant LearnCourseViewArguments other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
return other.key == key && other.id == id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
return key.hashCode ^ id.hashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AssessmentViewArguments {
|
class AssessmentViewArguments {
|
||||||
const AssessmentViewArguments({
|
const AssessmentViewArguments({
|
||||||
this.key,
|
this.key,
|
||||||
|
|
@ -1534,6 +1502,33 @@ class CourseModuleViewArguments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LearnCourseViewArguments {
|
||||||
|
const LearnCourseViewArguments({
|
||||||
|
this.key,
|
||||||
|
required this.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
final _i37.Key? key;
|
||||||
|
|
||||||
|
final int id;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '{"key": "$key", "id": "$id"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant LearnCourseViewArguments other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return other.key == key && other.id == id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return key.hashCode ^ id.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension NavigatorStateExtension on _i46.NavigationService {
|
extension NavigatorStateExtension on _i46.NavigationService {
|
||||||
Future<dynamic> navigateToHomeView({
|
Future<dynamic> navigateToHomeView({
|
||||||
_i37.Key? key,
|
_i37.Key? key,
|
||||||
|
|
@ -1991,23 +1986,6 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToLearnCourseView({
|
|
||||||
_i37.Key? key,
|
|
||||||
required int id,
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
}) async {
|
|
||||||
return navigateTo<dynamic>(Routes.learnCourseView,
|
|
||||||
arguments: LearnCourseViewArguments(key: key, id: id),
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> navigateToAssessmentView({
|
Future<dynamic> navigateToAssessmentView({
|
||||||
_i37.Key? key,
|
_i37.Key? key,
|
||||||
required Map<String, dynamic> data,
|
required Map<String, dynamic> data,
|
||||||
|
|
@ -2126,7 +2104,22 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<dynamic> navigateToLearnCourseView({
|
||||||
|
_i37.Key? key,
|
||||||
|
required int id,
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
}) async {
|
||||||
|
return navigateTo<dynamic>(Routes.learnCourseView,
|
||||||
|
arguments: LearnCourseViewArguments(key: key, id: id),
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithHomeView({
|
Future<dynamic> replaceWithHomeView({
|
||||||
_i37.Key? key,
|
_i37.Key? key,
|
||||||
|
|
@ -2584,23 +2577,6 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithLearnCourseView({
|
|
||||||
_i37.Key? key,
|
|
||||||
required int id,
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
}) async {
|
|
||||||
return replaceWith<dynamic>(Routes.learnCourseView,
|
|
||||||
arguments: LearnCourseViewArguments(key: key, id: id),
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> replaceWithAssessmentView({
|
Future<dynamic> replaceWithAssessmentView({
|
||||||
_i37.Key? key,
|
_i37.Key? key,
|
||||||
required Map<String, dynamic> data,
|
required Map<String, dynamic> data,
|
||||||
|
|
@ -2719,5 +2695,20 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<dynamic> replaceWithLearnCourseView({
|
||||||
|
_i37.Key? key,
|
||||||
|
required int id,
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
}) async {
|
||||||
|
return replaceWith<dynamic>(Routes.learnCourseView,
|
||||||
|
arguments: LearnCourseViewArguments(key: key, id: id),
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ Future<void> main() async {
|
||||||
EasyLocalization(
|
EasyLocalization(
|
||||||
supportedLocales: const [
|
supportedLocales: const [
|
||||||
Locale('en'),
|
Locale('en'),
|
||||||
Locale('አማ'),
|
Locale(
|
||||||
|
'am',
|
||||||
|
),
|
||||||
],
|
],
|
||||||
path: 'assets/translations',
|
path: 'assets/translations',
|
||||||
startLocale: const Locale('en'),
|
startLocale: const Locale('en'),
|
||||||
|
|
|
||||||
19
lib/models/app_update.dart
Normal file
19
lib/models/app_update.dart
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'app_update.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class AppUpdate {
|
||||||
|
@JsonKey(name: 'force_update')
|
||||||
|
final bool? forceUpdate;
|
||||||
|
|
||||||
|
@JsonKey(name: 'update_available')
|
||||||
|
final bool? updateAvailable;
|
||||||
|
|
||||||
|
const AppUpdate({this.forceUpdate, this.updateAvailable});
|
||||||
|
|
||||||
|
factory AppUpdate.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$AppUpdateFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$AppUpdateToJson(this);
|
||||||
|
}
|
||||||
17
lib/models/app_update.g.dart
Normal file
17
lib/models/app_update.g.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'app_update.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
AppUpdate _$AppUpdateFromJson(Map<String, dynamic> json) => AppUpdate(
|
||||||
|
forceUpdate: json['force_update'] as bool?,
|
||||||
|
updateAvailable: json['update_available'] as bool?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$AppUpdateToJson(AppUpdate instance) => <String, dynamic>{
|
||||||
|
'force_update': instance.forceUpdate,
|
||||||
|
'update_available': instance.updateAvailable,
|
||||||
|
};
|
||||||
17
lib/models/field_option.dart
Normal file
17
lib/models/field_option.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
part 'field_option.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class FieldOption {
|
||||||
|
final String? code;
|
||||||
|
|
||||||
|
final String? label;
|
||||||
|
|
||||||
|
const FieldOption({this.code, this.label});
|
||||||
|
|
||||||
|
factory FieldOption.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$FieldOptionFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$FieldOptionToJson(this);
|
||||||
|
}
|
||||||
18
lib/models/field_option.g.dart
Normal file
18
lib/models/field_option.g.dart
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'field_option.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
FieldOption _$FieldOptionFromJson(Map<String, dynamic> json) => FieldOption(
|
||||||
|
code: json['code'] as String?,
|
||||||
|
label: json['label'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$FieldOptionToJson(FieldOption instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'code': instance.code,
|
||||||
|
'label': instance.label,
|
||||||
|
};
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:yimaru_app/models/app_update.dart';
|
||||||
import 'package:yimaru_app/models/learn_lesson.dart';
|
import 'package:yimaru_app/models/learn_lesson.dart';
|
||||||
import 'package:yimaru_app/models/learn_practice.dart';
|
import 'package:yimaru_app/models/learn_practice.dart';
|
||||||
import 'package:yimaru_app/models/learn_program.dart';
|
import 'package:yimaru_app/models/learn_program.dart';
|
||||||
|
|
@ -12,6 +13,7 @@ import 'package:yimaru_app/ui/common/app_constants.dart';
|
||||||
import '../app/app.locator.dart';
|
import '../app/app.locator.dart';
|
||||||
import '../models/course_module.dart';
|
import '../models/course_module.dart';
|
||||||
import '../models/course_unit.dart';
|
import '../models/course_unit.dart';
|
||||||
|
import '../models/field_option.dart';
|
||||||
import '../models/learn_course.dart';
|
import '../models/learn_course.dart';
|
||||||
import '../models/learn_module.dart';
|
import '../models/learn_module.dart';
|
||||||
import '../models/learn_question.dart';
|
import '../models/learn_question.dart';
|
||||||
|
|
@ -379,6 +381,222 @@ class ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get educational levels
|
||||||
|
Future<List<FieldOption>> getEducationalLevels() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=education_level');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['education_level'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ethiopia regions
|
||||||
|
Future<List<FieldOption>> getEthiopiaRegions() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=ethiopia_regions');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['ethiopia_regions'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get language challenges
|
||||||
|
Future<List<FieldOption>> getLanguageChallenges() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=language_challange');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['language_challange'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get occupations
|
||||||
|
Future<List<FieldOption>> getOccupations() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=occupation');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['occupation'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get age group
|
||||||
|
Future<List<FieldOption>> getAgeGroups() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=age_group');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['age_group'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get countries
|
||||||
|
Future<List<FieldOption>> getCountries() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=country');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['country'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get topics
|
||||||
|
Future<List<FieldOption>> getTopics() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=favourite_topic');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['favourite_topic'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get topics
|
||||||
|
Future<List<FieldOption>> getLanguageGoals() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=language_goal');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['language_goal'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get learning goal
|
||||||
|
Future<List<FieldOption>> getLearningGoals() async {
|
||||||
|
try {
|
||||||
|
List<FieldOption> levels = [];
|
||||||
|
|
||||||
|
final Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kFieldOptions?field_key=learning_goal');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data']['learning_goal'] as List;
|
||||||
|
levels = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return FieldOption.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return levels;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get assessment questions
|
// Get assessment questions
|
||||||
Future<List<AssessmentQuestion>> getAssessmentQuestions(int id) async {
|
Future<List<AssessmentQuestion>> getAssessmentQuestions(int id) async {
|
||||||
try {
|
try {
|
||||||
|
|
@ -795,4 +1013,29 @@ class ApiService {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check update
|
||||||
|
Future<Map<String, dynamic>> checkUpdate(Map<String, dynamic> data) async {
|
||||||
|
try {
|
||||||
|
Response response = await _service.dio.get(
|
||||||
|
'$kBaseUrl/$kApiUrl/$kApiVersionUrl/$kAppUrl/$kApiVersionUrl/$kCheckUrl',
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.success,
|
||||||
|
'data': AppUpdate.fromJson(response.data['data']),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} on DioException {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,51 @@
|
||||||
import 'package:battery_plus/battery_plus.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:in_app_update/in_app_update.dart';
|
import 'package:in_app_update/in_app_update.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:storage_info/storage_info.dart';
|
|
||||||
import 'package:yimaru_app/app/app.locator.dart';
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
|
import 'package:yimaru_app/models/app_update.dart';
|
||||||
|
import 'package:yimaru_app/services/status_checker_service.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
|
|
||||||
import '../ui/common/ui_helpers.dart';
|
import '../ui/common/ui_helpers.dart';
|
||||||
|
import 'api_service.dart';
|
||||||
|
|
||||||
class InAppUpdateService {
|
class InAppUpdateService {
|
||||||
|
// Dependency Injection
|
||||||
|
final _apiService = locator<ApiService>();
|
||||||
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
Future<int> getBatteryLevel() async {
|
final _statusCheckerService = locator<StatusCheckerService>();
|
||||||
final battery = Battery();
|
|
||||||
final batteryLevel = await battery.batteryLevel;
|
|
||||||
return batteryLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> getAvailableStorage() async {
|
|
||||||
try {
|
|
||||||
final availableStorage =
|
|
||||||
await StorageInfo().getStorageFreeSpace(SpaceUnit.Bytes);
|
|
||||||
return availableStorage.toInt(); // Convert GB to bytes
|
|
||||||
} catch (e) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> checkForUpdate() async {
|
Future<void> checkForUpdate() async {
|
||||||
const requiredStorage = 500 * 1024 * 1024;
|
|
||||||
|
|
||||||
final batteryLevel =
|
|
||||||
await getBatteryLevel(); // Implement getBatteryLevel function
|
|
||||||
final int storageAvailable =
|
|
||||||
await getAvailableStorage(); // Implement getAvailableStorage
|
|
||||||
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
|
||||||
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
|
||||||
// KewedeConst().showErrorToast(
|
|
||||||
// 'Unable to update app, please charge your phone & free up space.');
|
|
||||||
} else if (batteryLevel < 20) {
|
|
||||||
// KewedeConst()
|
|
||||||
// .showErrorToast('Unable to update app, please charge your phone.');
|
|
||||||
} else if (storageAvailable < requiredStorage) {
|
|
||||||
// KewedeConst()
|
|
||||||
// .showErrorToast('Unable to update app, please free up space.');
|
|
||||||
}
|
|
||||||
// Show user-friendly message explaining why update failed and suggesting solutions (e.g., charge device, free up space)
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
final info = await InAppUpdate.checkForUpdate();
|
final info = await InAppUpdate.checkForUpdate();
|
||||||
if (info.updateAvailability == UpdateAvailability.updateAvailable) {
|
final String version = await _statusCheckerService.getAppVersion();
|
||||||
AppUpdateResult result = await InAppUpdate.performImmediateUpdate();
|
|
||||||
if (result == AppUpdateResult.userDeniedUpdate) {
|
if (version != info.availableVersionCode.toString()) {
|
||||||
showErrorToast('An update is required to continue using this app.');
|
Map<String, dynamic> data = {
|
||||||
_navigationService.back();
|
'platform': 'ANDROID',
|
||||||
|
'version_code': info.availableVersionCode
|
||||||
|
};
|
||||||
|
Map<String, dynamic> response = await _apiService.checkUpdate(data);
|
||||||
|
|
||||||
|
if (response['status'] == ResponseStatus.success) {
|
||||||
|
AppUpdate update = response['data'] as AppUpdate;
|
||||||
|
if (update.updateAvailable ?? false) {
|
||||||
|
if (update.forceUpdate ?? false) {
|
||||||
|
AppUpdateResult result =
|
||||||
|
await InAppUpdate.performImmediateUpdate();
|
||||||
|
if (result == AppUpdateResult.userDeniedUpdate) {
|
||||||
|
showErrorToast(
|
||||||
|
'An update is required to continue using this app.');
|
||||||
|
_navigationService.back();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await InAppUpdate.startFlexibleUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... rest of your update logic ...
|
|
||||||
} on PlatformException {
|
} on PlatformException {
|
||||||
// Handle specific error code for better user experience and potentially different error messages for each issue
|
// Handle specific error code for better user experience and potentially different error messages for each issue
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class LocalizationService with ListenableServiceMixin {
|
||||||
Map<String, dynamic> get selectedLanguage => _selectedLanguage;
|
Map<String, dynamic> get selectedLanguage => _selectedLanguage;
|
||||||
|
|
||||||
final List<Map<String, dynamic>> _languages = [
|
final List<Map<String, dynamic>> _languages = [
|
||||||
{'code': 'አማ', 'language': 'አማርኛ'},
|
{'code': 'am', 'language': 'አማርኛ'},
|
||||||
{'code': 'en', 'language': 'English'},
|
{'code': 'en', 'language': 'English'},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -37,7 +37,7 @@ class LocalizationService with ListenableServiceMixin {
|
||||||
required Map<String, dynamic> title}) async {
|
required Map<String, dynamic> title}) async {
|
||||||
_selectedLanguage = title;
|
_selectedLanguage = title;
|
||||||
|
|
||||||
if (title['code'] == 'አማ') {
|
if (title['code'] == 'am') {
|
||||||
await setAmharicLanguage(context);
|
await setAmharicLanguage(context);
|
||||||
} else {
|
} else {
|
||||||
await setEnglishLanguage(context);
|
await setEnglishLanguage(context);
|
||||||
|
|
@ -50,17 +50,15 @@ class LocalizationService with ListenableServiceMixin {
|
||||||
|
|
||||||
if (language == 'en') {
|
if (language == 'en') {
|
||||||
_selectedLanguage = {'code': 'en', 'language': 'English'};
|
_selectedLanguage = {'code': 'en', 'language': 'English'};
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_selectedLanguage = {'code': 'አማ', 'language': 'አማርኛ'};
|
_selectedLanguage = {'code': 'am', 'language': 'አማርኛ'};
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
print('SELECTED LANGUAGE: $language $_selectedLanguage');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setAmharicLanguage(BuildContext context) async {
|
Future<void> setAmharicLanguage(BuildContext context) async {
|
||||||
await context.setLocale(const Locale('አማ'));
|
await context.setLocale(const Locale('am'));
|
||||||
await _secureService.setString('language', 'አማ');
|
await _secureService.setString('language', 'am');
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
104
lib/services/onboarding_service.dart
Normal file
104
lib/services/onboarding_service.dart
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
import 'package:yimaru_app/models/field_option.dart';
|
||||||
|
|
||||||
|
import '../app/app.locator.dart';
|
||||||
|
import 'api_service.dart';
|
||||||
|
|
||||||
|
class OnboardingService with ListenableServiceMixin {
|
||||||
|
// Dependency injection
|
||||||
|
final _apiService = locator<ApiService>();
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
learnService() {
|
||||||
|
listenToReactiveValues([
|
||||||
|
_topics,
|
||||||
|
_regions,
|
||||||
|
_ageGroups,
|
||||||
|
_countries,
|
||||||
|
_challenges,
|
||||||
|
_occupations,
|
||||||
|
_learningGoals,
|
||||||
|
_languageGoals,
|
||||||
|
_educationalBackgrounds
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Topics
|
||||||
|
List<FieldOption> _topics = [];
|
||||||
|
|
||||||
|
List<FieldOption> get topics => _topics;
|
||||||
|
|
||||||
|
// Regions
|
||||||
|
List<FieldOption> _regions = [];
|
||||||
|
|
||||||
|
List<FieldOption> get regions => _regions;
|
||||||
|
|
||||||
|
// Age groups
|
||||||
|
List<FieldOption> _ageGroups = [];
|
||||||
|
|
||||||
|
List<FieldOption> get ageGroups => _ageGroups;
|
||||||
|
|
||||||
|
// Countries
|
||||||
|
List<FieldOption> _countries = [];
|
||||||
|
|
||||||
|
List<FieldOption> get countries => _countries;
|
||||||
|
|
||||||
|
// Challenges
|
||||||
|
List<FieldOption> _challenges = [];
|
||||||
|
|
||||||
|
List<FieldOption> get challenges => _challenges;
|
||||||
|
|
||||||
|
// Occupations
|
||||||
|
List<FieldOption> _occupations = [];
|
||||||
|
|
||||||
|
List<FieldOption> get occupations => _occupations;
|
||||||
|
|
||||||
|
// Learning goals
|
||||||
|
List<FieldOption> _learningGoals = [];
|
||||||
|
|
||||||
|
List<FieldOption> get learningGoals => _learningGoals;
|
||||||
|
|
||||||
|
// Language goals
|
||||||
|
List<FieldOption> _languageGoals = [];
|
||||||
|
|
||||||
|
List<FieldOption> get languageGoals => _languageGoals;
|
||||||
|
|
||||||
|
// Educational backgrounds
|
||||||
|
List<FieldOption> _educationalBackgrounds = [];
|
||||||
|
|
||||||
|
List<FieldOption> get educationalBackgrounds => _educationalBackgrounds;
|
||||||
|
|
||||||
|
// Onboarding fields
|
||||||
|
Future<bool> getOnboardingFields() async {
|
||||||
|
_topics = await _apiService.getTopics();
|
||||||
|
|
||||||
|
_ageGroups = await _apiService.getAgeGroups();
|
||||||
|
|
||||||
|
_countries = await _apiService.getCountries();
|
||||||
|
|
||||||
|
_occupations = await _apiService.getOccupations();
|
||||||
|
|
||||||
|
_regions = await _apiService.getEthiopiaRegions();
|
||||||
|
|
||||||
|
_learningGoals = await _apiService.getLearningGoals();
|
||||||
|
|
||||||
|
_languageGoals = await _apiService.getLanguageGoals();
|
||||||
|
|
||||||
|
_challenges = await _apiService.getLanguageChallenges();
|
||||||
|
|
||||||
|
_educationalBackgrounds = await _apiService.getEducationalLevels();
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
if (_topics.isNotEmpty &&
|
||||||
|
_ageGroups.isNotEmpty &&
|
||||||
|
_countries.isNotEmpty &&
|
||||||
|
_occupations.isNotEmpty &&
|
||||||
|
_regions.isNotEmpty &&
|
||||||
|
_learningGoals.isNotEmpty &&
|
||||||
|
_challenges.isNotEmpty &&
|
||||||
|
_educationalBackgrounds.isNotEmpty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart';
|
import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:yimaru_app/services/secure_storage_service.dart';
|
import 'package:yimaru_app/services/secure_storage_service.dart';
|
||||||
|
|
||||||
import '../app/app.locator.dart';
|
import '../app/app.locator.dart';
|
||||||
|
|
@ -25,4 +26,16 @@ class StatusCheckerService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get app version
|
||||||
|
Future<String> getAppVersion() async {
|
||||||
|
PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
|
||||||
|
String version = packageInfo.version; // e.g. 1.0.0
|
||||||
|
String buildNumber = packageInfo.buildNumber; // version code
|
||||||
|
|
||||||
|
print("Version: $version");
|
||||||
|
print("Build Number: $buildNumber");
|
||||||
|
return buildNumber;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,14 @@
|
||||||
// Endpoints
|
// Endpoints
|
||||||
String kBaseUrl = 'https://api.yimaruacademy.com';
|
String kBaseUrl = 'https://api.yimaruacademy.com';
|
||||||
|
|
||||||
|
String kAppUrl = 'app';
|
||||||
|
|
||||||
String kApiUrl = 'api';
|
String kApiUrl = 'api';
|
||||||
|
|
||||||
String kUnitsUrl = 'units';
|
String kUnitsUrl = 'units';
|
||||||
|
|
||||||
|
String kCheckUrl = 'check';
|
||||||
|
|
||||||
String kApiVersionUrl = 'v1';
|
String kApiVersionUrl = 'v1';
|
||||||
|
|
||||||
String kLevelsUrl = 'levels';
|
String kLevelsUrl = 'levels';
|
||||||
|
|
@ -15,6 +19,8 @@ String kModulesUrl = 'modules';
|
||||||
|
|
||||||
String kLessonsUrl = 'lessons';
|
String kLessonsUrl = 'lessons';
|
||||||
|
|
||||||
|
String kVersionUrl = 'version';
|
||||||
|
|
||||||
String kProgramsUrl = 'programs';
|
String kProgramsUrl = 'programs';
|
||||||
|
|
||||||
String kRegisterUrl = 'register';
|
String kRegisterUrl = 'register';
|
||||||
|
|
@ -47,6 +53,8 @@ String kSubmodulesUrl = 'sub-modules';
|
||||||
|
|
||||||
String kSubcoursesUrl = 'sub-courses';
|
String kSubcoursesUrl = 'sub-courses';
|
||||||
|
|
||||||
|
String kFieldOptions = 'field-options';
|
||||||
|
|
||||||
String kResetPassword = 'resetPassword';
|
String kResetPassword = 'resetPassword';
|
||||||
|
|
||||||
String kQuestionSetsUrl = 'question-sets';
|
String kQuestionSetsUrl = 'question-sets';
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class CodegenLoader extends AssetLoader{
|
||||||
"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": "የይለፍ ቃል ረሱ?",
|
||||||
|
|
@ -59,14 +59,14 @@ class CodegenLoader extends AssetLoader{
|
||||||
"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": "በሂደት ላይ",
|
||||||
|
|
@ -150,7 +150,7 @@ class CodegenLoader extends AssetLoader{
|
||||||
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
"ask_you_few_actions": "ጥቂት ጥያቄዎችን እጠይቅሃለሁ፣ አንተም በተፈጥሮ መልስ ልትሰጥ ትችላለህ።",
|
||||||
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
"begin_level_practice": "የደረጃ ልምምድን ጀምር",
|
||||||
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
"lets_practice_course": "የኮርሱን ልምምድ እንለማመድ",
|
||||||
"lets_quick_practice": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
"lets_quick_review": "በዚህ ደረጃ የተማርከውን በፍጥነት እንከልስ!",
|
||||||
"speaking": "እየተናገረ ነው",
|
"speaking": "እየተናገረ ነው",
|
||||||
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
"you_have_finished_practice": "ልምምድህን አጠናቀቅህ",
|
||||||
"view_results": "ውጤቶቼን እይ",
|
"view_results": "ውጤቶቼን እይ",
|
||||||
|
|
@ -169,13 +169,42 @@ class CodegenLoader extends AssetLoader{
|
||||||
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
"what_should_we_call_you": "ምን ብለን እንጠራህ?",
|
||||||
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
"name_for_personalization": "በመማር ጉዞህ ውስጥ ለግል ለማድረግ ስምህን እንጠቀማለን።",
|
||||||
"choose_your_gender": "ጾታህን ምረጥ",
|
"choose_your_gender": "ጾታህን ምረጥ",
|
||||||
"gender_for_personalization": "በጾታህ መሰረት የመማር ተሞክሮህን እናበጅለታለን።"
|
"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": "አጠናቅቅ"
|
||||||
};
|
};
|
||||||
static const Map<String,dynamic> _en = {
|
static const Map<String,dynamic> _en = {
|
||||||
"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? Register",
|
"dont_have_account": "Don't have an account?",
|
||||||
"email": "Email",
|
"email": "Email",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"forgot_password": "Forgot password?",
|
"forgot_password": "Forgot password?",
|
||||||
|
|
@ -326,7 +355,36 @@ static const Map<String,dynamic> _en = {
|
||||||
"what_should_we_call_you": "What should we call you?",
|
"what_should_we_call_you": "What should we call you?",
|
||||||
"name_for_personalization": "We’ll use your name to personalize your learning journey.",
|
"name_for_personalization": "We’ll use your name to personalize your learning journey.",
|
||||||
"choose_your_gender": "Choose your gender?",
|
"choose_your_gender": "Choose your gender?",
|
||||||
"gender_for_personalization": "We’ll personalize your learning experience based on your gender."
|
"gender_for_personalization": "We’ll personalize your learning experience based on your gender.",
|
||||||
|
"age_range": "Which age range are you in?",
|
||||||
|
"age_for_personalization": "We’ll personalize your learning experience based on your age.",
|
||||||
|
"educational_background": "What’s your current educational level?",
|
||||||
|
"education_for_personalization": "This helps us tailor your lessons to your experience.",
|
||||||
|
"your_occupation": "What’s your occupation?",
|
||||||
|
"occupation_for_personalization": "We’ll 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": "What’s 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, let’s 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": "You’re likely speaker of",
|
||||||
|
"great_job": "Great Job! Here’s your next step to keep improving.",
|
||||||
|
"lets_start_practice": "Let's start your practice",
|
||||||
|
"welcome_abroad": "Welcome aboard",
|
||||||
|
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
||||||
|
"finish": "Finish"
|
||||||
};
|
};
|
||||||
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en};
|
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ abstract class LocaleKeys {
|
||||||
static const ask_you_few_actions = 'ask_you_few_actions';
|
static const ask_you_few_actions = 'ask_you_few_actions';
|
||||||
static const begin_level_practice = 'begin_level_practice';
|
static const begin_level_practice = 'begin_level_practice';
|
||||||
static const lets_practice_course = 'lets_practice_course';
|
static const lets_practice_course = 'lets_practice_course';
|
||||||
static const lets_quick_practice = 'lets_quick_practice';
|
static const lets_quick_review = 'lets_quick_review';
|
||||||
static const speaking = 'speaking';
|
static const speaking = 'speaking';
|
||||||
static const you_have_finished_practice = 'you_have_finished_practice';
|
static const you_have_finished_practice = 'you_have_finished_practice';
|
||||||
static const view_results = 'view_results';
|
static const view_results = 'view_results';
|
||||||
|
|
@ -156,5 +156,34 @@ abstract class LocaleKeys {
|
||||||
static const name_for_personalization = 'name_for_personalization';
|
static const name_for_personalization = 'name_for_personalization';
|
||||||
static const choose_your_gender = 'choose_your_gender';
|
static const choose_your_gender = 'choose_your_gender';
|
||||||
static const gender_for_personalization = 'gender_for_personalization';
|
static const gender_for_personalization = 'gender_for_personalization';
|
||||||
|
static const age_range = 'age_range';
|
||||||
|
static const age_for_personalization = 'age_for_personalization';
|
||||||
|
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 location = 'location';
|
||||||
|
static const select_country_region = 'select_country_region';
|
||||||
|
static const select_country = 'select_country';
|
||||||
|
static const learning_goal = 'learning_goal';
|
||||||
|
static const language_goal = 'language_goal';
|
||||||
|
static const your_goal = 'your_goal';
|
||||||
|
static const write_your_goal = 'write_your_goal';
|
||||||
|
static const challenge_you_face = 'challenge_you_face';
|
||||||
|
static const evey_one_has_strugle = 'evey_one_has_strugle';
|
||||||
|
static const write_your_challenge = 'write_your_challenge';
|
||||||
|
static const topic_interest = 'topic_interest';
|
||||||
|
static const favourite_topic = 'favourite_topic';
|
||||||
|
static const your_interest = 'your_interest';
|
||||||
|
static const want_quick_assessment = 'want_quick_assessment';
|
||||||
|
static const answer_quick_questions = 'answer_quick_questions';
|
||||||
|
static const skip = 'skip';
|
||||||
|
static const finish_level = 'finish_level';
|
||||||
|
static const likely_speaker = 'likely_speaker';
|
||||||
|
static const great_job = 'great_job';
|
||||||
|
static const lets_start_practice = 'lets_start_practice';
|
||||||
|
static const welcome_abroad = 'welcome_abroad';
|
||||||
|
static const ready_to_explore = 'ready_to_explore';
|
||||||
|
static const finish = 'finish';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ class FormValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.isEmpty) {
|
if (value.isEmpty) {
|
||||||
return LocaleKeys.required_field.tr();
|
return LocaleKeys.required_field.tr();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ class AccountPrivacyViewModel extends ReactiveViewModel {
|
||||||
final _localizationService = locator<LocalizationService>();
|
final _localizationService = locator<LocalizationService>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices => [_localizationService];
|
||||||
[ _localizationService];
|
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
Map<String, dynamic> get _selectedLanguage =>
|
Map<String, dynamic> get _selectedLanguage =>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
@ -67,17 +69,19 @@ class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'Want a quick assessment to know your English level?',
|
LocaleKeys.want_quick_assessment.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'Answer a few quick questions to help us understand your English proficiency.',
|
LocaleKeys.answer_quick_questions.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -96,9 +100,9 @@ class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
safe: false,
|
safe: false,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await _next(viewModel),
|
onTap: () async => await _next(viewModel),
|
||||||
);
|
);
|
||||||
|
|
@ -111,9 +115,9 @@ class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
Widget _buildSkipButton(AssessmentViewModel viewModel) =>
|
Widget _buildSkipButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Skip',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.skip.tr(),
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
onTap: () => viewModel.next(page: 3),
|
onTap: () => viewModel.next(page: 3),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
||||||
|
|
@ -134,8 +136,8 @@ class AssessmentQuestionsScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
text: viewModel.currentQuestionIndex ==
|
text: viewModel.currentQuestionIndex ==
|
||||||
viewModel.assessmentQuestions.length - 1
|
viewModel.assessmentQuestions.length - 1
|
||||||
? 'Finish Level'
|
? LocaleKeys.finish_level.tr()
|
||||||
: 'Continue',
|
: LocaleKeys.cont.tr(),
|
||||||
backgroundColor: viewModel.selectedAnswers
|
backgroundColor: viewModel.selectedAnswers
|
||||||
.containsKey('${viewModel.currentQuestionIndex + 1}')
|
.containsKey('${viewModel.currentQuestionIndex + 1}')
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package: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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
@ -35,8 +37,10 @@ class AssessmentResultScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
|
|
@ -75,13 +79,13 @@ class AssessmentResultScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildTitle(AssessmentViewModel viewModel) => Text(
|
Widget _buildTitle(AssessmentViewModel viewModel) => Text(
|
||||||
'You’re likely a ${viewModel.proficiencyLevel?.toUpperCase()} speaker!',
|
'${LocaleKeys.likely_speaker.tr()} ${viewModel.proficiencyLevel?.toUpperCase()}',
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPrimarySubtitle() => Text(
|
Widget _buildPrimarySubtitle() => Text(
|
||||||
'Great Job! Here’s your next step to keep improving.',
|
LocaleKeys.great_job.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -93,7 +97,7 @@ class AssessmentResultScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
'assets/icons/${viewModel.proficiencyLevel?.substring(0, 1).toLowerCase()}_${viewModel.proficiencyLevel?.substring(1).toLowerCase()}.svg');
|
'assets/icons/${viewModel.proficiencyLevel?.substring(0, 1).toLowerCase()}_${viewModel.proficiencyLevel?.substring(1).toLowerCase()}.svg');
|
||||||
|
|
||||||
Widget _buildSecondarySubtitle() => Text(
|
Widget _buildSecondarySubtitle() => Text(
|
||||||
'Let\'s start your practice',
|
LocaleKeys.lets_start_practice.tr(),
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -106,9 +110,9 @@ class AssessmentResultScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
onTap: () => viewModel.next(),
|
onTap: () => viewModel.next(),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package: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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
@ -52,8 +54,10 @@ class StartLessonScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
|
|
@ -92,7 +96,7 @@ class StartLessonScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
|
|
||||||
Widget _buildTitle(AssessmentViewModel viewModel) => Text.rich(
|
Widget _buildTitle(AssessmentViewModel viewModel) => Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Welcome aboard',
|
text: LocaleKeys.welcome_abroad.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
|
|
@ -104,7 +108,7 @@ class StartLessonScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'You’re ready to explore your personalized lessons.',
|
LocaleKeys.ready_to_explore.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -116,9 +120,9 @@ class StartLessonScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Finish',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.finish.tr(),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await _start(viewModel),
|
onTap: () async => await _start(viewModel),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
||||||
const CircularIcon(icon: Icons.call, size: 50, color: kcPrimaryColor);
|
const CircularIcon(icon: Icons.call, size: 50, color: kcPrimaryColor);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
LocaleKeys.call_our_support.tr(),
|
LocaleKeys.call_our_support.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -116,7 +116,7 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
||||||
leadingIcon: Icons.call,
|
leadingIcon: Icons.call,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
text:LocaleKeys.tap_to_call.tr(),
|
text: LocaleKeys.tap_to_call.tr(),
|
||||||
onTap: () async => await viewModel.callSupport(),
|
onTap: () async => await viewModel.callSupport(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,10 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _inAppPop(viewModel),
|
onPop: () => _inAppPop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody(
|
||||||
|
|
|
||||||
|
|
@ -96,8 +96,10 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _inAppPop(viewModel),
|
onPop: () => _inAppPop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(ForgetPasswordViewModel viewModel) =>
|
Widget _buildExpandedBody(ForgetPasswordViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ 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 '../../widgets/coming_soon.dart';
|
import '../../widgets/coming_soon.dart';
|
||||||
import '../course/course_view.dart';
|
|
||||||
import 'home_viewmodel.dart';
|
import 'home_viewmodel.dart';
|
||||||
|
|
||||||
class HomeView extends StackedView<HomeViewModel> {
|
class HomeView extends StackedView<HomeViewModel> {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_carousel_widget/flutter_carousel_widget.dart';
|
import 'package:flutter_carousel_widget/flutter_carousel_widget.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/views/landing/screens/first_landing_screen.dart';
|
import 'package:yimaru_app/ui/views/landing/screens/first_landing_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/screens/fourth_landing_screen.dart';
|
import 'package:yimaru_app/ui/views/landing/screens/fourth_landing_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/landing/screens/second_landing_screen.dart';
|
import 'package:yimaru_app/ui/views/landing/screens/second_landing_screen.dart';
|
||||||
|
|
@ -23,19 +24,21 @@ class LandingView extends StackedView<LandingViewModel> {
|
||||||
LandingViewModel viewModel,
|
LandingViewModel viewModel,
|
||||||
Widget? child,
|
Widget? child,
|
||||||
) =>
|
) =>
|
||||||
_buildLandingScreens(viewModel);
|
_buildLandingScreensWrapper(viewModel);
|
||||||
|
|
||||||
|
Widget _buildLandingScreensWrapper(LandingViewModel viewModel) => Scaffold(
|
||||||
|
backgroundColor: kcPrimaryColor,
|
||||||
|
body: _buildLandingScreens(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildLandingScreens(LandingViewModel viewModel) => FlutterCarousel(
|
Widget _buildLandingScreens(LandingViewModel viewModel) => FlutterCarousel(
|
||||||
options: FlutterCarouselOptions(
|
options: FlutterCarouselOptions(
|
||||||
autoPlay: true,
|
autoPlay: true,
|
||||||
viewportFraction: 1,
|
viewportFraction: 1,
|
||||||
showIndicator: true,
|
|
||||||
indicatorMargin: 40,
|
indicatorMargin: 40,
|
||||||
|
showIndicator: false,
|
||||||
height: double.maxFinite,
|
height: double.maxFinite,
|
||||||
slideIndicator: CircularSlideIndicator(
|
controller: viewModel.controller,
|
||||||
slideIndicatorOptions:
|
|
||||||
const SlideIndicatorOptions(indicatorRadius: 2.5),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
items: _buildScreens(),
|
items: _buildScreens(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:flutter_carousel_widget/flutter_carousel_widget.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';
|
||||||
|
|
||||||
|
|
@ -11,6 +12,16 @@ class LandingViewModel extends BaseViewModel {
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
|
// Controller
|
||||||
|
final FlutterCarouselController _controller = FlutterCarouselController();
|
||||||
|
|
||||||
|
FlutterCarouselController get controller => _controller;
|
||||||
|
|
||||||
|
// In-app navigation
|
||||||
|
void next() {
|
||||||
|
_controller.nextPage();
|
||||||
|
}
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
Future<void> navigateToLogin() async =>
|
Future<void> navigateToLogin() async =>
|
||||||
await _navigationService.replaceWithLoginView();
|
await _navigationService.replaceWithLoginView();
|
||||||
|
|
@ -18,6 +29,7 @@ class LandingViewModel extends BaseViewModel {
|
||||||
// Remote api call
|
// Remote api call
|
||||||
|
|
||||||
// First time install
|
// First time install
|
||||||
|
|
||||||
Future<void> setFirstTimeInstall() async {
|
Future<void> setFirstTimeInstall() async {
|
||||||
await runBusyFuture(_setFirstTimeInstall());
|
await runBusyFuture(_setFirstTimeInstall());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,10 @@ class FirstLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
|
text: 'Next',
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
text: 'Get Started',
|
onTap: viewModel.next,
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await viewModel.setFirstTimeInstall(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,10 +127,10 @@ class SecondLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
|
text: 'Next',
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
text: 'Get Started',
|
onTap: viewModel.next,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await viewModel.setFirstTimeInstall(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -122,15 +122,15 @@ class ThirdLandingScreen extends ViewModelWidget<LandingViewModel> {
|
||||||
viewModel.isBusy ? _buildIndicator() : _buildContinueButton(viewModel);
|
viewModel.isBusy ? _buildIndicator() : _buildContinueButton(viewModel);
|
||||||
|
|
||||||
Widget _buildIndicator() =>
|
Widget _buildIndicator() =>
|
||||||
const CustomCircularProgressIndicator(color: kcWhite);
|
const CustomCircularProgressIndicator(color: kcPrimaryColor);
|
||||||
|
|
||||||
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
Widget _buildContinueButton(LandingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
|
text: 'Next',
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
text: 'Get Started',
|
onTap: viewModel.next,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await viewModel.setFirstTimeInstall(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,16 +108,16 @@ class LanguageView extends StackedView<LanguageViewModel> {
|
||||||
Widget _buildAppbar(LanguageViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(LanguageViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
title:LocaleKeys.language_preference.tr() ,
|
title: LocaleKeys.language_preference.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
LocaleKeys.choose_your_language.tr(),
|
LocaleKeys.choose_your_language.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
LocaleKeys.switch_language_anytime.tr() ,
|
LocaleKeys.switch_language_anytime.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
||||||
course: viewModel.courses[index],
|
course: viewModel.courses[index],
|
||||||
onViewTap: () async =>
|
onViewTap: () async =>
|
||||||
await viewModel.navigateToLearnModule(viewModel.courses[index]),
|
await viewModel.navigateToLearnModule(viewModel.courses[index]),
|
||||||
|
onLockTap: () async => await viewModel.navigateToLearnSubscription(),
|
||||||
onPracticeTap: () async => await viewModel.navigateToLearnPractice(
|
onPracticeTap: () async => await viewModel.navigateToLearnPractice(
|
||||||
id: viewModel.courses[index].id ?? 0,
|
id: viewModel.courses[index].id ?? 0,
|
||||||
level: viewModel.courses[index].name ?? ''),
|
level: viewModel.courses[index].name ?? ''),
|
||||||
|
|
@ -99,11 +100,13 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
||||||
Widget _buildTile({
|
Widget _buildTile({
|
||||||
required LearnCourse course,
|
required LearnCourse course,
|
||||||
required GestureTapCallback onViewTap,
|
required GestureTapCallback onViewTap,
|
||||||
|
required GestureTapCallback onLockTap,
|
||||||
required GestureTapCallback onPracticeTap,
|
required GestureTapCallback onPracticeTap,
|
||||||
}) =>
|
}) =>
|
||||||
LearnCourseTile(
|
LearnCourseTile(
|
||||||
course: course,
|
course: course,
|
||||||
onViewTap: onViewTap,
|
onViewTap: onViewTap,
|
||||||
|
onLockTap: onLockTap,
|
||||||
onPracticeTap: onPracticeTap,
|
onPracticeTap: onPracticeTap,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,9 @@ class LearnCourseViewModel extends ReactiveViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
|
Future<void> navigateToLearnSubscription() async =>
|
||||||
|
await _navigationService.navigateToLearnSubscriptionView();
|
||||||
|
|
||||||
Future<void> navigateToLearnModule(LearnCourse course) async =>
|
Future<void> navigateToLearnModule(LearnCourse course) async =>
|
||||||
_navigationService.navigateToLearnModuleView(course: course);
|
_navigationService.navigateToLearnModuleView(course: course);
|
||||||
|
|
||||||
|
|
@ -39,7 +42,7 @@ class LearnCourseViewModel extends ReactiveViewModel {
|
||||||
level: level,
|
level: level,
|
||||||
practice: LearnPractices.course,
|
practice: LearnPractices.course,
|
||||||
label: LocaleKeys.begin_level_practice.tr(),
|
label: LocaleKeys.begin_level_practice.tr(),
|
||||||
subtitle: LocaleKeys.lets_quick_practice.tr(),
|
subtitle: LocaleKeys.lets_quick_review.tr(),
|
||||||
title: '${LocaleKeys.lets_practice_course.tr()} $level',
|
title: '${LocaleKeys.lets_practice_course.tr()} $level',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
Widget _buildMotivationCard() => const MotivationCard();
|
Widget _buildMotivationCard() => const MotivationCard();
|
||||||
|
|
||||||
Widget _buildHeader() => Text(
|
Widget _buildHeader() => Text(
|
||||||
LocaleKeys.lessons_in_module.tr(),
|
LocaleKeys.lessons_in_module.tr(),
|
||||||
style: style18DG700,
|
style: style18DG700,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,9 @@ class LearnLessonViewModel extends ReactiveViewModel {
|
||||||
await _navigationService.navigateToLearnPracticeView(
|
await _navigationService.navigateToLearnPracticeView(
|
||||||
id: id,
|
id: id,
|
||||||
practice: LearnPractices.lesson,
|
practice: LearnPractices.lesson,
|
||||||
label:LocaleKeys.start_practice.tr(),
|
label: LocaleKeys.start_practice.tr(),
|
||||||
title: LocaleKeys.lets_practice_module.tr(),
|
title: LocaleKeys.lets_practice_module.tr(),
|
||||||
subtitle:LocaleKeys.ask_you_few_actions.tr(),
|
subtitle: LocaleKeys.ask_you_few_actions.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<void> navigateToLearnLessonDetail(
|
Future<void> navigateToLearnLessonDetail(
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
text:LocaleKeys.take_practice.tr() ,
|
text: LocaleKeys.take_practice.tr(),
|
||||||
onTap: () async => await _navigate(viewModel),
|
onTap: () async => await _navigate(viewModel),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
LocaleKeys.your_current_level.tr(),
|
LocaleKeys.your_current_level.tr(),
|
||||||
style: style14P400,
|
style: style14P400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ class LearnModuleViewModel extends ReactiveViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<void> navigateToLearnLesson(LearnModule module) async =>
|
Future<void> navigateToLearnLesson(LearnModule module) async =>
|
||||||
await _navigationService.navigateToLearnLessonView(module: module);
|
await _navigationService.navigateToLearnLessonView(module: module);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,8 @@ class InteractLearnPracticeScreen
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: () async =>
|
onPop: () async =>
|
||||||
await _showSheet(context: context, viewModel: viewModel),
|
await _showSheet(context: context, viewModel: viewModel),
|
||||||
title: '${LocaleKeys.practice_speaking.tr()} ($index/${viewModel.questions.length})');
|
title:
|
||||||
|
'${LocaleKeys.practice_speaking.tr()} ($index/${viewModel.questions.length})');
|
||||||
|
|
||||||
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
||||||
Column(
|
Column(
|
||||||
|
|
@ -154,13 +155,13 @@ class InteractLearnPracticeScreen
|
||||||
: const SizedBox(height: 20);
|
: const SizedBox(height: 20);
|
||||||
|
|
||||||
Widget _buildListeningLabel() => Text(
|
Widget _buildListeningLabel() => Text(
|
||||||
'Daniel ${LocaleKeys.speaking.tr()}',
|
'Daniel ${LocaleKeys.speaking.tr()}',
|
||||||
style: style14P400,
|
style: style14P400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSpeakingLabel() => Text(
|
Widget _buildSpeakingLabel() => Text(
|
||||||
'${ LocaleKeys.you_are_speaking.tr()}...',
|
'${LocaleKeys.you_are_speaking.tr()}...',
|
||||||
style: style14P400,
|
style: style14P400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -239,7 +240,7 @@ class InteractLearnPracticeScreen
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildActionLabel() => Text(
|
Widget _buildActionLabel() => Text(
|
||||||
LocaleKeys.tap_microphone.tr(),
|
LocaleKeys.tap_microphone.tr(),
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -359,7 +360,7 @@ class InteractLearnPracticeScreen
|
||||||
CustomColumnButton(
|
CustomColumnButton(
|
||||||
color: kcRed,
|
color: kcRed,
|
||||||
icon: Icons.close,
|
icon: Icons.close,
|
||||||
label:LocaleKeys.cancel.tr() ,
|
label: LocaleKeys.cancel.tr(),
|
||||||
onTap: () async =>
|
onTap: () async =>
|
||||||
await _showSheet(context: context, viewModel: viewModel),
|
await _showSheet(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class LearnLoadingScreen extends StatelessWidget {
|
||||||
Align(alignment: Alignment.center, child: _buildRefreshButton());
|
Align(alignment: Alignment.center, child: _buildRefreshButton());
|
||||||
|
|
||||||
Widget _buildRefreshButton() => NoDataIndicator(
|
Widget _buildRefreshButton() => NoDataIndicator(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
title: LocaleKeys.no_practice_available.tr(),
|
title: LocaleKeys.no_practice_available.tr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ class LearnPracticeAppreciationScreen
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
LocaleKeys.you_have_finished_practice.tr(),
|
LocaleKeys.you_have_finished_practice.tr(),
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -158,6 +158,5 @@ class LearnPracticeAppreciationScreen
|
||||||
onTap: () => viewModel.goTo(4),
|
onTap: () => viewModel.goTo(4),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
text: LocaleKeys.view_results.tr(),
|
text: LocaleKeys.view_results.tr(),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -180,6 +180,6 @@ class LearnPracticeDescriptionScreen
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: () => viewModel.goTo(2),
|
onTap: () => viewModel.goTo(2),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
text: LocaleKeys.start_practice.tr() ,
|
text: LocaleKeys.start_practice.tr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ class LearnPracticeFinishScreen
|
||||||
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
title:LocaleKeys.practice_speaking.tr(),
|
title: LocaleKeys.practice_speaking.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
@ -81,13 +81,13 @@ class LearnPracticeFinishScreen
|
||||||
Widget _buildIcon() => SvgPicture.asset('assets/icons/success.svg');
|
Widget _buildIcon() => SvgPicture.asset('assets/icons/success.svg');
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
LocaleKeys.practice_completed.tr(),
|
LocaleKeys.practice_completed.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
LocaleKeys.sound_confident.tr() ,
|
LocaleKeys.sound_confident.tr(),
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -120,7 +120,7 @@ class LearnPracticeFinishScreen
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
text: LocaleKeys.continue_practice.tr() ,
|
text: LocaleKeys.continue_practice.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPracticeAgainButton(LearnPracticeViewModel viewModel) =>
|
Widget _buildPracticeAgainButton(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ class LearnPracticeResultScreen
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
SmallAppBar(
|
SmallAppBar(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
title:LocaleKeys.result.tr(),
|
title: LocaleKeys.result.tr(),
|
||||||
onPop: () async =>
|
onPop: () async =>
|
||||||
await _showSheet(context: context, viewModel: viewModel),
|
await _showSheet(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
@ -176,7 +176,7 @@ class LearnPracticeResultScreen
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
text:LocaleKeys.cont.tr(),
|
text: LocaleKeys.cont.tr(),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await _navigate(viewModel),
|
onTap: () async => await _navigate(viewModel),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildActionLabel() => Text(
|
Widget _buildActionLabel() => Text(
|
||||||
LocaleKeys.tap_start_to_listen.tr() ,
|
LocaleKeys.tap_start_to_listen.tr(),
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -215,8 +215,8 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
|
|
||||||
Widget _buildReplyButtonWrapper() => Expanded(child: _buildReplyButton());
|
Widget _buildReplyButtonWrapper() => Expanded(child: _buildReplyButton());
|
||||||
|
|
||||||
Widget _buildReplyButton() => CustomColumnButton(
|
Widget _buildReplyButton() => CustomColumnButton(
|
||||||
icon: Icons.replay, label:LocaleKeys.reply.tr() , color: kcLightGrey);
|
icon: Icons.replay, label: LocaleKeys.reply.tr(), color: kcLightGrey);
|
||||||
|
|
||||||
Widget _buildMicButtonWrapper(LearnPracticeViewModel viewModel) =>
|
Widget _buildMicButtonWrapper(LearnPracticeViewModel viewModel) =>
|
||||||
Expanded(child: _buildMicButton(viewModel));
|
Expanded(child: _buildMicButton(viewModel));
|
||||||
|
|
|
||||||
|
|
@ -89,14 +89,12 @@ class LearnProgramView extends StackedView<LearnProgramViewModel> {
|
||||||
program: viewModel.learnPrograms[index],
|
program: viewModel.learnPrograms[index],
|
||||||
onTap: () async => await viewModel
|
onTap: () async => await viewModel
|
||||||
.navigateToLearnCourse(viewModel.learnPrograms[index].id ?? 0),
|
.navigateToLearnCourse(viewModel.learnPrograms[index].id ?? 0),
|
||||||
onLockTap: () async => await viewModel.navigateToLearnSubscription(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTile({
|
Widget _buildTile({
|
||||||
required LearnProgram program,
|
required LearnProgram program,
|
||||||
required GestureTapCallback onTap,
|
required GestureTapCallback onTap,
|
||||||
required GestureTapCallback onLockTap,
|
|
||||||
}) =>
|
}) =>
|
||||||
LearnProgramTile(onTap: onTap, program: program,onLockTap: onLockTap,);
|
LearnProgramTile(onTap: onTap, program: program);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,6 @@ class LearnProgramViewModel extends ReactiveViewModel {
|
||||||
Future<void> navigateToLearnCourse(int id) async =>
|
Future<void> navigateToLearnCourse(int id) async =>
|
||||||
_navigationService.navigateToLearnCourseView(id: id);
|
_navigationService.navigateToLearnCourseView(id: id);
|
||||||
|
|
||||||
Future<void> navigateToLearnSubscription() async =>
|
|
||||||
await _navigationService.navigateToLearnSubscriptionView();
|
|
||||||
|
|
||||||
// Remote api call
|
// Remote api call
|
||||||
|
|
||||||
// Learn programs
|
// Learn programs
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,10 @@ class LoginOtpScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
Widget _buildAppBar(LoginViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(LoginViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody(
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,10 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
Widget _buildAppBar(LoginViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(LoginViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody(
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,10 @@ class LoginWithPhoneNumberScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => viewModel.goTo(0),
|
onPop: () => viewModel.goTo(0),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked/stacked_annotations.dart';
|
import 'package:stacked/stacked_annotations.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/age_group_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/age_group_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/challenge_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/challenge_form_screen.dart';
|
||||||
|
|
@ -12,18 +13,16 @@ import 'package:yimaru_app/ui/views/onboarding/screens/language_goal_form_screen
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/learning_goal_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/learning_goal_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/occupation_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/occupation_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/topic_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/topic_form_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/startup/startup_view.dart';
|
||||||
|
|
||||||
import '../../common/validators/form_validator.dart';
|
import '../../common/validators/form_validator.dart';
|
||||||
import 'onboarding_viewmodel.dart';
|
import 'onboarding_viewmodel.dart';
|
||||||
import 'onboarding_view.form.dart';
|
import 'onboarding_view.form.dart';
|
||||||
|
|
||||||
@FormView(fields: [
|
@FormView(fields: [
|
||||||
FormTextField(name: 'topic', validator: FormValidator.validateForm),
|
|
||||||
FormTextField(
|
FormTextField(
|
||||||
name: 'fullName', validator: FormValidator.validateFullNameForm),
|
name: 'fullName', validator: FormValidator.validateFullNameForm),
|
||||||
FormTextField(name: 'region', validator: FormValidator.validateForm),
|
FormTextField(name: 'region', validator: FormValidator.validateForm),
|
||||||
FormTextField(name: 'challenge', validator: FormValidator.validateForm),
|
|
||||||
FormTextField(name: 'languageGoal', validator: FormValidator.validateForm),
|
|
||||||
])
|
])
|
||||||
class OnboardingView extends StackedView<OnboardingViewModel>
|
class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
with $OnboardingView {
|
with $OnboardingView {
|
||||||
|
|
@ -34,11 +33,8 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initClearData() {
|
void _initClearData() {
|
||||||
topicController.clear();
|
|
||||||
regionController.clear();
|
regionController.clear();
|
||||||
fullNameController.clear();
|
fullNameController.clear();
|
||||||
challengeController.clear();
|
|
||||||
languageGoalController.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearDataOnNavigation(OnboardingViewModel viewModel) {
|
void _clearDataOnNavigation(OnboardingViewModel viewModel) {
|
||||||
|
|
@ -54,17 +50,15 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
} else if (viewModel.currentPage == 4) {
|
} else if (viewModel.currentPage == 4) {
|
||||||
viewModel.resetOccupationFormScreen();
|
viewModel.resetOccupationFormScreen();
|
||||||
} else if (viewModel.currentPage == 5) {
|
} else if (viewModel.currentPage == 5) {
|
||||||
|
regionController.clear();
|
||||||
viewModel.resetCountryRegionFormScreen();
|
viewModel.resetCountryRegionFormScreen();
|
||||||
} else if (viewModel.currentPage == 6) {
|
} else if (viewModel.currentPage == 6) {
|
||||||
viewModel.resetLearningGoalFormScreen();
|
viewModel.resetLearningGoalFormScreen();
|
||||||
} else if (viewModel.currentPage == 7) {
|
} else if (viewModel.currentPage == 7) {
|
||||||
languageGoalController.clear();
|
|
||||||
viewModel.resetLanguageGoalFormScreen();
|
viewModel.resetLanguageGoalFormScreen();
|
||||||
} else if (viewModel.currentPage == 8) {
|
} else if (viewModel.currentPage == 8) {
|
||||||
challengeController.clear();
|
|
||||||
viewModel.resetChallengeFormScreen();
|
viewModel.resetChallengeFormScreen();
|
||||||
} else if (viewModel.currentPage == 9) {
|
} else if (viewModel.currentPage == 9) {
|
||||||
topicController.clear();
|
|
||||||
viewModel.resetTopicFormScreen();
|
viewModel.resetTopicFormScreen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +71,7 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(OnboardingViewModel viewModel) {
|
void onViewModelReady(OnboardingViewModel viewModel) async {
|
||||||
_initClearData();
|
_initClearData();
|
||||||
_initUserData(viewModel);
|
_initUserData(viewModel);
|
||||||
syncFormWithViewModel(viewModel);
|
syncFormWithViewModel(viewModel);
|
||||||
|
|
@ -134,17 +128,13 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
|
|
||||||
Widget _buildOccupationForm() => const OccupationFormScreen();
|
Widget _buildOccupationForm() => const OccupationFormScreen();
|
||||||
|
|
||||||
Widget _buildCountryRegionForm() => CountryRegionFormScreen(
|
Widget _buildCountryRegionForm() => CountryRegionFormScreen(regionController: regionController);
|
||||||
regionController: regionController,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLearningGoalForm() => const LearningGoalFormScreen();
|
Widget _buildLearningGoalForm() => const LearningGoalFormScreen();
|
||||||
|
|
||||||
Widget _buildLanguageGoalForm() =>
|
Widget _buildLanguageGoalForm() => const LanguageGoalFormScreen();
|
||||||
LanguageGoalFormScreen(languageGoalController: languageGoalController);
|
|
||||||
|
|
||||||
Widget _buildChallengeForm() =>
|
Widget _buildChallengeForm() => const ChallengeFormScreen();
|
||||||
ChallengeFormScreen(challengeController: challengeController);
|
|
||||||
|
|
||||||
Widget _buildTopicForm() => TopicFormScreen(topicController: topicController);
|
Widget _buildTopicForm() => const TopicFormScreen();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,8 @@ import 'package:yimaru_app/ui/common/validators/form_validator.dart';
|
||||||
|
|
||||||
const bool _autoTextFieldValidation = true;
|
const bool _autoTextFieldValidation = true;
|
||||||
|
|
||||||
const String TopicValueKey = 'topic';
|
|
||||||
const String FullNameValueKey = 'fullName';
|
const String FullNameValueKey = 'fullName';
|
||||||
const String RegionValueKey = 'region';
|
const String RegionValueKey = 'region';
|
||||||
const String ChallengeValueKey = 'challenge';
|
|
||||||
const String LanguageGoalValueKey = 'languageGoal';
|
|
||||||
|
|
||||||
final Map<String, TextEditingController> _OnboardingViewTextEditingControllers =
|
final Map<String, TextEditingController> _OnboardingViewTextEditingControllers =
|
||||||
{};
|
{};
|
||||||
|
|
@ -25,31 +22,18 @@ final Map<String, TextEditingController> _OnboardingViewTextEditingControllers =
|
||||||
final Map<String, FocusNode> _OnboardingViewFocusNodes = {};
|
final Map<String, FocusNode> _OnboardingViewFocusNodes = {};
|
||||||
|
|
||||||
final Map<String, String? Function(String?)?> _OnboardingViewTextValidations = {
|
final Map<String, String? Function(String?)?> _OnboardingViewTextValidations = {
|
||||||
TopicValueKey: FormValidator.validateForm,
|
|
||||||
FullNameValueKey: FormValidator.validateFullNameForm,
|
FullNameValueKey: FormValidator.validateFullNameForm,
|
||||||
RegionValueKey: FormValidator.validateForm,
|
RegionValueKey: FormValidator.validateForm,
|
||||||
ChallengeValueKey: FormValidator.validateForm,
|
|
||||||
LanguageGoalValueKey: FormValidator.validateForm,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mixin $OnboardingView {
|
mixin $OnboardingView {
|
||||||
TextEditingController get topicController =>
|
|
||||||
_getFormTextEditingController(TopicValueKey);
|
|
||||||
TextEditingController get fullNameController =>
|
TextEditingController get fullNameController =>
|
||||||
_getFormTextEditingController(FullNameValueKey);
|
_getFormTextEditingController(FullNameValueKey);
|
||||||
TextEditingController get regionController =>
|
TextEditingController get regionController =>
|
||||||
_getFormTextEditingController(RegionValueKey);
|
_getFormTextEditingController(RegionValueKey);
|
||||||
TextEditingController get challengeController =>
|
|
||||||
_getFormTextEditingController(ChallengeValueKey);
|
|
||||||
TextEditingController get languageGoalController =>
|
|
||||||
_getFormTextEditingController(LanguageGoalValueKey);
|
|
||||||
|
|
||||||
FocusNode get topicFocusNode => _getFormFocusNode(TopicValueKey);
|
|
||||||
FocusNode get fullNameFocusNode => _getFormFocusNode(FullNameValueKey);
|
FocusNode get fullNameFocusNode => _getFormFocusNode(FullNameValueKey);
|
||||||
FocusNode get regionFocusNode => _getFormFocusNode(RegionValueKey);
|
FocusNode get regionFocusNode => _getFormFocusNode(RegionValueKey);
|
||||||
FocusNode get challengeFocusNode => _getFormFocusNode(ChallengeValueKey);
|
|
||||||
FocusNode get languageGoalFocusNode =>
|
|
||||||
_getFormFocusNode(LanguageGoalValueKey);
|
|
||||||
|
|
||||||
TextEditingController _getFormTextEditingController(
|
TextEditingController _getFormTextEditingController(
|
||||||
String key, {
|
String key, {
|
||||||
|
|
@ -75,11 +59,8 @@ mixin $OnboardingView {
|
||||||
/// Registers a listener on every generated controller that calls [model.setData()]
|
/// Registers a listener on every generated controller that calls [model.setData()]
|
||||||
/// with the latest textController values
|
/// with the latest textController values
|
||||||
void syncFormWithViewModel(FormStateHelper model) {
|
void syncFormWithViewModel(FormStateHelper model) {
|
||||||
topicController.addListener(() => _updateFormData(model));
|
|
||||||
fullNameController.addListener(() => _updateFormData(model));
|
fullNameController.addListener(() => _updateFormData(model));
|
||||||
regionController.addListener(() => _updateFormData(model));
|
regionController.addListener(() => _updateFormData(model));
|
||||||
challengeController.addListener(() => _updateFormData(model));
|
|
||||||
languageGoalController.addListener(() => _updateFormData(model));
|
|
||||||
|
|
||||||
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
||||||
}
|
}
|
||||||
|
|
@ -91,11 +72,8 @@ mixin $OnboardingView {
|
||||||
'This feature was deprecated after 3.1.0.',
|
'This feature was deprecated after 3.1.0.',
|
||||||
)
|
)
|
||||||
void listenToFormUpdated(FormViewModel model) {
|
void listenToFormUpdated(FormViewModel model) {
|
||||||
topicController.addListener(() => _updateFormData(model));
|
|
||||||
fullNameController.addListener(() => _updateFormData(model));
|
fullNameController.addListener(() => _updateFormData(model));
|
||||||
regionController.addListener(() => _updateFormData(model));
|
regionController.addListener(() => _updateFormData(model));
|
||||||
challengeController.addListener(() => _updateFormData(model));
|
|
||||||
languageGoalController.addListener(() => _updateFormData(model));
|
|
||||||
|
|
||||||
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
||||||
}
|
}
|
||||||
|
|
@ -105,11 +83,8 @@ mixin $OnboardingView {
|
||||||
model.setData(
|
model.setData(
|
||||||
model.formValueMap
|
model.formValueMap
|
||||||
..addAll({
|
..addAll({
|
||||||
TopicValueKey: topicController.text,
|
|
||||||
FullNameValueKey: fullNameController.text,
|
FullNameValueKey: fullNameController.text,
|
||||||
RegionValueKey: regionController.text,
|
RegionValueKey: regionController.text,
|
||||||
ChallengeValueKey: challengeController.text,
|
|
||||||
LanguageGoalValueKey: languageGoalController.text,
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -151,22 +126,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
return !hasAnyValidationMessage;
|
return !hasAnyValidationMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
String? get topicValue => this.formValueMap[TopicValueKey] as String?;
|
|
||||||
String? get fullNameValue => this.formValueMap[FullNameValueKey] as String?;
|
String? get fullNameValue => this.formValueMap[FullNameValueKey] as String?;
|
||||||
String? get regionValue => this.formValueMap[RegionValueKey] as String?;
|
String? get regionValue => this.formValueMap[RegionValueKey] as String?;
|
||||||
String? get challengeValue => this.formValueMap[ChallengeValueKey] as String?;
|
|
||||||
String? get languageGoalValue =>
|
|
||||||
this.formValueMap[LanguageGoalValueKey] as String?;
|
|
||||||
|
|
||||||
set topicValue(String? value) {
|
|
||||||
this.setData(
|
|
||||||
this.formValueMap..addAll({TopicValueKey: value}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (_OnboardingViewTextEditingControllers.containsKey(TopicValueKey)) {
|
|
||||||
_OnboardingViewTextEditingControllers[TopicValueKey]?.text = value ?? '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set fullNameValue(String? value) {
|
set fullNameValue(String? value) {
|
||||||
this.setData(
|
this.setData(
|
||||||
|
|
@ -189,97 +150,41 @@ extension ValueProperties on FormStateHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set challengeValue(String? value) {
|
|
||||||
this.setData(
|
|
||||||
this.formValueMap..addAll({ChallengeValueKey: value}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (_OnboardingViewTextEditingControllers.containsKey(ChallengeValueKey)) {
|
|
||||||
_OnboardingViewTextEditingControllers[ChallengeValueKey]?.text =
|
|
||||||
value ?? '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set languageGoalValue(String? value) {
|
|
||||||
this.setData(
|
|
||||||
this.formValueMap..addAll({LanguageGoalValueKey: value}),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (_OnboardingViewTextEditingControllers.containsKey(
|
|
||||||
LanguageGoalValueKey)) {
|
|
||||||
_OnboardingViewTextEditingControllers[LanguageGoalValueKey]?.text =
|
|
||||||
value ?? '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get hasTopic =>
|
|
||||||
this.formValueMap.containsKey(TopicValueKey) &&
|
|
||||||
(topicValue?.isNotEmpty ?? false);
|
|
||||||
bool get hasFullName =>
|
bool get hasFullName =>
|
||||||
this.formValueMap.containsKey(FullNameValueKey) &&
|
this.formValueMap.containsKey(FullNameValueKey) &&
|
||||||
(fullNameValue?.isNotEmpty ?? false);
|
(fullNameValue?.isNotEmpty ?? false);
|
||||||
bool get hasRegion =>
|
bool get hasRegion =>
|
||||||
this.formValueMap.containsKey(RegionValueKey) &&
|
this.formValueMap.containsKey(RegionValueKey) &&
|
||||||
(regionValue?.isNotEmpty ?? false);
|
(regionValue?.isNotEmpty ?? false);
|
||||||
bool get hasChallenge =>
|
|
||||||
this.formValueMap.containsKey(ChallengeValueKey) &&
|
|
||||||
(challengeValue?.isNotEmpty ?? false);
|
|
||||||
bool get hasLanguageGoal =>
|
|
||||||
this.formValueMap.containsKey(LanguageGoalValueKey) &&
|
|
||||||
(languageGoalValue?.isNotEmpty ?? false);
|
|
||||||
|
|
||||||
bool get hasTopicValidationMessage =>
|
|
||||||
this.fieldsValidationMessages[TopicValueKey]?.isNotEmpty ?? false;
|
|
||||||
bool get hasFullNameValidationMessage =>
|
bool get hasFullNameValidationMessage =>
|
||||||
this.fieldsValidationMessages[FullNameValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[FullNameValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasRegionValidationMessage =>
|
bool get hasRegionValidationMessage =>
|
||||||
this.fieldsValidationMessages[RegionValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[RegionValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasChallengeValidationMessage =>
|
|
||||||
this.fieldsValidationMessages[ChallengeValueKey]?.isNotEmpty ?? false;
|
|
||||||
bool get hasLanguageGoalValidationMessage =>
|
|
||||||
this.fieldsValidationMessages[LanguageGoalValueKey]?.isNotEmpty ?? false;
|
|
||||||
|
|
||||||
String? get topicValidationMessage =>
|
|
||||||
this.fieldsValidationMessages[TopicValueKey];
|
|
||||||
String? get fullNameValidationMessage =>
|
String? get fullNameValidationMessage =>
|
||||||
this.fieldsValidationMessages[FullNameValueKey];
|
this.fieldsValidationMessages[FullNameValueKey];
|
||||||
String? get regionValidationMessage =>
|
String? get regionValidationMessage =>
|
||||||
this.fieldsValidationMessages[RegionValueKey];
|
this.fieldsValidationMessages[RegionValueKey];
|
||||||
String? get challengeValidationMessage =>
|
|
||||||
this.fieldsValidationMessages[ChallengeValueKey];
|
|
||||||
String? get languageGoalValidationMessage =>
|
|
||||||
this.fieldsValidationMessages[LanguageGoalValueKey];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Methods on FormStateHelper {
|
extension Methods on FormStateHelper {
|
||||||
void setTopicValidationMessage(String? validationMessage) =>
|
|
||||||
this.fieldsValidationMessages[TopicValueKey] = validationMessage;
|
|
||||||
void setFullNameValidationMessage(String? validationMessage) =>
|
void setFullNameValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[FullNameValueKey] = validationMessage;
|
this.fieldsValidationMessages[FullNameValueKey] = validationMessage;
|
||||||
void setRegionValidationMessage(String? validationMessage) =>
|
void setRegionValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[RegionValueKey] = validationMessage;
|
this.fieldsValidationMessages[RegionValueKey] = validationMessage;
|
||||||
void setChallengeValidationMessage(String? validationMessage) =>
|
|
||||||
this.fieldsValidationMessages[ChallengeValueKey] = validationMessage;
|
|
||||||
void setLanguageGoalValidationMessage(String? validationMessage) =>
|
|
||||||
this.fieldsValidationMessages[LanguageGoalValueKey] = validationMessage;
|
|
||||||
|
|
||||||
/// Clears text input fields on the Form
|
/// Clears text input fields on the Form
|
||||||
void clearForm() {
|
void clearForm() {
|
||||||
topicValue = '';
|
|
||||||
fullNameValue = '';
|
fullNameValue = '';
|
||||||
regionValue = '';
|
regionValue = '';
|
||||||
challengeValue = '';
|
|
||||||
languageGoalValue = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates text input fields on the Form
|
/// Validates text input fields on the Form
|
||||||
void validateForm() {
|
void validateForm() {
|
||||||
this.setValidationMessages({
|
this.setValidationMessages({
|
||||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
|
||||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||||
RegionValueKey: getValidationMessage(RegionValueKey),
|
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
|
||||||
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -299,9 +204,6 @@ String? getValidationMessage(String key) {
|
||||||
/// Updates the fieldsValidationMessages on the FormViewModel
|
/// Updates the fieldsValidationMessages on the FormViewModel
|
||||||
void updateValidationData(FormStateHelper model) =>
|
void updateValidationData(FormStateHelper model) =>
|
||||||
model.setValidationMessages({
|
model.setValidationMessages({
|
||||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
|
||||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||||
RegionValueKey: getValidationMessage(RegionValueKey),
|
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
|
||||||
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,13 @@ import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:yimaru_app/app/app.router.dart';
|
import 'package:yimaru_app/app/app.router.dart';
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
|
import '../../../models/field_option.dart';
|
||||||
|
import '../../../services/api_service.dart';
|
||||||
import '../../../services/google_auth_service.dart';
|
import '../../../services/google_auth_service.dart';
|
||||||
import '../../../services/localization_service.dart';
|
import '../../../services/localization_service.dart';
|
||||||
|
import '../../../services/onboarding_service.dart';
|
||||||
|
import '../../../services/status_checker_service.dart';
|
||||||
|
import '../../common/enmus.dart';
|
||||||
|
|
||||||
class OnboardingViewModel extends ReactiveViewModel
|
class OnboardingViewModel extends ReactiveViewModel
|
||||||
with FormStateHelper
|
with FormStateHelper
|
||||||
|
|
@ -15,6 +20,8 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
final _googleAuthService = locator<GoogleAuthService>();
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
|
final _onboardingService = locator<OnboardingService>();
|
||||||
|
|
||||||
final _localizationService = locator<LocalizationService>();
|
final _localizationService = locator<LocalizationService>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -47,19 +54,15 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
bool get focusFullName => _focusFullName;
|
bool get focusFullName => _focusFullName;
|
||||||
|
|
||||||
// Educational background
|
// Educational background
|
||||||
final List<String> _educationalBackgrounds = [
|
List<FieldOption> get _educationalBackgrounds =>
|
||||||
'No formal education',
|
_onboardingService.educationalBackgrounds;
|
||||||
'Primary school',
|
|
||||||
'Secondary /High school',
|
|
||||||
'College / Diploma',
|
|
||||||
'Bachelor’s and above',
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> get educationalBackgrounds => _educationalBackgrounds;
|
List<FieldOption> get educationalBackgrounds => _educationalBackgrounds;
|
||||||
|
|
||||||
String? _selectedEducationalBackground;
|
FieldOption? _selectedEducationalBackground;
|
||||||
|
|
||||||
String? get selectedEducationalBackground => _selectedEducationalBackground;
|
FieldOption? get selectedEducationalBackground =>
|
||||||
|
_selectedEducationalBackground;
|
||||||
|
|
||||||
// Gender
|
// Gender
|
||||||
final List<String> _gendersEn = [
|
final List<String> _gendersEn = [
|
||||||
|
|
@ -81,150 +84,73 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
String? get selectedGender => _selectedGender;
|
String? get selectedGender => _selectedGender;
|
||||||
|
|
||||||
// Age group
|
// Age group
|
||||||
final List<Map<String, dynamic>> _ageGroups = [
|
List<FieldOption> get _ageGroups => _onboardingService.ageGroups;
|
||||||
{
|
|
||||||
'Under 13': 'UNDER_13',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'13-17': '13_17',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'18-24': '18_24',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'25-34': '25_34',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'35-44': '35_44',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'45-54': '45_54',
|
|
||||||
},
|
|
||||||
{'55-Plus': '55_PLUS'},
|
|
||||||
];
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> get ageGroups => _ageGroups;
|
List<FieldOption> get ageGroups => _ageGroups;
|
||||||
|
|
||||||
Map<String, dynamic>? _selectedAgeGroup;
|
FieldOption? _selectedAgeGroup;
|
||||||
|
|
||||||
Map<String, dynamic>? get selectedAgeGroup => _selectedAgeGroup;
|
FieldOption? get selectedAgeGroup => _selectedAgeGroup;
|
||||||
|
|
||||||
// Occupation
|
// Occupation
|
||||||
String _selectedOccupation = 'Students (High school & University)';
|
FieldOption? _selectedOccupation;
|
||||||
|
|
||||||
String get selectedOccupation => _selectedOccupation;
|
FieldOption? get selectedOccupation => _selectedOccupation;
|
||||||
|
|
||||||
// Country
|
// Country
|
||||||
String _selectedCountry = 'Ethiopia';
|
FieldOption? _selectedCountry;
|
||||||
|
|
||||||
String get selectedCountry => _selectedCountry;
|
FieldOption? get selectedCountry => _selectedCountry;
|
||||||
|
|
||||||
// Region
|
// Region
|
||||||
bool _focusRegion = false;
|
bool _focusRegion = false;
|
||||||
|
|
||||||
bool get focusRegion => _focusRegion;
|
bool get focusRegion => _focusRegion;
|
||||||
|
|
||||||
bool _dropdownRegion = true;
|
bool _dropdownRegion = false;
|
||||||
|
|
||||||
bool get dropdownRegion => _dropdownRegion;
|
bool get dropdownRegion => _dropdownRegion;
|
||||||
|
|
||||||
String _selectedRegion = 'Addis Ababa';
|
FieldOption? _selectedRegion;
|
||||||
|
|
||||||
String get selectedRegion => _selectedRegion;
|
FieldOption? get selectedRegion => _selectedRegion;
|
||||||
|
|
||||||
// Learning goal
|
// Learning goal
|
||||||
String? _selectedLearningGoal;
|
FieldOption? _selectedLearningGoal;
|
||||||
|
|
||||||
String? get selectedLearningGoal => _selectedLearningGoal;
|
FieldOption? get selectedLearningGoal => _selectedLearningGoal;
|
||||||
|
|
||||||
final List<Map<String, dynamic>> _learningGoals = [
|
List<FieldOption> get _learningGoals => _onboardingService.learningGoals;
|
||||||
{
|
|
||||||
'icon': 0,
|
|
||||||
'title': 'Learn to Speak English',
|
|
||||||
'subtitle': 'I know some English, but i want to learn to speak it',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'icon': 1,
|
|
||||||
'title': 'Practice Speaking English',
|
|
||||||
'subtitle': 'I already speak English, but I want more practice.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'icon': 2,
|
|
||||||
'title': 'Skill-based Courses',
|
|
||||||
'subtitle': 'I want courses for IELTS, TOEFL, Duolingo, or work.',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> get learningGoals => _learningGoals;
|
List<FieldOption> get learningGoals => _learningGoals;
|
||||||
|
|
||||||
// Learning reason
|
// Learning reason
|
||||||
bool _showLanguageGoalTextBox = false;
|
|
||||||
|
|
||||||
bool get showLanguageGoalTextBox => _showLanguageGoalTextBox;
|
FieldOption? _selectedLanguageGoal;
|
||||||
|
|
||||||
bool _focusLanguageGoal = false;
|
FieldOption? get selectedLanguageGoal => _selectedLanguageGoal;
|
||||||
|
|
||||||
bool get focusLanguageGoal => _focusLanguageGoal;
|
List<FieldOption> get _languageGoals => _onboardingService.languageGoals;
|
||||||
|
|
||||||
String? _selectedLanguageGoal;
|
List<FieldOption> get languageGoals => _languageGoals;
|
||||||
|
|
||||||
String? get selectedLanguageGoal => _selectedLanguageGoal;
|
|
||||||
|
|
||||||
final List<String> _languageGoals = [
|
|
||||||
'Speak confidently at work or school',
|
|
||||||
'Travel or handle daily situations',
|
|
||||||
'Connect with family or friends',
|
|
||||||
'General skills expansion',
|
|
||||||
'Other'
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> get languageGoals => _languageGoals;
|
|
||||||
|
|
||||||
// Challenges
|
// Challenges
|
||||||
bool _showChallengeTextBox = false;
|
FieldOption? _selectedChallenge;
|
||||||
|
|
||||||
bool get showChallengeTextBox => _showChallengeTextBox;
|
FieldOption? get selectedChallenge => _selectedChallenge;
|
||||||
|
|
||||||
bool _focusChallenge = false;
|
List<FieldOption> get _challenges => _onboardingService.challenges;
|
||||||
|
|
||||||
bool get focusChallenge => _focusChallenge;
|
List<FieldOption> get challenges => _challenges;
|
||||||
|
|
||||||
String? _selectedChallenge;
|
|
||||||
|
|
||||||
String? get selectedChallenge => _selectedChallenge;
|
|
||||||
|
|
||||||
final List<String> _challenges = [
|
|
||||||
'Pronunciation',
|
|
||||||
'Finding words or grammar quickly',
|
|
||||||
'Feeling nervous or lacking confidence',
|
|
||||||
'Understanding accents or fast speech',
|
|
||||||
'Other'
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> get challenges => _challenges;
|
|
||||||
|
|
||||||
// Topic
|
// Topic
|
||||||
bool _showTopicTextBox = false;
|
FieldOption? _selectedTopic;
|
||||||
|
|
||||||
bool get showTopicTextBox => _showTopicTextBox;
|
FieldOption? get selectedTopic => _selectedTopic;
|
||||||
|
|
||||||
bool _focusTopic = false;
|
List<FieldOption> get _topics => _onboardingService.topics;
|
||||||
|
|
||||||
bool get focusTopic => _focusTopic;
|
List<FieldOption> get topics => _topics;
|
||||||
|
|
||||||
String? _selectedTopic;
|
|
||||||
|
|
||||||
String? get selectedTopic => _selectedTopic;
|
|
||||||
|
|
||||||
final List<String> _topics = [
|
|
||||||
'Food & Cooking',
|
|
||||||
'Hobbies, Sports, Music',
|
|
||||||
'Tech, News, Business',
|
|
||||||
'Travel, Places, Culture',
|
|
||||||
'Other'
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> get topics => _topics;
|
|
||||||
|
|
||||||
// User data
|
// User data
|
||||||
final Map<String, dynamic> _userData = {};
|
final Map<String, dynamic> _userData = {};
|
||||||
|
|
@ -238,12 +164,12 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Education background
|
// Education background
|
||||||
void setSelectedEducationalBackground(String value) {
|
void setSelectedEducationalBackground(FieldOption value) {
|
||||||
_selectedEducationalBackground = value;
|
_selectedEducationalBackground = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedEducationalBackground(String value) =>
|
bool isSelectedEducationalBackground(FieldOption value) =>
|
||||||
_selectedEducationalBackground == value;
|
_selectedEducationalBackground == value;
|
||||||
|
|
||||||
// Gender
|
// Gender
|
||||||
|
|
@ -255,192 +181,35 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
bool isSelectedGender(String value) => _selectedGender == value;
|
bool isSelectedGender(String value) => _selectedGender == value;
|
||||||
|
|
||||||
// Age group
|
// Age group
|
||||||
void setSelectedAgeGroup(Map<String, dynamic> value) {
|
void setSelectedAgeGroup(FieldOption value) {
|
||||||
_selectedAgeGroup = value;
|
_selectedAgeGroup = value;
|
||||||
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedAgeGroup(Map<String, dynamic> value) =>
|
bool isSelectedAgeGroup(FieldOption value) => _selectedAgeGroup == value;
|
||||||
_selectedAgeGroup == value;
|
|
||||||
|
|
||||||
// Occupation
|
// Occupation
|
||||||
List<String> getOccupations() => [
|
List<FieldOption> get _occupations => _onboardingService.occupations;
|
||||||
'Students (High school & University)',
|
|
||||||
'Job Seekers / Fresh Graduates',
|
|
||||||
'Working Professionals (Corporate/Office)',
|
|
||||||
'Government & NGO Workers',
|
|
||||||
'Entrepreneurs & Small Business Owners',
|
|
||||||
'Hospitality & Tourism Workers',
|
|
||||||
'Freelancers / Remote Workers (Digital Economy)'
|
|
||||||
];
|
|
||||||
|
|
||||||
void setSelectedOccupation(String value) {
|
List<FieldOption> get occupations => _occupations;
|
||||||
|
|
||||||
|
void setSelectedOccupation(FieldOption? value) {
|
||||||
_selectedOccupation = value;
|
_selectedOccupation = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Country
|
// Country
|
||||||
List<String> getCountries() => [
|
List<FieldOption> get _countries => _onboardingService.countries;
|
||||||
"Afghanistan",
|
|
||||||
"Albania",
|
|
||||||
"Algeria",
|
|
||||||
"Andorra",
|
|
||||||
"Angola",
|
|
||||||
"Argentina",
|
|
||||||
"Armenia",
|
|
||||||
"Australia",
|
|
||||||
"Austria",
|
|
||||||
"Azerbaijan",
|
|
||||||
"Bahrain",
|
|
||||||
"Bangladesh",
|
|
||||||
"Belarus",
|
|
||||||
"Belgium",
|
|
||||||
"Belize",
|
|
||||||
"Benin",
|
|
||||||
"Bhutan",
|
|
||||||
"Bolivia",
|
|
||||||
"Bosnia and Herzegovina",
|
|
||||||
"Botswana",
|
|
||||||
"Brazil",
|
|
||||||
"Brunei",
|
|
||||||
"Bulgaria",
|
|
||||||
"Burkina Faso",
|
|
||||||
"Burundi",
|
|
||||||
"Cambodia",
|
|
||||||
"Cameroon",
|
|
||||||
"Canada",
|
|
||||||
"Chad",
|
|
||||||
"Chile",
|
|
||||||
"China",
|
|
||||||
"Colombia",
|
|
||||||
"Comoros",
|
|
||||||
"Congo",
|
|
||||||
"Costa Rica",
|
|
||||||
"Croatia",
|
|
||||||
"Cuba",
|
|
||||||
"Cyprus",
|
|
||||||
"Czech Republic",
|
|
||||||
"Denmark",
|
|
||||||
"Djibouti",
|
|
||||||
"Dominican Republic",
|
|
||||||
"Ecuador",
|
|
||||||
"Egypt",
|
|
||||||
"El Salvador",
|
|
||||||
"Eritrea",
|
|
||||||
"Estonia",
|
|
||||||
"Eswatini",
|
|
||||||
"Ethiopia",
|
|
||||||
"Finland",
|
|
||||||
"France",
|
|
||||||
"Gabon",
|
|
||||||
"Gambia",
|
|
||||||
"Georgia",
|
|
||||||
"Germany",
|
|
||||||
"Ghana",
|
|
||||||
"Greece",
|
|
||||||
"Guatemala",
|
|
||||||
"Guinea",
|
|
||||||
"Haiti",
|
|
||||||
"Honduras",
|
|
||||||
"Hungary",
|
|
||||||
"Iceland",
|
|
||||||
"India",
|
|
||||||
"Indonesia",
|
|
||||||
"Iran",
|
|
||||||
"Iraq",
|
|
||||||
"Ireland",
|
|
||||||
"Israel",
|
|
||||||
"Italy",
|
|
||||||
"Jamaica",
|
|
||||||
"Japan",
|
|
||||||
"Jordan",
|
|
||||||
"Kazakhstan",
|
|
||||||
"Kenya",
|
|
||||||
"Kuwait",
|
|
||||||
"Kyrgyzstan",
|
|
||||||
"Laos",
|
|
||||||
"Latvia",
|
|
||||||
"Lebanon",
|
|
||||||
"Liberia",
|
|
||||||
"Libya",
|
|
||||||
"Lithuania",
|
|
||||||
"Luxembourg",
|
|
||||||
"Madagascar",
|
|
||||||
"Malawi",
|
|
||||||
"Malaysia",
|
|
||||||
"Maldives",
|
|
||||||
"Mali",
|
|
||||||
"Malta",
|
|
||||||
"Mexico",
|
|
||||||
"Moldova",
|
|
||||||
"Monaco",
|
|
||||||
"Mongolia",
|
|
||||||
"Morocco",
|
|
||||||
"Mozambique",
|
|
||||||
"Myanmar",
|
|
||||||
"Namibia",
|
|
||||||
"Nepal",
|
|
||||||
"Netherlands",
|
|
||||||
"New Zealand",
|
|
||||||
"Nicaragua",
|
|
||||||
"Niger",
|
|
||||||
"Nigeria",
|
|
||||||
"North Korea",
|
|
||||||
"Norway",
|
|
||||||
"Oman",
|
|
||||||
"Pakistan",
|
|
||||||
"Panama",
|
|
||||||
"Paraguay",
|
|
||||||
"Peru",
|
|
||||||
"Philippines",
|
|
||||||
"Poland",
|
|
||||||
"Portugal",
|
|
||||||
"Qatar",
|
|
||||||
"Romania",
|
|
||||||
"Russia",
|
|
||||||
"Rwanda",
|
|
||||||
"Saudi Arabia",
|
|
||||||
"Senegal",
|
|
||||||
"Serbia",
|
|
||||||
"Singapore",
|
|
||||||
"Slovakia",
|
|
||||||
"Slovenia",
|
|
||||||
"Somalia",
|
|
||||||
"South Africa",
|
|
||||||
"South Korea",
|
|
||||||
"Spain",
|
|
||||||
"Sri Lanka",
|
|
||||||
"Sudan",
|
|
||||||
"Sweden",
|
|
||||||
"Switzerland",
|
|
||||||
"Syria",
|
|
||||||
"Taiwan",
|
|
||||||
"Tajikistan",
|
|
||||||
"Tanzania",
|
|
||||||
"Thailand",
|
|
||||||
"Tunisia",
|
|
||||||
"Turkey",
|
|
||||||
"Uganda",
|
|
||||||
"Ukraine",
|
|
||||||
"United Arab Emirates",
|
|
||||||
"United Kingdom",
|
|
||||||
"United States",
|
|
||||||
"Uruguay",
|
|
||||||
"Uzbekistan",
|
|
||||||
"Venezuela",
|
|
||||||
"Vietnam",
|
|
||||||
"Yemen",
|
|
||||||
"Zambia",
|
|
||||||
"Zimbabwe"
|
|
||||||
];
|
|
||||||
|
|
||||||
void setSelectedCountry(String value) {
|
List<FieldOption> get countries => _countries;
|
||||||
|
|
||||||
|
void setSelectedCountry(FieldOption? value) {
|
||||||
_selectedCountry = value;
|
_selectedCountry = value;
|
||||||
|
if (value?.label?.toLowerCase().trim() == 'ethiopia') {
|
||||||
if (value == 'Ethiopia') {
|
|
||||||
_dropdownRegion = true;
|
_dropdownRegion = true;
|
||||||
_selectedRegion = 'Addis Ababa';
|
_selectedRegion = _regions
|
||||||
|
.firstWhere((e) => e.label?.toLowerCase().trim() == 'addis ababa');
|
||||||
} else {
|
} else {
|
||||||
_dropdownRegion = false;
|
_dropdownRegion = false;
|
||||||
}
|
}
|
||||||
|
|
@ -449,24 +218,11 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Region
|
// Region
|
||||||
List<String> getRegions() => [
|
List<FieldOption> get _regions => _onboardingService.regions;
|
||||||
'Addis Ababa',
|
|
||||||
'Afar',
|
|
||||||
'Amhara',
|
|
||||||
'Benishangul-Gumuz',
|
|
||||||
'Central Ethiopia',
|
|
||||||
'Dire Dawa',
|
|
||||||
'Gambela',
|
|
||||||
'Harari',
|
|
||||||
'Oromia',
|
|
||||||
'Sidama',
|
|
||||||
'Somali',
|
|
||||||
'South Ethiopia',
|
|
||||||
'South West Ethiopia Peoples',
|
|
||||||
'Tigray',
|
|
||||||
];
|
|
||||||
|
|
||||||
void setSelectedRegion(String value) {
|
List<FieldOption> get regions => _regions;
|
||||||
|
|
||||||
|
void setSelectedRegion(FieldOption? value) {
|
||||||
_selectedRegion = value;
|
_selectedRegion = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
@ -482,75 +238,42 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Learning goal
|
// Learning goal
|
||||||
void setSelectedLearningGoal(String value) {
|
void setSelectedLearningGoal(FieldOption value) {
|
||||||
_selectedLearningGoal = value;
|
_selectedLearningGoal = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedLearningGoal(String value) => _selectedLearningGoal == value;
|
bool isSelectedLearningGoal(FieldOption value) =>
|
||||||
|
_selectedLearningGoal == value;
|
||||||
|
|
||||||
// Learning reason
|
// Learning reason
|
||||||
void setLanguageGoalFocus() {
|
|
||||||
_focusLanguageGoal = true;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSelectedLanguageGoal(String value) {
|
void setSelectedLanguageGoal(FieldOption value) {
|
||||||
_selectedLanguageGoal = value;
|
_selectedLanguageGoal = value;
|
||||||
if (value.toLowerCase() == 'other') {
|
|
||||||
_showLanguageGoalTextBox = true;
|
|
||||||
} else {
|
|
||||||
if (_showLanguageGoalTextBox) {
|
|
||||||
_showLanguageGoalTextBox = false;
|
|
||||||
_focusLanguageGoal = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedLanguageGoal(String value) => _selectedLanguageGoal == value;
|
bool isSelectedLanguageGoal(FieldOption value) =>
|
||||||
|
_selectedLanguageGoal == value;
|
||||||
|
|
||||||
// Challenges
|
// Challenges
|
||||||
void setChallengesFocus() {
|
|
||||||
_focusChallenge = true;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSelectedChallenge(String value) {
|
void setSelectedChallenge(FieldOption value) {
|
||||||
_selectedChallenge = value;
|
_selectedChallenge = value;
|
||||||
if (value.toLowerCase() == 'other') {
|
|
||||||
_showChallengeTextBox = true;
|
|
||||||
} else {
|
|
||||||
if (_showChallengeTextBox) {
|
|
||||||
_showChallengeTextBox = false;
|
|
||||||
_focusChallenge = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedChallenge(String value) => _selectedChallenge == value;
|
bool isSelectedChallenge(FieldOption value) => _selectedChallenge == value;
|
||||||
|
|
||||||
// Topics
|
// Topics
|
||||||
void setTopicsFocus() {
|
|
||||||
_focusTopic = true;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSelectedTopic(String value) {
|
void setSelectedTopic(FieldOption value) {
|
||||||
_selectedTopic = value;
|
_selectedTopic = value;
|
||||||
if (value.toLowerCase() == 'other') {
|
|
||||||
_showTopicTextBox = true;
|
|
||||||
} else {
|
|
||||||
if (_showTopicTextBox) {
|
|
||||||
_showTopicTextBox = false;
|
|
||||||
_focusTopic = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedTopic(String value) => _selectedTopic == value;
|
bool isSelectedTopic(FieldOption value) => _selectedTopic == value;
|
||||||
|
|
||||||
// Add user data
|
// Add user data
|
||||||
void addUserData(Map<String, dynamic> data) {
|
void addUserData(Map<String, dynamic> data) {
|
||||||
|
|
@ -589,15 +312,15 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
// Reset occupation form screen
|
// Reset occupation form screen
|
||||||
void resetOccupationFormScreen() {
|
void resetOccupationFormScreen() {
|
||||||
_selectedOccupation = 'Students (High school & University)';
|
_selectedOccupation = null;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset country region form screen
|
// Reset country region form screen
|
||||||
void resetCountryRegionFormScreen() {
|
void resetCountryRegionFormScreen() {
|
||||||
_focusRegion = false;
|
_focusRegion = false;
|
||||||
_selectedCountry = 'Ethiopia';
|
_selectedRegion = null;
|
||||||
_selectedRegion = 'Addis Ababa';
|
_selectedCountry = null;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -609,26 +332,20 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
// Reset language goal form screen
|
// Reset language goal form screen
|
||||||
void resetLanguageGoalFormScreen() {
|
void resetLanguageGoalFormScreen() {
|
||||||
_focusLanguageGoal = false;
|
|
||||||
_selectedLanguageGoal = null;
|
_selectedLanguageGoal = null;
|
||||||
_showLanguageGoalTextBox = false;
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset challenge form screen
|
// Reset challenge form screen
|
||||||
void resetChallengeFormScreen() {
|
void resetChallengeFormScreen() {
|
||||||
_focusChallenge = false;
|
|
||||||
_selectedChallenge = null;
|
_selectedChallenge = null;
|
||||||
_showChallengeTextBox = false;
|
|
||||||
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset topic form screen
|
// Reset topic form screen
|
||||||
void resetTopicFormScreen() {
|
void resetTopicFormScreen() {
|
||||||
_focusTopic = false;
|
|
||||||
_selectedTopic = null;
|
_selectedTopic = null;
|
||||||
_showTopicTextBox = false;
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||||
|
|
@ -19,9 +21,7 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Future<void> _next(OnboardingViewModel viewModel) async {
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {'age_group': viewModel.selectedAgeGroup?.code};
|
||||||
'age_group': viewModel.selectedAgeGroup?.values.first
|
|
||||||
};
|
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
viewModel.next();
|
viewModel.next();
|
||||||
|
|
@ -88,17 +88,19 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'Which age range are you in?',
|
LocaleKeys.age_range.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'We’ll personalize your learning experience based on your age.',
|
LocaleKeys.age_for_personalization.tr(),
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -107,7 +109,7 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
itemCount: viewModel.ageGroups.length,
|
itemCount: viewModel.ageGroups.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildAgeGroup(
|
itemBuilder: (context, index) => _buildAgeGroup(
|
||||||
title: viewModel.ageGroups[index].keys.first,
|
title: viewModel.ageGroups[index].label ?? '',
|
||||||
selected: viewModel.isSelectedAgeGroup(viewModel.ageGroups[index]),
|
selected: viewModel.isSelectedAgeGroup(viewModel.ageGroups[index]),
|
||||||
onTap: () =>
|
onTap: () =>
|
||||||
viewModel.setSelectedAgeGroup(viewModel.ageGroups[index]),
|
viewModel.setSelectedAgeGroup(viewModel.ageGroups[index]),
|
||||||
|
|
@ -132,9 +134,9 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
backgroundColor: viewModel.selectedAgeGroup != null
|
backgroundColor: viewModel.selectedAgeGroup != null
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.form.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.form.dart';
|
||||||
|
|
@ -9,12 +11,9 @@ import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
final TextEditingController challengeController;
|
const ChallengeFormScreen({super.key});
|
||||||
|
|
||||||
const ChallengeFormScreen({super.key, required this.challengeController});
|
|
||||||
|
|
||||||
void _pop(OnboardingViewModel viewModel) {
|
void _pop(OnboardingViewModel viewModel) {
|
||||||
challengeController.clear();
|
|
||||||
viewModel.resetChallengeFormScreen();
|
viewModel.resetChallengeFormScreen();
|
||||||
viewModel.goBack();
|
viewModel.goBack();
|
||||||
}
|
}
|
||||||
|
|
@ -23,8 +22,7 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'language_challange':
|
'language_challange': viewModel.selectedChallenge?.code,
|
||||||
viewModel.selectedChallenge ?? challengeController.text,
|
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
|
@ -86,15 +84,6 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
_buildSubtitle(),
|
_buildSubtitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildChallenges(viewModel),
|
_buildChallenges(viewModel),
|
||||||
if (viewModel.showChallengeTextBox) _buildChallengeFormField(viewModel),
|
|
||||||
if (viewModel.showChallengeTextBox &&
|
|
||||||
viewModel.hasChallengeValidationMessage &&
|
|
||||||
viewModel.focusChallenge)
|
|
||||||
verticalSpaceTiny,
|
|
||||||
if (viewModel.showChallengeTextBox &&
|
|
||||||
viewModel.hasChallengeValidationMessage &&
|
|
||||||
viewModel.focusChallenge)
|
|
||||||
_buildChallengeValidatorWrapper(viewModel),
|
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -102,17 +91,19 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'What challenge do you face most with English?',
|
LocaleKeys.challenge_you_face.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'Everyone has struggles, let’s start fixing yours 😊',
|
'${LocaleKeys.evey_one_has_strugle.tr()} 😊',
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -122,7 +113,7 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
itemCount: viewModel.challenges.length,
|
itemCount: viewModel.challenges.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildChallenge(
|
itemBuilder: (context, index) => _buildChallenge(
|
||||||
title: viewModel.challenges[index],
|
title: viewModel.challenges[index].label ?? '',
|
||||||
onTap: () =>
|
onTap: () =>
|
||||||
viewModel.setSelectedChallenge(viewModel.challenges[index]),
|
viewModel.setSelectedChallenge(viewModel.challenges[index]),
|
||||||
selected: viewModel.isSelectedChallenge(viewModel.challenges[index]),
|
selected: viewModel.isSelectedChallenge(viewModel.challenges[index]),
|
||||||
|
|
@ -139,27 +130,6 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
selected: selected,
|
selected: selected,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildChallengeFormField(OnboardingViewModel viewModel) =>
|
|
||||||
TextFormField(
|
|
||||||
maxLines: 3,
|
|
||||||
controller: challengeController,
|
|
||||||
onTap: viewModel.setChallengesFocus,
|
|
||||||
decoration: inputDecoration(
|
|
||||||
focus: true,
|
|
||||||
hint: 'Write your challenge…',
|
|
||||||
filled: challengeController.text.isNotEmpty),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildChallengeValidatorWrapper(OnboardingViewModel viewModel) =>
|
|
||||||
viewModel.hasChallengeValidationMessage
|
|
||||||
? _buildChallengeValidator(viewModel)
|
|
||||||
: Container();
|
|
||||||
|
|
||||||
Widget _buildChallengeValidator(OnboardingViewModel viewModel) => Text(
|
|
||||||
viewModel.challengeValidationMessage!,
|
|
||||||
style: style12R700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
|
|
@ -168,21 +138,13 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
onTap: viewModel.selectedChallenge != null
|
onTap: viewModel.selectedChallenge != null
|
||||||
? viewModel.selectedChallenge?.toLowerCase() == 'other'
|
? () => _next(viewModel)
|
||||||
? challengeController.text.isNotEmpty
|
|
||||||
? () => _next(viewModel)
|
|
||||||
: null
|
|
||||||
: () => _next(viewModel)
|
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedChallenge != null
|
backgroundColor: viewModel.selectedChallenge != null
|
||||||
? viewModel.selectedChallenge?.toLowerCase() == 'other'
|
? kcPrimaryColor
|
||||||
? challengeController.text.isNotEmpty
|
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1)
|
|
||||||
: kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1));
|
: kcPrimaryColor.withOpacity(0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_dropdown.dart';
|
import 'package:yimaru_app/ui/widgets/custom_dropdown.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
import '../../../../models/field_option.dart';
|
||||||
import '../onboarding_view.form.dart';
|
import '../onboarding_view.form.dart';
|
||||||
|
|
||||||
class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
@ -13,10 +16,10 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
const CountryRegionFormScreen({super.key, required this.regionController});
|
const CountryRegionFormScreen({super.key, required this.regionController});
|
||||||
|
|
||||||
void _setSelectedCountry(
|
void _setSelectedCountry(
|
||||||
{String? value, required OnboardingViewModel viewModel}) {
|
{FieldOption? value, required OnboardingViewModel viewModel}) {
|
||||||
viewModel.setSelectedCountry(value ?? 'Ethiopia');
|
viewModel.setSelectedCountry(value);
|
||||||
|
|
||||||
if (viewModel.selectedCountry != 'Ethiopia') {
|
if (viewModel.selectedCountry?.label?.toLowerCase().tr() != 'ethiopia') {
|
||||||
regionController.clear();
|
regionController.clear();
|
||||||
viewModel.unsetRegionFocus();
|
viewModel.unsetRegionFocus();
|
||||||
}
|
}
|
||||||
|
|
@ -32,9 +35,9 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'region': viewModel.dropdownRegion
|
'region': viewModel.dropdownRegion
|
||||||
? viewModel.selectedRegion
|
? viewModel.selectedRegion?.code
|
||||||
: regionController.text,
|
: regionController.text,
|
||||||
'country': viewModel.selectedCountry,
|
'country': viewModel.selectedCountry?.code,
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
|
@ -112,26 +115,28 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'Where are you from?',
|
LocaleKeys.location.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'Select your country and region from the dropdown',
|
LocaleKeys.select_country_region.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildCountryDropDown(OnboardingViewModel viewModel) =>
|
Widget _buildCountryDropDown(OnboardingViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
CustomDropdownPicker(
|
||||||
hint: 'Select country',
|
|
||||||
icon: _buildSearchIcon(),
|
icon: _buildSearchIcon(),
|
||||||
|
hint: LocaleKeys.select_country.tr(),
|
||||||
selectedItem: viewModel.selectedCountry,
|
selectedItem: viewModel.selectedCountry,
|
||||||
items: (value, props) => viewModel.getCountries(),
|
items: (value, props) => viewModel.countries,
|
||||||
onChanged: (value) =>
|
onChanged: (value) =>
|
||||||
_setSelectedCountry(value: value, viewModel: viewModel));
|
_setSelectedCountry(value: value, viewModel: viewModel));
|
||||||
|
|
||||||
|
|
@ -142,19 +147,18 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
Widget _buildRegionDropDown(OnboardingViewModel viewModel) =>
|
Widget _buildRegionDropDown(OnboardingViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
CustomDropdownPicker(
|
||||||
hint: 'Select region',
|
|
||||||
icon: _buildSearchIcon(),
|
icon: _buildSearchIcon(),
|
||||||
|
hint: LocaleKeys.select_region.tr(),
|
||||||
selectedItem: viewModel.selectedRegion,
|
selectedItem: viewModel.selectedRegion,
|
||||||
items: (value, props) => viewModel.getRegions(),
|
items: (value, props) => viewModel.regions,
|
||||||
onChanged: (value) =>
|
onChanged: (value) => viewModel.setSelectedRegion(value));
|
||||||
viewModel.setSelectedRegion(value ?? 'Addis Ababa'));
|
|
||||||
|
|
||||||
Widget _buildRegionFormField(OnboardingViewModel viewModel) => TextFormField(
|
Widget _buildRegionFormField(OnboardingViewModel viewModel) => TextFormField(
|
||||||
controller: regionController,
|
controller: regionController,
|
||||||
onTap: viewModel.setRegionFocus,
|
onTap: viewModel.setRegionFocus,
|
||||||
decoration: inputDecoration(
|
decoration: inputDecoration(
|
||||||
hint: 'Enter Your City',
|
|
||||||
focus: viewModel.focusRegion,
|
focus: viewModel.focusRegion,
|
||||||
|
hint: LocaleKeys.enter_your_city.tr(),
|
||||||
filled: regionController.text.isNotEmpty),
|
filled: regionController.text.isNotEmpty),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -181,18 +185,26 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: !viewModel.dropdownRegion
|
text: LocaleKeys.cont.tr(),
|
||||||
? regionController.text.isNotEmpty
|
onTap: viewModel.selectedCountry != null
|
||||||
? () => _next(viewModel)
|
? !viewModel.dropdownRegion
|
||||||
: null
|
? regionController.text.isNotEmpty
|
||||||
: () => _next(viewModel),
|
? () => _next(viewModel)
|
||||||
backgroundColor: !viewModel.dropdownRegion
|
: null
|
||||||
? regionController.text.isNotEmpty
|
: viewModel.selectedRegion != null
|
||||||
? kcPrimaryColor
|
? () => _next(viewModel)
|
||||||
: kcPrimaryColor.withOpacity(0.1)
|
: null
|
||||||
: kcPrimaryColor,
|
: null,
|
||||||
|
backgroundColor: viewModel.selectedCountry != null
|
||||||
|
? !viewModel.dropdownRegion
|
||||||
|
? regionController.text.isNotEmpty
|
||||||
|
? kcPrimaryColor
|
||||||
|
: kcPrimaryColor.withOpacity(0.1)
|
||||||
|
: viewModel.selectedRegion != null
|
||||||
|
? kcPrimaryColor
|
||||||
|
: kcPrimaryColor.withOpacity(0.1)
|
||||||
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||||
|
|
@ -20,7 +22,7 @@ class EducationalBackgroundFormScreen
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'education_level': viewModel.selectedEducationalBackground
|
'education_level': viewModel.selectedEducationalBackground?.code
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
|
@ -88,22 +90,20 @@ class EducationalBackgroundFormScreen
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => Text(
|
||||||
'What’s your current educational level?',
|
LocaleKeys.educational_background.tr(),
|
||||||
style: TextStyle(
|
style: style25DG600,
|
||||||
fontSize: 25,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => const Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'This helps us tailor your lessons to your experience.',
|
LocaleKeys.education_for_personalization.tr(),
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildEducationalLevels(OnboardingViewModel viewModel) =>
|
Widget _buildEducationalLevels(OnboardingViewModel viewModel) =>
|
||||||
|
|
@ -112,7 +112,7 @@ class EducationalBackgroundFormScreen
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemCount: viewModel.educationalBackgrounds.length,
|
itemCount: viewModel.educationalBackgrounds.length,
|
||||||
itemBuilder: (context, index) => _buildEducationalLevel(
|
itemBuilder: (context, index) => _buildEducationalLevel(
|
||||||
title: viewModel.educationalBackgrounds[index],
|
title: viewModel.educationalBackgrounds[index].label ?? '',
|
||||||
selected: viewModel.isSelectedEducationalBackground(
|
selected: viewModel.isSelectedEducationalBackground(
|
||||||
viewModel.educationalBackgrounds[index]),
|
viewModel.educationalBackgrounds[index]),
|
||||||
onTap: () => viewModel.setSelectedEducationalBackground(
|
onTap: () => viewModel.setSelectedEducationalBackground(
|
||||||
|
|
@ -138,9 +138,9 @@ class EducationalBackgroundFormScreen
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
onTap: viewModel.selectedEducationalBackground != null
|
onTap: viewModel.selectedEducationalBackground != null
|
||||||
? () => _next(viewModel)
|
? () => _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
|
|
|
||||||
|
|
@ -90,18 +90,20 @@ class FullNameFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'${LocaleKeys.what_should_we_call_you.tr()} 😊',
|
'${LocaleKeys.what_should_we_call_you.tr()} 😊',
|
||||||
style:style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
LocaleKeys.name_for_personalization.tr(),
|
LocaleKeys.name_for_personalization.tr(),
|
||||||
style:style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildFullNameFormField(OnboardingViewModel viewModel) =>
|
Widget _buildFullNameFormField(OnboardingViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,10 @@ class GenderFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
|
|
@ -98,14 +100,22 @@ class GenderFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
Widget _buildAgeGroups(OnboardingViewModel viewModel) => ListView.builder(
|
Widget _buildAgeGroups(OnboardingViewModel viewModel) => ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: viewModel.selectedLanguage['code'] == 'አማ'
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: viewModel.selectedLanguage['code'] == 'am'
|
||||||
? viewModel.gendersAm.length
|
? viewModel.gendersAm.length
|
||||||
: viewModel.gendersEn.length,
|
: viewModel.gendersEn.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) => _buildAgeGroup(
|
itemBuilder: (context, index) => _buildAgeGroup(
|
||||||
title:viewModel.selectedLanguage['code'] == 'አማ' ? viewModel.gendersAm[index]:viewModel.gendersEn[index],
|
selected: viewModel.isSelectedGender(
|
||||||
selected: viewModel.isSelectedGender(viewModel.selectedLanguage['code'] == 'አማ' ? viewModel.gendersAm[index]: viewModel.gendersEn[index]),
|
viewModel.selectedLanguage['code'] == 'am'
|
||||||
onTap: () => viewModel.setSelectedGender(viewModel.selectedLanguage['code'] == 'አማ' ? viewModel.gendersAm[index]: viewModel.gendersEn[index]),
|
? viewModel.gendersAm[index]
|
||||||
|
: viewModel.gendersEn[index]),
|
||||||
|
onTap: () => viewModel.setSelectedGender(
|
||||||
|
viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? viewModel.gendersAm[index]
|
||||||
|
: viewModel.gendersEn[index]),
|
||||||
|
title: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? viewModel.gendersAm[index]
|
||||||
|
: viewModel.gendersEn[index],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.form.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.form.dart';
|
||||||
|
|
@ -9,13 +11,9 @@ import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
final TextEditingController languageGoalController;
|
const LanguageGoalFormScreen({super.key});
|
||||||
|
|
||||||
const LanguageGoalFormScreen(
|
|
||||||
{super.key, required this.languageGoalController});
|
|
||||||
|
|
||||||
void _pop(OnboardingViewModel viewModel) {
|
void _pop(OnboardingViewModel viewModel) {
|
||||||
languageGoalController.clear();
|
|
||||||
viewModel.resetLanguageGoalFormScreen();
|
viewModel.resetLanguageGoalFormScreen();
|
||||||
viewModel.goBack();
|
viewModel.goBack();
|
||||||
}
|
}
|
||||||
|
|
@ -24,8 +22,7 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'language_goal':
|
'language_goal': viewModel.selectedLanguageGoal?.code,
|
||||||
viewModel.selectedLanguageGoal ?? languageGoalController.text,
|
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
|
@ -87,15 +84,6 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
_buildSubtitle(),
|
_buildSubtitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildReasons(viewModel),
|
_buildReasons(viewModel),
|
||||||
if (viewModel.showLanguageGoalTextBox) _buildReasonFormField(viewModel),
|
|
||||||
if (viewModel.showLanguageGoalTextBox &&
|
|
||||||
viewModel.hasLanguageGoalValidationMessage &&
|
|
||||||
viewModel.focusLanguageGoal)
|
|
||||||
verticalSpaceTiny,
|
|
||||||
if (viewModel.showLanguageGoalTextBox &&
|
|
||||||
viewModel.hasLanguageGoalValidationMessage &&
|
|
||||||
viewModel.focusLanguageGoal)
|
|
||||||
_buildReasonValidatorWrapper(viewModel),
|
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -103,17 +91,19 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'What’s your main goal for improving your English?',
|
LocaleKeys.language_goal.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'Your goal helps us tailor your learning journey.',
|
LocaleKeys.your_goal.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -123,7 +113,7 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
itemCount: viewModel.languageGoals.length,
|
itemCount: viewModel.languageGoals.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildLanguageGoal(
|
itemBuilder: (context, index) => _buildLanguageGoal(
|
||||||
title: viewModel.languageGoals[index],
|
title: viewModel.languageGoals[index].label ?? '',
|
||||||
selected:
|
selected:
|
||||||
viewModel.isSelectedLanguageGoal(viewModel.languageGoals[index]),
|
viewModel.isSelectedLanguageGoal(viewModel.languageGoals[index]),
|
||||||
onTap: () =>
|
onTap: () =>
|
||||||
|
|
@ -141,26 +131,6 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
selected: selected,
|
selected: selected,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildReasonFormField(OnboardingViewModel viewModel) => TextFormField(
|
|
||||||
maxLines: 3,
|
|
||||||
controller: languageGoalController,
|
|
||||||
onTap: viewModel.setLanguageGoalFocus,
|
|
||||||
decoration: inputDecoration(
|
|
||||||
focus: true,
|
|
||||||
hint: 'Write your goal…',
|
|
||||||
filled: languageGoalController.text.isNotEmpty),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildReasonValidatorWrapper(OnboardingViewModel viewModel) =>
|
|
||||||
viewModel.hasLanguageGoalValidationMessage
|
|
||||||
? _buildReasonValidator(viewModel)
|
|
||||||
: Container();
|
|
||||||
|
|
||||||
Widget _buildReasonValidator(OnboardingViewModel viewModel) => Text(
|
|
||||||
viewModel.languageGoalValidationMessage!,
|
|
||||||
style: style12R700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
|
|
@ -169,21 +139,13 @@ class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
onTap: viewModel.selectedLanguageGoal != null
|
onTap: viewModel.selectedLanguageGoal != null
|
||||||
? viewModel.selectedLanguageGoal?.toLowerCase() == 'other'
|
? () => _next(viewModel)
|
||||||
? languageGoalController.text.isNotEmpty
|
|
||||||
? () => _next(viewModel)
|
|
||||||
: null
|
|
||||||
: () => _next(viewModel)
|
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedLanguageGoal != null
|
backgroundColor: viewModel.selectedLanguageGoal != null
|
||||||
? viewModel.selectedLanguageGoal?.toLowerCase() == 'other'
|
? kcPrimaryColor
|
||||||
? languageGoalController.text.isNotEmpty
|
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1)
|
|
||||||
: kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1));
|
: kcPrimaryColor.withOpacity(0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:iconsax/iconsax.dart';
|
import 'package:iconsax/iconsax.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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||||
|
|
@ -32,7 +34,7 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'learning_goal': viewModel.selectedLearningGoal,
|
'learning_goal': viewModel.selectedLearningGoal?.code,
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
|
@ -98,17 +100,20 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle(OnboardingViewModel viewModel) => Text.rich(
|
Widget _buildTitle(OnboardingViewModel viewModel) => Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Hi ${viewModel.userData['first_name']},',
|
text:
|
||||||
|
'${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},',
|
||||||
style: style18P600.copyWith(fontSize: 22),
|
style: style18P600.copyWith(fontSize: 22),
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' Choose your learning goal.',
|
text: ' ${LocaleKeys.learning_goal.tr()}',
|
||||||
style: style16DG600.copyWith(fontSize: 22),
|
style: style16DG600.copyWith(fontSize: 22),
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
|
|
@ -119,27 +124,21 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
itemCount: viewModel.learningGoals.length,
|
itemCount: viewModel.learningGoals.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildLearningGoal(
|
itemBuilder: (context, index) => _buildLearningGoal(
|
||||||
title: viewModel.learningGoals[index]['title'],
|
title: viewModel.learningGoals[index].label ?? '',
|
||||||
icon: getIcon(viewModel.learningGoals[index]['icon']),
|
selected:
|
||||||
subtitle: viewModel.learningGoals[index]['subtitle'],
|
viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]),
|
||||||
selected: viewModel
|
onTap: () =>
|
||||||
.isSelectedLearningGoal(viewModel.learningGoals[index]['title']),
|
viewModel.setSelectedLearningGoal(viewModel.learningGoals[index]),
|
||||||
onTap: () => viewModel
|
|
||||||
.setSelectedLearningGoal(viewModel.learningGoals[index]['title']),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLearningGoal(
|
Widget _buildLearningGoal(
|
||||||
{required String title,
|
{required String title,
|
||||||
required bool selected,
|
required bool selected,
|
||||||
required IconData icon,
|
|
||||||
required String subtitle,
|
|
||||||
required GestureTapCallback onTap}) =>
|
required GestureTapCallback onTap}) =>
|
||||||
CustomLargeRadioButton(
|
CustomLargeRadioButton(
|
||||||
icon: icon,
|
|
||||||
title: title,
|
title: title,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
subtitle: subtitle,
|
|
||||||
selected: selected,
|
selected: selected,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -151,9 +150,9 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
onTap: viewModel.selectedLearningGoal != null
|
onTap: viewModel.selectedLearningGoal != null
|
||||||
? () => _next(viewModel)
|
? () => _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
|
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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||||
|
|
@ -19,7 +21,9 @@ class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Future<void> _next(OnboardingViewModel viewModel) async {
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
Map<String, dynamic> data = {'occupation': viewModel.selectedOccupation};
|
Map<String, dynamic> data = {
|
||||||
|
'occupation': viewModel.selectedOccupation?.code
|
||||||
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
viewModel.next();
|
viewModel.next();
|
||||||
|
|
@ -86,28 +90,30 @@ class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'What’s your occupation?',
|
LocaleKeys.your_occupation.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'We’ll personalize your learning experience based on your occupation.',
|
LocaleKeys.occupation_for_personalization.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildOccupationDropdown(OnboardingViewModel viewModel) =>
|
Widget _buildOccupationDropdown(OnboardingViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
CustomDropdownPicker(
|
||||||
hint: 'Select occupation',
|
|
||||||
icon: _buildSearchIcon(),
|
icon: _buildSearchIcon(),
|
||||||
|
hint: LocaleKeys.select_occupation.tr(),
|
||||||
selectedItem: viewModel.selectedOccupation,
|
selectedItem: viewModel.selectedOccupation,
|
||||||
items: (value, props) => viewModel.getOccupations(),
|
items: (value, props) => viewModel.occupations,
|
||||||
onChanged: (value) => viewModel.setSelectedOccupation(
|
onChanged: (value) => viewModel.setSelectedOccupation(value));
|
||||||
value ?? 'Students (High school & University)'));
|
|
||||||
Icon _buildSearchIcon() => const Icon(
|
Icon _buildSearchIcon() => const Icon(
|
||||||
Icons.search,
|
Icons.search,
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
|
|
@ -120,10 +126,15 @@ class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
borderRadius: 12,
|
||||||
borderRadius: 12,
|
foregroundColor: kcWhite,
|
||||||
foregroundColor: kcWhite,
|
text: LocaleKeys.cont.tr(),
|
||||||
onTap: () => _next(viewModel),
|
onTap: viewModel.selectedOccupation != null
|
||||||
backgroundColor: kcPrimaryColor);
|
? () => _next(viewModel)
|
||||||
|
: null,
|
||||||
|
backgroundColor: viewModel.selectedOccupation != null
|
||||||
|
? kcPrimaryColor
|
||||||
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.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/translations/locale_keys.g.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.form.dart';
|
import 'package:yimaru_app/ui/views/onboarding/onboarding_view.form.dart';
|
||||||
|
|
@ -10,12 +11,9 @@ import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
final TextEditingController topicController;
|
const TopicFormScreen({super.key});
|
||||||
|
|
||||||
const TopicFormScreen({super.key, required this.topicController});
|
|
||||||
|
|
||||||
void _pop(OnboardingViewModel viewModel) {
|
void _pop(OnboardingViewModel viewModel) {
|
||||||
topicController.clear();
|
|
||||||
viewModel.resetTopicFormScreen();
|
viewModel.resetTopicFormScreen();
|
||||||
viewModel.goBack();
|
viewModel.goBack();
|
||||||
}
|
}
|
||||||
|
|
@ -26,8 +24,8 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'profile_completed': true,
|
'profile_completed': true,
|
||||||
'preferred_language': 'en',
|
'preferred_language': 'en',
|
||||||
|
'favoutite_topic': viewModel.selectedTopic?.code,
|
||||||
'birth_day': DateFormat('yyyy-MM-dd').format(DateTime.now()),
|
'birth_day': DateFormat('yyyy-MM-dd').format(DateTime.now()),
|
||||||
'favoutite_topic': viewModel.selectedTopic ?? topicController.text,
|
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
|
@ -58,8 +56,10 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
||||||
|
|
@ -97,25 +97,16 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
_buildSubtitle(),
|
_buildSubtitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTopics(viewModel),
|
_buildTopics(viewModel),
|
||||||
if (viewModel.showTopicTextBox) _buildTopicFormField(viewModel),
|
|
||||||
if (viewModel.showTopicTextBox &&
|
|
||||||
viewModel.hasTopicValidationMessage &&
|
|
||||||
viewModel.focusTopic)
|
|
||||||
verticalSpaceTiny,
|
|
||||||
if (viewModel.showTopicTextBox &&
|
|
||||||
viewModel.hasTopicValidationMessage &&
|
|
||||||
viewModel.focusTopic)
|
|
||||||
_buildTopicWrapper(viewModel),
|
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'Which topics interest you most?',
|
LocaleKeys.topic_interest.tr(),
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'Your favorite topics help us create fun, relatable lessons.',
|
LocaleKeys.favourite_topic.tr(),
|
||||||
style: style14MG400,
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -125,7 +116,7 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
itemCount: viewModel.topics.length,
|
itemCount: viewModel.topics.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildTopic(
|
itemBuilder: (context, index) => _buildTopic(
|
||||||
title: viewModel.topics[index],
|
title: viewModel.topics[index].label ?? '',
|
||||||
selected: viewModel.isSelectedTopic(viewModel.topics[index]),
|
selected: viewModel.isSelectedTopic(viewModel.topics[index]),
|
||||||
onTap: () => viewModel.setSelectedTopic(viewModel.topics[index]),
|
onTap: () => viewModel.setSelectedTopic(viewModel.topics[index]),
|
||||||
),
|
),
|
||||||
|
|
@ -141,26 +132,6 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
selected: selected,
|
selected: selected,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTopicFormField(OnboardingViewModel viewModel) => TextFormField(
|
|
||||||
maxLines: 3,
|
|
||||||
controller: topicController,
|
|
||||||
onTap: viewModel.setTopicsFocus,
|
|
||||||
decoration: inputDecoration(
|
|
||||||
focus: true,
|
|
||||||
hint: 'Write you interest…',
|
|
||||||
filled: topicController.text.isNotEmpty),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildTopicWrapper(OnboardingViewModel viewModel) =>
|
|
||||||
viewModel.hasTopicValidationMessage
|
|
||||||
? _buildTopicValidator(viewModel)
|
|
||||||
: Container();
|
|
||||||
|
|
||||||
Widget _buildTopicValidator(OnboardingViewModel viewModel) => Text(
|
|
||||||
viewModel.topicValidationMessage!,
|
|
||||||
style: style12R700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
|
|
@ -169,21 +140,13 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: LocaleKeys.cont.tr(),
|
||||||
onTap: viewModel.selectedTopic != null
|
onTap: viewModel.selectedTopic != null
|
||||||
? viewModel.selectedTopic?.toLowerCase() == 'other'
|
? () async => await _next(viewModel)
|
||||||
? topicController.text.isNotEmpty
|
|
||||||
? () async => await _next(viewModel)
|
|
||||||
: null
|
|
||||||
: () async => await _next(viewModel)
|
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedTopic != null
|
backgroundColor: viewModel.selectedTopic != null
|
||||||
? viewModel.selectedTopic?.toLowerCase() == 'other'
|
? kcPrimaryColor
|
||||||
? topicController.text.isNotEmpty
|
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1)
|
|
||||||
: kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1));
|
: kcPrimaryColor.withOpacity(0.1));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,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)
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import '../../common/app_colors.dart';
|
||||||
import '../../common/enmus.dart';
|
import '../../common/enmus.dart';
|
||||||
import '../../common/ui_helpers.dart';
|
import '../../common/ui_helpers.dart';
|
||||||
import '../../common/validators/form_validator.dart';
|
import '../../common/validators/form_validator.dart';
|
||||||
import '../../widgets/custom_dropdown.dart';
|
|
||||||
import '../../widgets/custom_elevated_button.dart';
|
import '../../widgets/custom_elevated_button.dart';
|
||||||
import '../../widgets/image_picker_option.dart';
|
import '../../widgets/image_picker_option.dart';
|
||||||
import '../../widgets/page_loading_indicator.dart';
|
import '../../widgets/page_loading_indicator.dart';
|
||||||
|
|
@ -202,7 +201,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildCountryDropdownLabel(),
|
_buildCountryDropdownLabel(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildCountryDropdown(viewModel),
|
// _buildCountryDropdown(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildRegionFormFieldWrapper(viewModel),
|
_buildRegionFormFieldWrapper(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
|
@ -527,13 +526,13 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
label: LocaleKeys.country.tr(),
|
label: LocaleKeys.country.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildCountryDropdown(ProfileDetailViewModel viewModel) =>
|
// Widget _buildCountryDropdown(ProfileDetailViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
// CustomDropdownPicker(
|
||||||
hint: 'Select country',
|
// hint: 'Select country',
|
||||||
selectedItem: viewModel.selectedCountry,
|
// selectedItem: viewModel.selectedCountry,
|
||||||
items: (value, props) => viewModel.getCountries(),
|
// items: (value, props) => viewModel.getCountries(),
|
||||||
onChanged: (value) => viewModel.setSelectedCountry(value ?? 'Ethiopia'),
|
// onChanged: (value) => viewModel.setSelectedCountry(value ?? 'Ethiopia'),
|
||||||
);
|
// );
|
||||||
|
|
||||||
Widget _buildRegionFormFieldWrapper(ProfileDetailViewModel viewModel) =>
|
Widget _buildRegionFormFieldWrapper(ProfileDetailViewModel viewModel) =>
|
||||||
Column(
|
Column(
|
||||||
|
|
@ -565,18 +564,19 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildRegionFormState(ProfileDetailViewModel viewModel) =>
|
Widget _buildRegionFormState(ProfileDetailViewModel viewModel) =>
|
||||||
viewModel.dropdownRegion
|
// viewModel.dropdownRegion
|
||||||
? _buildRegionDropDown(viewModel)
|
// ? _buildRegionDropDown(viewModel)
|
||||||
: _buildRegionFormField(viewModel);
|
// :
|
||||||
|
_buildRegionFormField(viewModel);
|
||||||
Widget _buildRegionDropDown(ProfileDetailViewModel viewModel) =>
|
//
|
||||||
CustomDropdownPicker(
|
// Widget _buildRegionDropDown(ProfileDetailViewModel viewModel) =>
|
||||||
icon: _buildSearchIcon(),
|
// CustomDropdownPicker(
|
||||||
hint:LocaleKeys.select_region.tr(),
|
// icon: _buildSearchIcon(),
|
||||||
selectedItem: viewModel.selectedRegion,
|
// hint:LocaleKeys.select_region.tr(),
|
||||||
items: (value, props) => viewModel.getRegions(),
|
// selectedItem: viewModel.selectedRegion,
|
||||||
onChanged: (value) =>
|
// items: (value, props) => viewModel.getRegions(),
|
||||||
viewModel.setSelectedRegion(value ?? 'Addis Ababa'));
|
// onChanged: (value) =>
|
||||||
|
// viewModel.setSelectedRegion(value ?? 'Addis Ababa'));
|
||||||
|
|
||||||
Widget _buildRegionFormField(ProfileDetailViewModel viewModel) =>
|
Widget _buildRegionFormField(ProfileDetailViewModel viewModel) =>
|
||||||
TextFormField(
|
TextFormField(
|
||||||
|
|
@ -584,7 +584,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
onTap: viewModel.setRegionFocus,
|
onTap: viewModel.setRegionFocus,
|
||||||
decoration: inputDecoration(
|
decoration: inputDecoration(
|
||||||
focus: viewModel.focusRegion,
|
focus: viewModel.focusRegion,
|
||||||
hint:LocaleKeys.enter_your_city.tr(),
|
hint: LocaleKeys.enter_your_city.tr(),
|
||||||
filled: regionController.text.isNotEmpty),
|
filled: regionController.text.isNotEmpty),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -611,7 +611,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
[
|
[
|
||||||
_buildOccupationDropdownLabel(),
|
_buildOccupationDropdownLabel(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildOccupationDropdown(viewModel)
|
// _buildOccupationDropdown(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildOccupationDropdownLabel() => CustomFormLabel(
|
Widget _buildOccupationDropdownLabel() => CustomFormLabel(
|
||||||
|
|
@ -619,14 +619,14 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
label: LocaleKeys.occupation.tr(),
|
label: LocaleKeys.occupation.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildOccupationDropdown(ProfileDetailViewModel viewModel) =>
|
// Widget _buildOccupationDropdown(ProfileDetailViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
// CustomDropdownPicker(
|
||||||
icon: _buildSearchIcon(),
|
// icon: _buildSearchIcon(),
|
||||||
hint:LocaleKeys.select_occupation.tr(),
|
// hint:LocaleKeys.select_occupation.tr(),
|
||||||
selectedItem: viewModel.selectedOccupation,
|
// selectedItem: viewModel.selectedOccupation,
|
||||||
items: (value, props) => viewModel.getOccupations(),
|
// items: (value, props) => viewModel.getOccupations(),
|
||||||
onChanged: (value) => viewModel.setSelectedOccupation(
|
// onChanged: (value) => viewModel.setSelectedOccupation(
|
||||||
value ?? 'Students (High school & University)'));
|
// value ?? 'Students (High school & University)'));
|
||||||
Icon _buildSearchIcon() => const Icon(
|
Icon _buildSearchIcon() => const Icon(
|
||||||
Icons.search,
|
Icons.search,
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
|
|
@ -663,7 +663,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
text:LocaleKeys.cancel.tr(),
|
text: LocaleKeys.cancel.tr(),
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,10 @@ class CreatePasswordScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(RegisterViewModel viewModel) =>
|
Widget _buildExpandedBody(RegisterViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,10 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody(
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,10 @@ class RegisterWithPhoneNumberScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody(
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,10 @@ class RegistrationOtpScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.goBack,
|
onPop: viewModel.goBack,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
language: viewModel.selectedLanguage['code'],
|
|
||||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
language: viewModel.selectedLanguage['code'] == 'am'
|
||||||
|
? 'አማ'
|
||||||
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody(
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
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/authentication_service.dart';
|
import 'package:yimaru_app/services/authentication_service.dart';
|
||||||
|
import 'package:yimaru_app/services/onboarding_service.dart';
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../app/app.router.dart';
|
import '../../../app/app.router.dart';
|
||||||
|
|
@ -14,15 +15,22 @@ import '../../common/enmus.dart';
|
||||||
class StartupViewModel extends ReactiveViewModel {
|
class StartupViewModel extends ReactiveViewModel {
|
||||||
// Dependency injection
|
// Dependency injection
|
||||||
final _apiService = locator<ApiService>();
|
final _apiService = locator<ApiService>();
|
||||||
|
|
||||||
final _statusChecker = locator<StatusCheckerService>();
|
final _statusChecker = locator<StatusCheckerService>();
|
||||||
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
|
final _onboardingService = locator<OnboardingService>();
|
||||||
|
|
||||||
final _localizationService = locator<LocalizationService>();
|
final _localizationService = locator<LocalizationService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
final _imageDownloaderService = locator<ImageDownloaderService>();
|
final _imageDownloaderService = locator<ImageDownloaderService>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
List<ListenableServiceMixin> get listenableServices =>
|
||||||
[_authenticationService];
|
[_onboardingService, _authenticationService];
|
||||||
|
|
||||||
// Current user
|
// Current user
|
||||||
User? get _user => _authenticationService.user;
|
User? get _user => _authenticationService.user;
|
||||||
|
|
@ -81,7 +89,7 @@ class StartupViewModel extends ReactiveViewModel {
|
||||||
response = {'data': true, 'status': ResponseStatus.success};
|
response = {'data': true, 'status': ResponseStatus.success};
|
||||||
}
|
}
|
||||||
if (response['status'] == ResponseStatus.success && !response['data']) {
|
if (response['status'] == ResponseStatus.success && !response['data']) {
|
||||||
await replaceWithOnboarding();
|
await etOnboardingFields();
|
||||||
} else if (response['status'] == ResponseStatus.success &&
|
} else if (response['status'] == ResponseStatus.success &&
|
||||||
response['data']) {
|
response['data']) {
|
||||||
await saveProfileStatus(response['data']);
|
await saveProfileStatus(response['data']);
|
||||||
|
|
@ -122,4 +130,16 @@ class StartupViewModel extends ReactiveViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remote api call
|
||||||
|
|
||||||
|
// Onboarding fields
|
||||||
|
Future<void> etOnboardingFields() async {
|
||||||
|
bool response = await _onboardingService.getOnboardingFields();
|
||||||
|
if (response) {
|
||||||
|
await replaceWithOnboarding();
|
||||||
|
} else {
|
||||||
|
await replaceWithFailure();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,8 @@ class SupportView extends StackedView<SupportViewModel> {
|
||||||
Widget _buildAppbar(SupportViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(SupportViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
title:LocaleKeys.need_help.tr(),
|
title: LocaleKeys.need_help.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(SupportViewModel viewModel) =>
|
Widget _buildContentWrapper(SupportViewModel viewModel) =>
|
||||||
Expanded(child: _buildContentColumnWrapper(viewModel));
|
Expanded(child: _buildContentColumnWrapper(viewModel));
|
||||||
|
|
@ -87,7 +87,7 @@ class SupportView extends StackedView<SupportViewModel> {
|
||||||
Widget _buildCallSupport(SupportViewModel viewModel) => SupportCard(
|
Widget _buildCallSupport(SupportViewModel viewModel) => SupportCard(
|
||||||
icon: Icons.call,
|
icon: Icons.call,
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
title:LocaleKeys.call_support.tr(),
|
title: LocaleKeys.call_support.tr(),
|
||||||
subtitle: LocaleKeys.talk_with_support.tr(),
|
subtitle: LocaleKeys.talk_with_support.tr(),
|
||||||
onTap: () async => await viewModel.navigateToCallSupport(),
|
onTap: () async => await viewModel.navigateToCallSupport(),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -135,11 +135,14 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
|
||||||
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
||||||
|
|
||||||
Widget _buildSearchText() => Text.rich(
|
Widget _buildSearchText() => Text.rich(
|
||||||
TextSpan(text: LocaleKeys.search_for.tr(), style: style14DG500, children: [
|
TextSpan(
|
||||||
TextSpan(
|
text: LocaleKeys.search_for.tr(),
|
||||||
style: style14P600,
|
style: style14DG500,
|
||||||
text: ' $kTelegramSupport',
|
children: [
|
||||||
)
|
TextSpan(
|
||||||
]),
|
style: style14P600,
|
||||||
|
text: ' $kTelegramSupport',
|
||||||
|
)
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,10 +58,10 @@ class CancelLearnPracticeSheet extends StatelessWidget {
|
||||||
style: style18DG700,
|
style: style18DG700,
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' $user',
|
text: ' $user',
|
||||||
style: style18P600,
|
style: style18P600,
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,15 @@ import 'package:flutter/material.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/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
|
||||||
|
import '../../models/field_option.dart';
|
||||||
|
|
||||||
class CustomDropdownPicker extends StatelessWidget {
|
class CustomDropdownPicker extends StatelessWidget {
|
||||||
final Icon? icon;
|
final Icon? icon;
|
||||||
final String hint;
|
final String hint;
|
||||||
final String selectedItem;
|
final FieldOption? selectedItem;
|
||||||
final void Function(String?)? onChanged;
|
final void Function(FieldOption?)? onChanged;
|
||||||
final FutureOr<List<String>> Function(String value, LoadProps? props)? items;
|
final FutureOr<List<FieldOption>> Function(String value, LoadProps? props)?
|
||||||
|
items;
|
||||||
|
|
||||||
const CustomDropdownPicker(
|
const CustomDropdownPicker(
|
||||||
{super.key,
|
{super.key,
|
||||||
|
|
@ -28,16 +31,18 @@ class CustomDropdownPicker extends StatelessWidget {
|
||||||
child: _buildDropDownSearch(),
|
child: _buildDropDownSearch(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildDropDownSearch() => DropdownSearch<String>(
|
Widget _buildDropDownSearch() => DropdownSearch<FieldOption>(
|
||||||
|
onChanged: onChanged,
|
||||||
popupProps: _popupProps(),
|
popupProps: _popupProps(),
|
||||||
selectedItem: selectedItem,
|
selectedItem: selectedItem,
|
||||||
onChanged: (value) => onChanged!(value),
|
itemAsString: (item) => item.label ?? '',
|
||||||
decoratorProps: _dropDownDecoratorProps(),
|
decoratorProps: _dropDownDecoratorProps(),
|
||||||
|
compareFn: (item1, item2) => item1.label == item2.label,
|
||||||
|
items: (value, properties) => items!(value, properties),
|
||||||
dropdownBuilder: (context, value) => _buildDropdownBuilder(value),
|
dropdownBuilder: (context, value) => _buildDropdownBuilder(value),
|
||||||
items: (value, properties) async => await items!(value, properties),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
PopupProps<String> _popupProps() => PopupProps.menu(
|
PopupProps<FieldOption> _popupProps() => PopupProps<FieldOption>.menu(
|
||||||
showSearchBox: true,
|
showSearchBox: true,
|
||||||
showSelectedItems: true,
|
showSelectedItems: true,
|
||||||
searchFieldProps: _searchFieldProps(),
|
searchFieldProps: _searchFieldProps(),
|
||||||
|
|
@ -57,25 +62,25 @@ class CustomDropdownPicker extends StatelessWidget {
|
||||||
InputDecoration _popUpDecoration() => InputDecoration(
|
InputDecoration _popUpDecoration() => InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
hintStyle: style14DG400,
|
hintStyle: style14DG400,
|
||||||
fillColor: kcTransparent,
|
|
||||||
errorBorder: searchBorder,
|
errorBorder: searchBorder,
|
||||||
focusedBorder: searchBorder,
|
focusedBorder: searchBorder,
|
||||||
enabledBorder: searchBorder,
|
enabledBorder: searchBorder,
|
||||||
disabledBorder: searchBorder,
|
disabledBorder: searchBorder,
|
||||||
focusedErrorBorder: searchBorder,
|
focusedErrorBorder: searchBorder,
|
||||||
|
fillColor: const Color(0xfff5e9f4),
|
||||||
contentPadding: const EdgeInsets.only(top: 12),
|
contentPadding: const EdgeInsets.only(top: 12),
|
||||||
prefixIcon: icon != null ? _buildPrefixIcon() : null,
|
prefixIcon: icon != null ? _buildPrefixIcon() : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPopupProsBuilderWrapper(String value) => Padding(
|
Widget _buildPopupProsBuilderWrapper(FieldOption value) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
child: _buildPopupProsBuilder(value),
|
child: _buildPopupProsBuilder(value),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPopupProsBuilder(String value) => Text(
|
Widget _buildPopupProsBuilder(FieldOption value) => Text(
|
||||||
value,
|
value.label ?? '',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: const TextStyle(color: kcDarkGrey, fontSize: 14),
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
DropDownDecoratorProps _dropDownDecoratorProps() => DropDownDecoratorProps(
|
DropDownDecoratorProps _dropDownDecoratorProps() => DropDownDecoratorProps(
|
||||||
|
|
@ -91,7 +96,7 @@ class CustomDropdownPicker extends StatelessWidget {
|
||||||
focusedBorder: border,
|
focusedBorder: border,
|
||||||
enabledBorder: border,
|
enabledBorder: border,
|
||||||
disabledBorder: border,
|
disabledBorder: border,
|
||||||
hintStyle: style14LG400,
|
hintStyle: style14MG400,
|
||||||
fillColor: kcPrimaryColor.withOpacity(0.1),
|
fillColor: kcPrimaryColor.withOpacity(0.1),
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
const EdgeInsets.symmetric(vertical: 10, horizontal: 15),
|
||||||
|
|
@ -102,8 +107,8 @@ class CustomDropdownPicker extends StatelessWidget {
|
||||||
child: icon,
|
child: icon,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildDropdownBuilder(String? value) => Text(
|
Widget _buildDropdownBuilder(FieldOption? value) => Text(
|
||||||
value ?? hint,
|
value?.label ?? '',
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,20 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
class CustomLargeRadioButton extends StatelessWidget {
|
class CustomLargeRadioButton extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final bool selected;
|
final bool selected;
|
||||||
final IconData icon;
|
|
||||||
final String subtitle;
|
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback? onTap;
|
||||||
|
|
||||||
const CustomLargeRadioButton(
|
const CustomLargeRadioButton({
|
||||||
{super.key,
|
super.key,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.icon,
|
required this.selected,
|
||||||
required this.selected,
|
});
|
||||||
required this.subtitle});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => _buildButtonWrapper();
|
Widget build(BuildContext context) => _buildButtonWrapper();
|
||||||
|
|
||||||
Widget _buildButtonWrapper() => Container(
|
Widget _buildButtonWrapper() => Container(
|
||||||
height: 125,
|
height: 75,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: _buildContainerWrapper(),
|
child: _buildContainerWrapper(),
|
||||||
|
|
@ -41,39 +38,24 @@ class CustomLargeRadioButton extends StatelessWidget {
|
||||||
color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75),
|
color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: _buildButtonColumnWrapper(),
|
child: _buildButtonRowWrapper(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonColumnWrapper() => Column(
|
Widget _buildButtonRowWrapper() => Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildButtonRowChildren(),
|
children: _buildButtonRowChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildButtonRowChildren() =>
|
List<Widget> _buildButtonRowChildren() =>
|
||||||
[_buildIconSectionWrapper(), _buildTitle(), _buildSubtitle()];
|
[_buildTitleWrapper(), _buildSelectedCheckBox()];
|
||||||
|
|
||||||
Widget _buildIconSectionWrapper() => Row(
|
Widget _buildTitleWrapper() => Expanded(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
child: _buildTitle(),
|
||||||
children: _buildIconSectionChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildIconSectionChildren() =>
|
|
||||||
[_buildLeadingIcon(), _buildSelectedCheckBox()];
|
|
||||||
|
|
||||||
Widget _buildLeadingIcon() => Icon(
|
|
||||||
icon,
|
|
||||||
size: 25,
|
|
||||||
color: kcPrimaryColor,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
title,
|
title,
|
||||||
style: style18DG700,
|
maxLines: 1,
|
||||||
);
|
style: style16DG400,
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
subtitle,
|
|
||||||
style: const TextStyle(color: kcMediumGrey),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSelectedCheckBox() => Checkbox(
|
Widget _buildSelectedCheckBox() => Checkbox(
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,26 @@ import 'custom_elevated_button.dart';
|
||||||
class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
||||||
final LearnCourse course;
|
final LearnCourse course;
|
||||||
final GestureTapCallback? onViewTap;
|
final GestureTapCallback? onViewTap;
|
||||||
|
final GestureTapCallback? onLockTap;
|
||||||
final GestureTapCallback? onPracticeTap;
|
final GestureTapCallback? onPracticeTap;
|
||||||
|
|
||||||
const LearnCourseTile({
|
const LearnCourseTile({
|
||||||
super.key,
|
super.key,
|
||||||
this.onViewTap,
|
this.onViewTap,
|
||||||
|
this.onLockTap,
|
||||||
this.onPracticeTap,
|
this.onPracticeTap,
|
||||||
required this.course,
|
required this.course,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnCourseViewModel viewModel) =>
|
Widget build(BuildContext context, LearnCourseViewModel viewModel) =>
|
||||||
_buildExpansionTileCard(viewModel);
|
_buildExpansionTileCardWrapper(viewModel);
|
||||||
|
|
||||||
|
Widget _buildExpansionTileCardWrapper(LearnCourseViewModel viewModel) =>
|
||||||
|
GestureDetector(
|
||||||
|
onTap: !(course.access?.isAccessible ?? false) ? onLockTap : null,
|
||||||
|
child: _buildExpansionTileCard(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container(
|
Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container(
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
|
|
@ -109,7 +117,7 @@ class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
||||||
? _buildProgressStatus()
|
? _buildProgressStatus()
|
||||||
: Container();
|
: Container();
|
||||||
|
|
||||||
Widget _buildProgressStatus() => ProgressStatus(
|
Widget _buildProgressStatus() => ProgressStatus(
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
status: LocaleKeys.current_level.tr(),
|
status: LocaleKeys.current_level.tr(),
|
||||||
);
|
);
|
||||||
|
|
@ -147,7 +155,7 @@ class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
||||||
onTap: onViewTap,
|
onTap: onViewTap,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
text:LocaleKeys.view_course.tr(),
|
text: LocaleKeys.view_course.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPracticeButtonWrapper(LearnCourseViewModel viewModel) =>
|
Widget _buildPracticeButtonWrapper(LearnCourseViewModel viewModel) =>
|
||||||
|
|
@ -163,6 +171,6 @@ class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
text:LocaleKeys.take_practice.tr() ,
|
text: LocaleKeys.take_practice.tr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -130,7 +130,9 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildProgressText() => Text(
|
Widget _buildProgressText() => Text(
|
||||||
(lesson.access?.isCompleted ?? false) ?LocaleKeys.completed.tr() : LocaleKeys.in_progress.tr() ,
|
(lesson.access?.isCompleted ?? false)
|
||||||
|
? LocaleKeys.completed.tr()
|
||||||
|
: LocaleKeys.in_progress.tr(),
|
||||||
style: style14P600,
|
style: style14P600,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -166,7 +168,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
text:LocaleKeys.practice.tr() ,
|
text: LocaleKeys.practice.tr(),
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -182,7 +184,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
onTap: onLessonTap,
|
onTap: onLessonTap,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
text:LocaleKeys.start.tr() ,
|
text: LocaleKeys.start.tr(),
|
||||||
trailingIcon: Icons.play_arrow,
|
trailingIcon: Icons.play_arrow,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -18,10 +18,7 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
final GestureTapCallback? onPracticeTap;
|
final GestureTapCallback? onPracticeTap;
|
||||||
|
|
||||||
const LearnModuleTile(
|
const LearnModuleTile(
|
||||||
{super.key,
|
{super.key, this.onModuleTap, this.onPracticeTap, required this.module});
|
||||||
this.onModuleTap,
|
|
||||||
this.onPracticeTap,
|
|
||||||
required this.module});
|
|
||||||
|
|
||||||
Future<void> _showSheet(
|
Future<void> _showSheet(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
|
|
@ -54,7 +51,7 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
_buildExpansionTile(context: context, viewModel: viewModel),
|
_buildExpansionTile(context: context, viewModel: viewModel),
|
||||||
_buildContainerShaderState()
|
// _buildContainerShaderState()
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -73,14 +70,14 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
shape: Border.all(color: kcTransparent),
|
shape: Border.all(color: kcTransparent),
|
||||||
expandedAlignment: Alignment.centerLeft,
|
expandedAlignment: Alignment.centerLeft,
|
||||||
collapsedBackgroundColor: kcBackgroundColor,
|
collapsedBackgroundColor: kcBackgroundColor,
|
||||||
enabled: (module.access?.isAccessible ?? false),
|
//enabled: (module.access?.isAccessible ?? false),
|
||||||
controlAffinity: ListTileControlAffinity.trailing,
|
controlAffinity: ListTileControlAffinity.trailing,
|
||||||
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||||
tilePadding: const EdgeInsets.symmetric(horizontal: 15),
|
tilePadding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
childrenPadding: const EdgeInsets.fromLTRB(70, 0, 15, 15),
|
childrenPadding: const EdgeInsets.fromLTRB(70, 0, 15, 15),
|
||||||
initiallyExpanded: (module.access?.isAccessible ?? false),
|
//initiallyExpanded: (module.access?.isAccessible ?? false),
|
||||||
showTrailingIcon:
|
// showTrailingIcon:
|
||||||
!(module.access?.isAccessible ?? false) ? true : false,
|
// !(module.access?.isAccessible ?? false) ? true : false,
|
||||||
children:
|
children:
|
||||||
_buildExpansionTileChildren(context: context, viewModel: viewModel),
|
_buildExpansionTileChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
@ -211,9 +208,7 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
text:LocaleKeys.take_practice.tr(),
|
text: LocaleKeys.take_practice.tr(),
|
||||||
|
|
||||||
// onTap: () async => await viewModel.navigateToLearnPractice(practices),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSheet(LearnModuleViewModel viewModel) => FinishPracticeSheet(
|
Widget _buildSheet(LearnModuleViewModel viewModel) => FinishPracticeSheet(
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class LearnPracticeResultCard extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
Widget _buildSampleResponse() => LearnPracticeAnswerCard(
|
Widget _buildSampleResponse() => LearnPracticeAnswerCard(
|
||||||
answer: answer,
|
answer: answer,
|
||||||
voice: Voice.sample,
|
voice: Voice.sample,
|
||||||
title:LocaleKeys.sample_answer.tr() ,
|
title: LocaleKeys.sample_answer.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildActualResponseWrapper() =>
|
Widget _buildActualResponseWrapper() =>
|
||||||
|
|
@ -62,7 +62,6 @@ class LearnPracticeResultCard extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
Widget _buildActualResponse() => LearnPracticeAnswerCard(
|
Widget _buildActualResponse() => LearnPracticeAnswerCard(
|
||||||
answer: answer,
|
answer: answer,
|
||||||
voice: Voice.recorded,
|
voice: Voice.recorded,
|
||||||
title: LocaleKeys.your_answer.tr(),
|
title: LocaleKeys.your_answer.tr(),
|
||||||
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class LearnPracticeResultsWrapper
|
||||||
[_buildTitle(), verticalSpaceSmall, _buildResults(viewModel)];
|
[_buildTitle(), verticalSpaceSmall, _buildResults(viewModel)];
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
LocaleKeys.conversation_review.tr(),
|
LocaleKeys.conversation_review.tr(),
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ class LearnPracticeTipSection extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
LocaleKeys.quick_tip.tr(),
|
LocaleKeys.quick_tip.tr(),
|
||||||
style: style16B600,
|
style: style16B600,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,12 @@ import 'custom_elevated_button.dart';
|
||||||
class LearnProgramTile extends ViewModelWidget<LearnProgramViewModel> {
|
class LearnProgramTile extends ViewModelWidget<LearnProgramViewModel> {
|
||||||
final LearnProgram program;
|
final LearnProgram program;
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback? onTap;
|
||||||
final GestureTapCallback? onLockTap;
|
|
||||||
|
|
||||||
const LearnProgramTile(
|
const LearnProgramTile({super.key, this.onTap, required this.program});
|
||||||
{super.key, this.onTap, this.onLockTap, required this.program});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnProgramViewModel viewModel) =>
|
Widget build(BuildContext context, LearnProgramViewModel viewModel) =>
|
||||||
_buildExpansionTileCardWrapper(viewModel);
|
_buildExpansionTileCard(viewModel);
|
||||||
|
|
||||||
Widget _buildExpansionTileCardWrapper(LearnProgramViewModel viewModel) =>
|
|
||||||
GestureDetector(
|
|
||||||
// onTap: !(program.access?.isAccessible ?? false) ? onLockTap : null,
|
|
||||||
child: _buildExpansionTileCard(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildExpansionTileCard(LearnProgramViewModel viewModel) => Container(
|
Widget _buildExpansionTileCard(LearnProgramViewModel viewModel) => Container(
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
|
|
@ -109,7 +101,7 @@ class LearnProgramTile extends ViewModelWidget<LearnProgramViewModel> {
|
||||||
Widget _buildProgressStatus() => ProgressStatus(
|
Widget _buildProgressStatus() => ProgressStatus(
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
status: (program.access?.isCompleted ?? false)
|
status: (program.access?.isCompleted ?? false)
|
||||||
?LocaleKeys.completed.tr()
|
? LocaleKeys.completed.tr()
|
||||||
: LocaleKeys.in_progress.tr(),
|
: LocaleKeys.in_progress.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -134,6 +126,6 @@ class LearnProgramTile extends ViewModelWidget<LearnProgramViewModel> {
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
text: program.access?.progressPercent == 0
|
text: program.access?.progressPercent == 0
|
||||||
? LocaleKeys.start_learning.tr()
|
? LocaleKeys.start_learning.tr()
|
||||||
:LocaleKeys.continue_learning.tr() ,
|
: LocaleKeys.continue_learning.tr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class MotivationCard extends StatelessWidget {
|
||||||
|
|
||||||
Widget _buildText() => Expanded(
|
Widget _buildText() => Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
LocaleKeys.keep_going.tr(),
|
LocaleKeys.keep_going.tr(),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class OverallProgress extends StatelessWidget {
|
||||||
[_buildProgressInfo(), _buildProgress()];
|
[_buildProgressInfo(), _buildProgress()];
|
||||||
|
|
||||||
Widget _buildProgressInfo() => Text(
|
Widget _buildProgressInfo() => Text(
|
||||||
LocaleKeys.overall_progress.tr(),
|
LocaleKeys.overall_progress.tr(),
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ class OverallProgress extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
LocaleKeys.keep_up_the_great_work.tr(),
|
LocaleKeys.keep_up_the_great_work.tr(),
|
||||||
style: style14DG500,
|
style: style14DG500,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,16 +74,19 @@ class ProfileAppBar extends StatelessWidget {
|
||||||
[_buildGreetingTitle(), _buildSubtitle()];
|
[_buildGreetingTitle(), _buildSubtitle()];
|
||||||
|
|
||||||
Widget _buildGreetingTitle() => Text.rich(
|
Widget _buildGreetingTitle() => Text.rich(
|
||||||
TextSpan(text: '${LocaleKeys.hello.tr()},', style: style14DG600, children: [
|
TextSpan(
|
||||||
TextSpan(
|
text: '${LocaleKeys.hello.tr()},',
|
||||||
text: ' $name!',
|
style: style14DG600,
|
||||||
style: style14P600,
|
children: [
|
||||||
)
|
TextSpan(
|
||||||
]),
|
text: ' $name!',
|
||||||
|
style: style14P600,
|
||||||
|
)
|
||||||
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
LocaleKeys.ready_to_learn.tr(),
|
LocaleKeys.ready_to_learn.tr(),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import audioplayers_darwin
|
import audioplayers_darwin
|
||||||
import battery_plus
|
|
||||||
import connectivity_plus
|
import connectivity_plus
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
import firebase_core
|
import firebase_core
|
||||||
|
|
@ -25,7 +24,6 @@ import wakelock_plus
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
|
AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin"))
|
||||||
BatteryPlusMacosPlugin.register(with: registry.registrar(forPlugin: "BatteryPlusMacosPlugin"))
|
|
||||||
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||||
|
|
|
||||||
74
pubspec.lock
74
pubspec.lock
|
|
@ -113,22 +113,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.3.0"
|
version: "4.3.0"
|
||||||
battery_plus:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: battery_plus
|
|
||||||
sha256: ad16fcb55b7384be6b4bbc763d5e2031ac7ea62b2d9b6b661490c7b9741155bf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "7.0.0"
|
|
||||||
battery_plus_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: battery_plus_platform_interface
|
|
||||||
sha256: e8342c0f32de4b1dfd0223114b6785e48e579bfc398da9471c9179b907fa4910
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.1"
|
|
||||||
bloc:
|
bloc:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -349,10 +333,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: dbus
|
name: dbus
|
||||||
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
|
sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.11"
|
version: "0.7.12"
|
||||||
dio:
|
dio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -421,10 +405,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ffi
|
name: ffi
|
||||||
sha256: d07d37192dbf97461359c1518788f203b0c9102cfd2c35a716b823741219542c
|
sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.5"
|
version: "2.2.0"
|
||||||
|
ffi_leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi_leak_tracker
|
||||||
|
sha256: "4093d4ef9ca06ffe2786e73bfb25e22aa92112b9bb4ec941f11e3e6b61489a97"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2"
|
||||||
file:
|
file:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -743,10 +735,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_secure_storage_windows
|
name: flutter_secure_storage_windows
|
||||||
sha256: "3b7c8e068875dfd46719ff57c90d8c459c87f2302ed6b00ff006b3c9fcad1613"
|
sha256: "471951813a97006d899db4948acc654a4f28c440083ea08178935ce20b173ec1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.0"
|
version: "4.2.2"
|
||||||
flutter_spinkit:
|
flutter_spinkit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1206,21 +1198,21 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: package_info_plus
|
name: package_info_plus
|
||||||
sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d
|
sha256: "4bf625947f6c7713ee242296a682e23e44823c09cf9d79e4f1238923c92db852"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.0"
|
version: "10.1.0"
|
||||||
package_info_plus_platform_interface:
|
package_info_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: package_info_plus_platform_interface
|
name: package_info_plus_platform_interface
|
||||||
sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086"
|
sha256: db762cb2f4f25ee60fb6359773861b0f199e00b90d237bd85a76a1e806b46ef4
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "4.1.0"
|
||||||
path:
|
path:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1682,14 +1674,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.2"
|
version: "1.4.2"
|
||||||
storage_info:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: storage_info
|
|
||||||
sha256: adbf5fd1a7c2ca977dd828573820db0a0a16f4aa317e0ab72e9b3282eb5bbe42
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1770,14 +1754,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.1"
|
||||||
upower:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: upower
|
|
||||||
sha256: cf042403154751180affa1d15614db7fa50234bc2373cd21c3db666c38543ebf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.7.0"
|
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1942,18 +1918,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus
|
name: wakelock_plus
|
||||||
sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228"
|
sha256: "824c5bba0f800e86d32e57d3d1843c531f090005cc89d9a837933e6601093d53"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.6.1"
|
||||||
wakelock_plus_platform_interface:
|
wakelock_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus_platform_interface
|
name: wakelock_plus_platform_interface
|
||||||
sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2"
|
sha256: b13f99e992e7ae6a152e16c5559d3c07ff445b13330192662494e614ca3e7d7b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.5.1"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -2006,10 +1982,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e
|
sha256: ba6f4bba816c8d7e3c1580e170f3786d216951cc6b94babc3b814c08d2cb2738
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.15.0"
|
version: "6.3.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
name: yimaru_app
|
name: yimaru_app
|
||||||
version: 0.1.21+23
|
version: 0.1.22+24
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
|
|
@ -22,8 +22,6 @@ dependencies:
|
||||||
flutter_svg: ^2.2.3
|
flutter_svg: ^2.2.3
|
||||||
stacked_shared: any
|
stacked_shared: any
|
||||||
image_picker: ^1.2.1
|
image_picker: ^1.2.1
|
||||||
battery_plus: ^7.0.0
|
|
||||||
storage_info: ^1.0.0
|
|
||||||
flutter_html: ^3.0.0
|
flutter_html: ^3.0.0
|
||||||
email_validator: any
|
email_validator: any
|
||||||
audioplayers: ^6.6.0
|
audioplayers: ^6.6.0
|
||||||
|
|
@ -43,6 +41,7 @@ dependencies:
|
||||||
json_serializable: ^6.8.0
|
json_serializable: ^6.8.0
|
||||||
waveform_recorder: ^1.8.0
|
waveform_recorder: ^1.8.0
|
||||||
vimeo_video_player: ^1.0.3
|
vimeo_video_player: ^1.0.3
|
||||||
|
package_info_plus: ^10.1.0
|
||||||
permission_handler: ^12.0.1
|
permission_handler: ^12.0.1
|
||||||
firebase_messaging: ^16.1.1
|
firebase_messaging: ^16.1.1
|
||||||
cached_network_image: ^3.4.1
|
cached_network_image: ^3.4.1
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,9 @@ import 'package:yimaru_app/services/url_launcher_service.dart';
|
||||||
import 'package:yimaru_app/services/phone_caller_service.dart';
|
import 'package:yimaru_app/services/phone_caller_service.dart';
|
||||||
import 'package:yimaru_app/services/learn_service.dart';
|
import 'package:yimaru_app/services/learn_service.dart';
|
||||||
import 'package:yimaru_app/services/localization_service.dart';
|
import 'package:yimaru_app/services/localization_service.dart';
|
||||||
|
import 'package:yimaru_app/services/onboarding_service.dart';
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
||||||
import 'test_helpers.mocks.dart';
|
|
||||||
|
|
||||||
@GenerateMocks(
|
@GenerateMocks(
|
||||||
[],
|
[],
|
||||||
customMocks: [
|
customMocks: [
|
||||||
|
|
@ -54,10 +53,10 @@ import 'test_helpers.mocks.dart';
|
||||||
MockSpec<UrlLauncherService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<UrlLauncherService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<UrlLauncherService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<UrlLauncherService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<PhoneCallerService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<PhoneCallerService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<LearnLessonService>(onMissingStub: OnMissingStub.returnDefault),
|
|
||||||
MockSpec<LearnService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<LearnService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<LearnService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<LearnService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<LocalizationService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<LocalizationService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
|
MockSpec<OnboardingService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
// @stacked-mock-spec
|
// @stacked-mock-spec
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
@ -85,10 +84,10 @@ void registerServices() {
|
||||||
getAndRegisterUrlLauncherService();
|
getAndRegisterUrlLauncherService();
|
||||||
getAndRegisterUrlLauncherService();
|
getAndRegisterUrlLauncherService();
|
||||||
getAndRegisterPhoneCallerService();
|
getAndRegisterPhoneCallerService();
|
||||||
getAndRegisterLearnLessonService();
|
|
||||||
getAndRegisterLearnService();
|
getAndRegisterLearnService();
|
||||||
getAndRegisterLearnService();
|
getAndRegisterLearnService();
|
||||||
getAndRegisterLocalizationService();
|
getAndRegisterLocalizationService();
|
||||||
|
getAndRegisterOnboardingService();
|
||||||
// @stacked-mock-register
|
// @stacked-mock-register
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,6 +284,13 @@ MockLocalizationService getAndRegisterLocalizationService() {
|
||||||
locator.registerSingleton<LocalizationService>(service);
|
locator.registerSingleton<LocalizationService>(service);
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MockOnboardingService getAndRegisterOnboardingService() {
|
||||||
|
_removeRegistrationIfExists<OnboardingService>();
|
||||||
|
final service = MockOnboardingService();
|
||||||
|
locator.registerSingleton<OnboardingService>(service);
|
||||||
|
return service;
|
||||||
|
}
|
||||||
// @stacked-mock-create
|
// @stacked-mock-create
|
||||||
|
|
||||||
void _removeRegistrationIfExists<T extends Object>() {
|
void _removeRegistrationIfExists<T extends Object>() {
|
||||||
|
|
|
||||||
11
test/services/onboarding_service_test.dart
Normal file
11
test/services/onboarding_service_test.dart
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
|
|
||||||
|
import '../helpers/test_helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('OnboardingServiceTest -', () {
|
||||||
|
setUp(() => registerServices());
|
||||||
|
tearDown(() => locator.reset());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
#include <audioplayers_windows/audioplayers_windows_plugin.h>
|
||||||
#include <battery_plus/battery_plus_windows_plugin.h>
|
|
||||||
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||||
#include <file_selector_windows/file_selector_windows.h>
|
#include <file_selector_windows/file_selector_windows.h>
|
||||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||||
|
|
@ -20,8 +19,6 @@
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
AudioplayersWindowsPluginRegisterWithRegistrar(
|
AudioplayersWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
|
registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin"));
|
||||||
BatteryPlusWindowsPluginRegisterWithRegistrar(
|
|
||||||
registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin"));
|
|
||||||
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||||
FileSelectorWindowsRegisterWithRegistrar(
|
FileSelectorWindowsRegisterWithRegistrar(
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
audioplayers_windows
|
audioplayers_windows
|
||||||
battery_plus
|
|
||||||
connectivity_plus
|
connectivity_plus
|
||||||
file_selector_windows
|
file_selector_windows
|
||||||
firebase_core
|
firebase_core
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user