Merge branch 'release/0.1.34'

-fix(subscription): Subscription logic updated
This commit is contained in:
BisratHailu 2026-06-03 03:48:00 +03:00
commit 2554b80359
28 changed files with 558 additions and 498 deletions

View File

@ -475,16 +475,16 @@ class StackedRouter extends _i1.RouterBase {
_i18.LearnModuleView: (data) {
final args = data.getArgs<LearnModuleViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>(
builder: (context) =>
_i18.LearnModuleView(key: args.key, course: args.course),
builder: (context) => _i18.LearnModuleView(
key: args.key, first: args.first, course: args.course),
settings: data,
);
},
_i19.LearnLessonView: (data) {
final args = data.getArgs<LearnLessonViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>(
builder: (context) =>
_i19.LearnLessonView(key: args.key, module: args.module),
builder: (context) => _i19.LearnLessonView(
key: args.key, first: args.first, module: args.module),
settings: data,
);
},
@ -628,7 +628,8 @@ class StackedRouter extends _i1.RouterBase {
_i35.LearnCourseView: (data) {
final args = data.getArgs<LearnCourseViewArguments>(nullOk: false);
return _i37.MaterialPageRoute<dynamic>(
builder: (context) => _i35.LearnCourseView(key: args.key, id: args.id),
builder: (context) =>
_i35.LearnCourseView(key: args.key, id: args.id, first: args.first),
settings: data,
);
},
@ -1009,54 +1010,60 @@ class LoginViewArguments {
class LearnModuleViewArguments {
const LearnModuleViewArguments({
this.key,
required this.first,
required this.course,
});
final _i37.Key? key;
final bool first;
final _i38.LearnCourse course;
@override
String toString() {
return '{"key": "$key", "course": "$course"}';
return '{"key": "$key", "first": "$first", "course": "$course"}';
}
@override
bool operator ==(covariant LearnModuleViewArguments other) {
if (identical(this, other)) return true;
return other.key == key && other.course == course;
return other.key == key && other.first == first && other.course == course;
}
@override
int get hashCode {
return key.hashCode ^ course.hashCode;
return key.hashCode ^ first.hashCode ^ course.hashCode;
}
}
class LearnLessonViewArguments {
const LearnLessonViewArguments({
this.key,
required this.first,
required this.module,
});
final _i37.Key? key;
final bool first;
final _i39.LearnModule module;
@override
String toString() {
return '{"key": "$key", "module": "$module"}';
return '{"key": "$key", "first": "$first", "module": "$module"}';
}
@override
bool operator ==(covariant LearnLessonViewArguments other) {
if (identical(this, other)) return true;
return other.key == key && other.module == module;
return other.key == key && other.first == first && other.module == module;
}
@override
int get hashCode {
return key.hashCode ^ module.hashCode;
return key.hashCode ^ first.hashCode ^ module.hashCode;
}
}
@ -1486,26 +1493,29 @@ class LearnCourseViewArguments {
const LearnCourseViewArguments({
this.key,
required this.id,
required this.first,
});
final _i37.Key? key;
final int id;
final bool first;
@override
String toString() {
return '{"key": "$key", "id": "$id"}';
return '{"key": "$key", "id": "$id", "first": "$first"}';
}
@override
bool operator ==(covariant LearnCourseViewArguments other) {
if (identical(this, other)) return true;
return other.key == key && other.id == id;
return other.key == key && other.id == id && other.first == first;
}
@override
int get hashCode {
return key.hashCode ^ id.hashCode;
return key.hashCode ^ id.hashCode ^ first.hashCode;
}
}
@ -1801,6 +1811,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
Future<dynamic> navigateToLearnModuleView({
_i37.Key? key,
required bool first,
required _i38.LearnCourse course,
int? routerId,
bool preventDuplicates = true,
@ -1809,7 +1820,8 @@ extension NavigatorStateExtension on _i47.NavigationService {
transition,
}) async {
return navigateTo<dynamic>(Routes.learnModuleView,
arguments: LearnModuleViewArguments(key: key, course: course),
arguments:
LearnModuleViewArguments(key: key, first: first, course: course),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -1818,6 +1830,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
Future<dynamic> navigateToLearnLessonView({
_i37.Key? key,
required bool first,
required _i39.LearnModule module,
int? routerId,
bool preventDuplicates = true,
@ -1826,7 +1839,8 @@ extension NavigatorStateExtension on _i47.NavigationService {
transition,
}) async {
return navigateTo<dynamic>(Routes.learnLessonView,
arguments: LearnLessonViewArguments(key: key, module: module),
arguments:
LearnLessonViewArguments(key: key, first: first, module: module),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -2107,6 +2121,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
Future<dynamic> navigateToLearnCourseView({
_i37.Key? key,
required int id,
required bool first,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
@ -2114,7 +2129,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
transition,
}) async {
return navigateTo<dynamic>(Routes.learnCourseView,
arguments: LearnCourseViewArguments(key: key, id: id),
arguments: LearnCourseViewArguments(key: key, id: id, first: first),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -2399,6 +2414,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
Future<dynamic> replaceWithLearnModuleView({
_i37.Key? key,
required bool first,
required _i38.LearnCourse course,
int? routerId,
bool preventDuplicates = true,
@ -2407,7 +2423,8 @@ extension NavigatorStateExtension on _i47.NavigationService {
transition,
}) async {
return replaceWith<dynamic>(Routes.learnModuleView,
arguments: LearnModuleViewArguments(key: key, course: course),
arguments:
LearnModuleViewArguments(key: key, first: first, course: course),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -2416,6 +2433,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
Future<dynamic> replaceWithLearnLessonView({
_i37.Key? key,
required bool first,
required _i39.LearnModule module,
int? routerId,
bool preventDuplicates = true,
@ -2424,7 +2442,8 @@ extension NavigatorStateExtension on _i47.NavigationService {
transition,
}) async {
return replaceWith<dynamic>(Routes.learnLessonView,
arguments: LearnLessonViewArguments(key: key, module: module),
arguments:
LearnLessonViewArguments(key: key, first: first, module: module),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -2705,6 +2724,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
Future<dynamic> replaceWithLearnCourseView({
_i37.Key? key,
required int id,
required bool first,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
@ -2712,7 +2732,7 @@ extension NavigatorStateExtension on _i47.NavigationService {
transition,
}) async {
return replaceWith<dynamic>(Routes.learnCourseView,
arguments: LearnCourseViewArguments(key: key, id: id),
arguments: LearnCourseViewArguments(key: key, id: id, first: first),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,

View File

@ -31,7 +31,6 @@ class AuthenticationService with ListenableServiceMixin {
StateObjects get state => _state;
// Check user logged in
Future<bool> userLoggedIn() async {
if (await _secureService.getString('userId') != null) {
@ -202,7 +201,6 @@ class AuthenticationService with ListenableServiceMixin {
await setFirstTimeInstall(firstTimeInstall);
await _secureService.setString('language', language);
_state = StateObjects.none;
notifyListeners();
}

View File

@ -29,7 +29,6 @@ class GoogleAuthService with ListenableServiceMixin {
_googleUser ??=
await _signIn.authenticate(scopeHint: ['email', 'profile']);
});
notifyListeners();
} catch (e) {

View File

@ -58,8 +58,6 @@ class LearnService with ListenableServiceMixin {
List<LearnLesson> get lessons => _lessons;
// Learn programs
Future<String?> refreshObject(String url) async {
Map<String, dynamic> data = {'reference': url};

View File

@ -124,5 +124,4 @@ String kTelegramSupportLink = 'https://t.me/yimaruacademy2026';
String kErrorUrl = 'https://api.yimaruacademy.com/payment/error';
String kSuccessUrl =
'https://api.yimaruacademy.com/payment/success';
String kSuccessUrl = 'https://api.yimaruacademy.com/payment/success';

View File

@ -38,7 +38,8 @@ class CodegenLoader extends AssetLoader{
"confirm_password": "የይለፍ ቃል ያረጋግጡ",
"eight_character_minimum": "ቢያንስ 8 ፊደላት",
"password_match": "የይለፍ ቃሉ ተመሳስሏል",
"sign_up_agreement": "‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።",
"sign_up_agreement":
"‘ይመዝገቡ’ የሚለውን ሲጫኑ በ‘አገልግሎት ውሎች’ እና ‘በግላዊነት ፖሊሲ’ ይስማማሉ።",
"terms_of_services": "የአገልግሎት ውሎች",
"and": "እና",
"privacy_policy": "የግላዊነት ፖሊሲ",
@ -137,7 +138,8 @@ class CodegenLoader extends AssetLoader{
"call_our_support": "ከ3 ጠዋት እስከ 12 ማታ ድረስ የድጋፍ ቡድናችንን ይደውሉ",
"tap_to_call": "ለመደወል ይንኩ",
"join_telegram": "በቴሌግራም የይማሩ አካዳሚን ይቀላቀሉ",
"connect_with_support_team": "ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።",
"connect_with_support_team":
"ለፈጣን እርዳታ እና የማህበረሰብ ዝማኔዎች፣ በቴሌግራም ከድጋፍ ቡድናችን ጋር ወዲያውኑ ይገናኙ።",
"open_in_telegram": "በቴሌግራም ይክፈቱ",
"search_for": "ፈልጉት",
"current_level": "የአሁኑ ደረጃ",
@ -187,7 +189,8 @@ class CodegenLoader extends AssetLoader{
"evey_one_has_strugle": "ሁሉም ሰው ችግሮች አሉት፣ የአንተን እንጀምር እንፍታ",
"write_your_challenge": "ችግርህን ጻፍ…",
"topic_interest": "በጣም የሚስቡህ ርዕሶች የትኞቹ ናቸው?",
"favourite_topic": "የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።",
"favourite_topic":
"የምትወዳቸው ርዕሶች አስደሳች እና ከሕይወትህ ጋር የተዛመዱ ትምህርቶችን ለመፍጠር ይረዱናል።",
"your_interest": "ፍላጎትህን ጻፍ…",
"want_quick_assessment": "የእንግሊዝኛ ደረጃህን ለማወቅ ፈጣን ግምገማ ትፈልጋለህ?",
"answer_quick_questions": "የእንግሊዝኛ ችሎታህን ለመረዳት ጥቂት ፈጣን ጥያቄዎችን መልስ።",
@ -202,7 +205,8 @@ class CodegenLoader extends AssetLoader{
"finish_all_practice_lesson": "ይህን ልምምድ ለመውሰድ የቀድሞውን የትምህርት ልምምድ ያጠናቅቁ",
"finish_all_practice_module": "የሞጁሉን ልምምድ ለመውሰድ የትምህርት ልምምዶችን ያጠናቅቁ",
"finish_all_practice_course": "የኮርሱን ልምምድ ለመውሰድ የሞጁል ልምምዶችን ያጠናቅቁ",
"finish_all_practice_previouse_module": "ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
"finish_all_practice_previouse_module":
"ይህን ልምምድ ለመውሰድ የቀድሞውን የሞጁል ልምምድ ያጠናቅቁ",
"finish_all_practice_previouse_course": "ይህን ለመውሰድ የቀድሞውን የኮርስ ልምምድ ያጠናቅቁ",
"track_journey": "የትምህርት ጉዞዎን ይከታተሉ እና በጊዜ ሂደት ያሳዩትን እድገት ይመልከቱ።",
"learn_english": "እንግሊዝኛ ይማሩ",
@ -229,13 +233,15 @@ static const Map<String,dynamic> _en = {
"login": "Login",
"register_with_google": "Register with Google",
"register_with_phone": "Register with phone number",
"enter_phone_number": "Enter your phone number. We will send you a confirmation code there.",
"enter_phone_number":
"Enter your phone number. We will send you a confirmation code there.",
"login_with_email": "Login with email",
"create_password": "Create password",
"confirm_password": "Confirm password",
"eight_character_minimum": "8 characters minimum",
"password_match": "password match",
"sign_up_agreement": "By clicking Sign Up, you agree to our Terms of Service and Privacy Policy",
"sign_up_agreement":
"By clicking Sign Up, you agree to our Terms of Service and Privacy Policy",
"terms_of_services": "Terms of Service",
"and": "and",
"privacy_policy": "Privacy Policy",
@ -246,7 +252,8 @@ static const Map<String,dynamic> _en = {
"code_sent_to_email": "Code sent to your email",
"resend_code_in": "Resend code in",
"reset_password": "Reset Password",
"enter_email_reset_code": "Enter your email. We will send you a reset code.",
"enter_email_reset_code":
"Enter your email. We will send you a reset code.",
"please_wait": "Please wait",
"reset_code_sent": "Reset code sent successfully",
"reset_code": "Reset code",
@ -287,7 +294,8 @@ static const Map<String,dynamic> _en = {
"cancel": "Cancel",
"you_are_speaking": "You're speaking",
"practice_completed": "Practice completed!",
"great_improvement": "You sound more confident this time, great improvement",
"great_improvement":
"You sound more confident this time, great improvement",
"practice_again": "Practice again",
"conversation_review": "Conversation review",
"result": "Result",
@ -334,7 +342,8 @@ static const Map<String,dynamic> _en = {
"call_our_support": "Call our support team between 9 AM - 6 PM",
"tap_to_call": "Tap to call",
"join_telegram": "Join Yimaru Academy on Telegram",
"connect_with_support_team": "Connect with our support team instantly on Telegram for quick assistance and community updates",
"connect_with_support_team":
"Connect with our support team instantly on Telegram for quick assistance and community updates",
"open_in_telegram": "Open in Telegram",
"search_for": "Search for",
"current_level": "Current Level",
@ -342,18 +351,22 @@ static const Map<String,dynamic> _en = {
"no_practice_available": "No practice available!",
"begin_module_practice": "Begin Module Practice",
"lets_practice_lesson": "Lets Practice",
"lets_quickly_review": "Lets quickly review what youve learned in this module!",
"lets_quickly_review":
"Lets quickly review what youve learned in this module!",
"lets_practice_module": "Let's practice what you just learnt!",
"ask_you_few_actions": "Ill ask you a few questions, and you can respond naturally.",
"ask_you_few_actions":
"Ill ask you a few questions, and you can respond naturally.",
"begin_level_practice": "Begin Level Practice",
"lets_practice_course": "Lets Practice Course",
"lets_quick_review": "Lets quickly review what youve learned in this level!",
"lets_quick_review":
"Lets quickly review what youve learned in this level!",
"speaking": "is speaking...",
"you_have_finished_practice": "You have finished your practice",
"view_results": "View My Results",
"sample_answer": "Sample Answer",
"your_answer": "Your Answer",
"sound_confident": "You sound more confident this time - great improvement!",
"sound_confident":
"You sound more confident this time - great improvement!",
"you_have_completed": "Yay, youve completed",
"yes": "Yes",
"no": "No",
@ -364,15 +377,20 @@ static const Map<String,dynamic> _en = {
"phone_must_start_with": "Phone number must start with 251",
"phone_must_be": "Phone number must be 12 digits",
"what_should_we_call_you": "What should we call you?",
"name_for_personalization": "Well use your name to personalize your learning journey.",
"name_for_personalization":
"Well use your name to personalize your learning journey.",
"choose_your_gender": "Choose your gender?",
"gender_for_personalization": "Well personalize your learning experience based on your gender.",
"gender_for_personalization":
"Well personalize your learning experience based on your gender.",
"age_range": "Which age range are you in?",
"age_for_personalization": "Well personalize your learning experience based on your age.",
"age_for_personalization":
"Well personalize your learning experience based on your age.",
"educational_background": "Whats your current educational level?",
"education_for_personalization": "This helps us tailor your lessons to your experience.",
"education_for_personalization":
"This helps us tailor your lessons to your experience.",
"your_occupation": "Whats your occupation?",
"occupation_for_personalization": "Well personalize your learning experience based on your occupation.",
"occupation_for_personalization":
"Well personalize your learning experience based on your occupation.",
"location": "Where are you from?",
"select_country_region": "Select your country and region from the dropdown",
"select_country": "Select country",
@ -384,10 +402,13 @@ static const Map<String,dynamic> _en = {
"evey_one_has_strugle": "Everyone has struggles, lets start fixing yours",
"write_your_challenge": "Write your challenge…",
"topic_interest": "Which topics interest you most?",
"favourite_topic": "Your favorite topics help us create fun, relatable lessons.",
"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.",
"want_quick_assessment":
"Want a quick assessment to know your English level?",
"answer_quick_questions":
"Answer a few quick questions to help us understand your English proficiency.",
"skip": "Skip",
"finish_level": "Finish Level",
"likely_speaker": "Youre likely speaker of",
@ -396,17 +417,26 @@ static const Map<String,dynamic> _en = {
"welcome_abroad": "Welcome aboard",
"ready_to_explore": "Youre ready to explore your personalized lessons.",
"finish": "Finish",
"finish_all_practice_lesson": "Finish the previous lesson practice to take this practice",
"finish_all_practice_module": "Finish the lesson practices to take the Module Practice",
"finish_all_practice_course": "Finish the Module practices to take the Course practice",
"finish_all_practice_previouse_module": "Finish the previous Module practice to take this practice",
"finish_all_practice_previouse_course": "Finish the previous course practice to take this",
"track_journey": "Track your learning journey and see your growth over time.",
"finish_all_practice_lesson":
"Finish the previous lesson practice to take this practice",
"finish_all_practice_module":
"Finish the lesson practices to take the Module Practice",
"finish_all_practice_course":
"Finish the Module practices to take the Course practice",
"finish_all_practice_previouse_module":
"Finish the previous Module practice to take this practice",
"finish_all_practice_previouse_course":
"Finish the previous course practice to take this",
"track_journey":
"Track your learning journey and see your growth over time.",
"learn_english": "Learn English",
"keep_momentum": "Great job! Keep the momentum.",
"completed_practices": "Completed Practices",
"total_practices": "Total Practices",
"progress_percentage": "Progress Percentage"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en};
static const Map<String, Map<String, dynamic>> mapLocales = {
"am": _am,
"en": _en
};
}

View File

@ -161,7 +161,8 @@ abstract class LocaleKeys {
static const educational_background = 'educational_background';
static const education_for_personalization = 'education_for_personalization';
static const your_occupation = 'your_occupation';
static const occupation_for_personalization = 'occupation_for_personalization';
static const occupation_for_personalization =
'occupation_for_personalization';
static const location = 'location';
static const select_country_region = 'select_country_region';
static const select_country = 'select_country';
@ -188,13 +189,14 @@ abstract class LocaleKeys {
static const finish_all_practice_lesson = 'finish_all_practice_lesson';
static const finish_all_practice_module = 'finish_all_practice_module';
static const finish_all_practice_course = 'finish_all_practice_course';
static const finish_all_practice_previouse_module = 'finish_all_practice_previouse_module';
static const finish_all_practice_previouse_course = 'finish_all_practice_previouse_course';
static const finish_all_practice_previouse_module =
'finish_all_practice_previouse_module';
static const finish_all_practice_previouse_course =
'finish_all_practice_previouse_course';
static const track_journey = 'track_journey';
static const learn_english = 'learn_english';
static const keep_momentum = 'keep_momentum';
static const completed_practices = 'completed_practices';
static const total_practices = 'total_practices';
static const progress_percentage = 'progress_percentage';
}

View File

@ -55,8 +55,6 @@ class HomeViewModel extends ReactiveViewModel {
rebuildUi();
}
// Remote api calls
// In-app update

View File

@ -35,7 +35,6 @@ class LanguageViewModel extends ReactiveViewModel {
rebuildUi();
}
// Navigation
void pop() => _navigationService.back();
}

View File

@ -13,8 +13,10 @@ import 'learn_course_viewmodel.dart';
class LearnCourseView extends StackedView<LearnCourseViewModel> {
final int id;
final bool first;
const LearnCourseView({Key? key, required this.id}) : super(key: key);
const LearnCourseView({Key? key, required this.id, required this.first})
: super(key: key);
Future<void> _onPractice(
{required BuildContext context,
@ -151,7 +153,9 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
viewModel: viewModel,
course: viewModel.courses[index]),
onViewTap: () async =>
await viewModel.navigateToLearnModule(viewModel.courses[index]),
await viewModel.navigateToLearnModule(
first: first && index ==0,
course: viewModel.courses[index]),
),
separatorBuilder: (context, index) => verticalSpaceSmall,
);

View File

@ -32,8 +32,8 @@ class LearnCourseViewModel extends ReactiveViewModel {
Future<void> navigateToLearnSubscription() async =>
await _navigationService.navigateToLearnSubscriptionView();
Future<void> navigateToLearnModule(LearnCourse course) async =>
_navigationService.navigateToLearnModuleView(course: course);
Future<void> navigateToLearnModule({required bool first,required LearnCourse course}) async =>
_navigationService.navigateToLearnModuleView(first: first,course: course);
Future<void> navigateToLearnPractice(
{required int id, required String level}) async =>

View File

@ -17,21 +17,17 @@ import '../../widgets/small_app_bar.dart';
import 'learn_lesson_viewmodel.dart';
class LearnLessonView extends StackedView<LearnLessonViewModel> {
final bool first;
final LearnModule module;
const LearnLessonView({Key? key, required this.module}) : super(key: key);
const LearnLessonView({Key? key, required this.first, required this.module})
: super(key: key);
Future<void> _onPractice(
{required int index,
required LearnLesson lesson,
required BuildContext context,
required LearnLessonViewModel viewModel}) async {
/* if (lesson.access?.isAccessible ?? false) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else {
await _showSheet(context: context, viewModel: viewModel);
}*/
if (index > 1) {
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'active') {
if (lesson.access?.isAccessible ?? false) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
@ -39,10 +35,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
await _showSheet(context: context, viewModel: viewModel);
}
} else {
await viewModel.navigateToLearnSubscription();
}
} else {
if (lesson.access?.isAccessible ?? false) {
if (first && index < 3) {
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
} else {
await _showSheet(context: context, viewModel: viewModel);
@ -224,6 +217,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) => _buildTile(
index: index,
first: first && index < 3,
lesson: viewModel.lessons[index],
last: index == viewModel.lessons.length - 1,
onPracticeTap: () async => await _onPractice(
@ -244,12 +238,14 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
Widget _buildTile({
required bool last,
required int index,
required bool first,
required LearnLesson lesson,
required GestureTapCallback? onLessonTap,
required GestureTapCallback? onPracticeTap,
}) =>
LearnLessonTile(
last: last,
first: first,
index: index,
lesson: lesson,
onLessonTap: onLessonTap,

View File

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

View File

@ -16,9 +16,11 @@ import '../../widgets/small_app_bar.dart';
import 'learn_module_viewmodel.dart';
class LearnModuleView extends StackedView<LearnModuleViewModel> {
final bool first;
final LearnCourse course;
const LearnModuleView({Key? key, required this.course}) : super(key: key);
const LearnModuleView({Key? key, required this.first, required this.course})
: super(key: key);
Future<void> _onPractice(
{required BuildContext context,
@ -202,7 +204,9 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
module: viewModel.modules[index],
),
onModuleTap: () async =>
await viewModel.navigateToLearnLesson(viewModel.modules[index]),
await viewModel.navigateToLearnLesson(
first: first && index == 0,
module: viewModel.modules[index]),
),
);

View File

@ -35,8 +35,8 @@ class LearnModuleViewModel extends ReactiveViewModel {
// Navigation
void pop() => _navigationService.back();
Future<void> navigateToLearnLesson(LearnModule module) async =>
await _navigationService.navigateToLearnLessonView(module: module);
Future<void> navigateToLearnLesson({required bool first, required LearnModule module}) async =>
await _navigationService.navigateToLearnLessonView(first:first,module: module);
Future<void> navigateToLearnPractice(
{required int id, required String module}) async =>

View File

@ -10,6 +10,7 @@ import 'package:yimaru_app/services/voice_recorder_service.dart';
import 'package:yimaru_app/ui/common/enmus.dart';
import '../../../app/app.locator.dart';
import '../../../app/app.router.dart';
import '../../../models/learn_question.dart';
import '../../../services/api_service.dart';
import '../../../services/audio_player_service.dart';
@ -264,6 +265,9 @@ class LearnPracticeViewModel extends ReactiveViewModel {
// Navigation
void pop() => _navigationService.back();
Future<void> navigateToLearnSubscription() async =>
await _navigationService.navigateToLearnSubscriptionView();
// Remote api call
// Refresh url

View File

@ -27,6 +27,14 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
required this.subtitle,
required this.practice});
Future<void> _practice(LearnPracticeViewModel viewModel) async {
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'active') {
viewModel.goTo(1);
} else {
await viewModel.navigateToLearnSubscription();
}
}
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
await viewModel.stopRecording();
viewModel.pop();
@ -207,7 +215,7 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
text: label,
borderRadius: 12,
foregroundColor: kcWhite,
onTap: () => viewModel.goTo(1),
backgroundColor: kcPrimaryColor,
onTap: () async => await _practice(viewModel),
);
}

View File

@ -87,8 +87,8 @@ class LearnProgramView extends StackedView<LearnProgramViewModel> {
separatorBuilder: (context, index) => verticalSpaceSmall,
itemBuilder: (context, index) => _buildTile(
program: viewModel.learnPrograms[index],
onTap: () async => await viewModel
.navigateToLearnCourse(viewModel.learnPrograms[index].id ?? 0),
onTap: () async => await viewModel.navigateToLearnCourse(
first: index == 0, id: viewModel.learnPrograms[index].id ?? 0),
),
);

View File

@ -36,8 +36,8 @@ class LearnProgramViewModel extends ReactiveViewModel {
List<LearnProgram> get learnPrograms => _learnPrograms;
// Navigation
Future<void> navigateToLearnCourse(int id) async =>
_navigationService.navigateToLearnCourseView(id: id);
Future<void> navigateToLearnCourse({required int id,required bool first}) async =>
_navigationService.navigateToLearnCourseView(id: id,first: first);
// Remote api call

View File

@ -205,8 +205,8 @@ class OnboardingViewModel extends ReactiveViewModel
_selectedCountry = value;
if (value?.code?.toLowerCase().trim() == 'et') {
_dropdownRegion = true;
_selectedRegion = _regions
.firstWhere((e) => e.code?.toLowerCase().trim().contains('addis_ababa') ?? false);
_selectedRegion = _regions.firstWhere(
(e) => e.code?.toLowerCase().trim().contains('addis_ababa') ?? false);
} else {
_dropdownRegion = false;
}

View File

@ -26,7 +26,8 @@ class PaymentView extends StackedView<PaymentViewModel> {
@override
void onViewModelReady(PaymentViewModel viewModel) async {
await viewModel.createLearnSubscriptionRequest(phone: phone,subscription: subscription);
await viewModel.createLearnSubscriptionRequest(
phone: phone, subscription: subscription);
super.onViewModelReady(viewModel);
}

View File

@ -45,18 +45,22 @@ class PaymentViewModel extends ReactiveViewModel {
// Remote api call
// Learn subscription
Future<void> createLearnSubscriptionRequest({required String phone,required LearnSubscription subscription}) async =>
await runBusyFuture(_createLearnSubscriptionRequest(phone: phone,subscription: subscription),
Future<void> createLearnSubscriptionRequest(
{required String phone,
required LearnSubscription subscription}) async =>
await runBusyFuture(
_createLearnSubscriptionRequest(
phone: phone, subscription: subscription),
busyObject: StateObjects.learnSubscription);
Future<void> _createLearnSubscriptionRequest({required String phone,required LearnSubscription subscription}) async {
Future<void> _createLearnSubscriptionRequest(
{required String phone, required LearnSubscription subscription}) async {
if (await _statusChecker.checkConnection()) {
Map<String, dynamic> data = {
'provider': 'CHAPA',
'phone': '251$phone',
'email': 'test@gmail.com',
'plan_id': subscription.id,
};
Map<String, dynamic> response =

View File

@ -136,8 +136,8 @@ class ProfileDetailViewModel extends ReactiveViewModel
void setEthiopianRegion(String region) {
_dropdownRegion = true;
_selectedRegion =
_regions.firstWhere((r) => r.code?.toLowerCase() == region.toLowerCase());
_selectedRegion = _regions
.firstWhere((r) => r.code?.toLowerCase() == region.toLowerCase());
rebuildUi();
}

View File

@ -17,7 +17,6 @@ class ProgressViewModel extends ReactiveViewModel {
@override
List<ListenableServiceMixin> get listenableServices => [_learnService];
// Total practice count
int get _totalCount => _learnService.totalCount;
@ -33,7 +32,6 @@ class ProgressViewModel extends ReactiveViewModel {
int get totalProgress => _totalProgress;
// Courses
final List<Map<String, dynamic>> _courses = [
{
@ -53,7 +51,8 @@ class ProgressViewModel extends ReactiveViewModel {
// Learning progress
Future<void> getProgressSummary() async => runBusyFuture(_getProgressSummary(),
Future<void> getProgressSummary() async =>
runBusyFuture(_getProgressSummary(),
busyObject: StateObjects.progressSummary);
Future<void> _getProgressSummary() async {

View File

@ -17,6 +17,7 @@ import 'custom_linear_progress_indicator.dart';
class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
final int index;
final bool last;
final bool first;
final LearnLesson lesson;
final GestureTapCallback? onLessonTap;
final GestureTapCallback? onPracticeTap;
@ -26,6 +27,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
this.onLessonTap,
this.onPracticeTap,
required this.last,
required this.first,
required this.index,
required this.lesson});
@ -35,7 +37,9 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
Widget _buildContainerWrapper(LearnLessonViewModel viewModel) =>
GestureDetector(
onTap: !(lesson.access?.isAccessible ?? false) ? onPracticeTap : null,
onTap: viewModel.user?.subscriptionStatus?.toLowerCase() == 'active' ? !(lesson.access?.isAccessible ?? false)
? onPracticeTap
: null: !first ? onPracticeTap:null,
child: _buildContainer(viewModel),
);
@ -56,7 +60,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
Widget _buildTileStack(LearnLessonViewModel viewModel) => Stack(
children: [
_buildExpansionTile(viewModel),
_buildContainerShaderState()
_buildContainerShaderState(viewModel)
],
);
@ -70,7 +74,6 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
shape: Border.all(color: kcTransparent),
expandedAlignment: Alignment.centerLeft,
leading: _buildLeadingWrapper(viewModel),
enabled: (lesson.access?.isAccessible ?? false),
controlAffinity: ListTileControlAffinity.trailing,
expandedCrossAxisAlignment: CrossAxisAlignment.start,
tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
@ -85,6 +88,7 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
collapsedBackgroundColor: (lesson.access?.isCompleted ?? false)
? kcGreen.withOpacity(0.1)
: kcPrimaryColor.withOpacity(0.1),
enabled: first ? true : (lesson.access?.isAccessible ?? false),
children: _buildExpansionTileChildren(viewModel),
);
@ -203,7 +207,12 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
backgroundColor: kcPrimaryColor,
);
Widget _buildContainerShaderState() => !(lesson.access?.isAccessible ?? false)
Widget _buildContainerShaderState(LearnLessonViewModel viewModel) =>
viewModel.user?.subscriptionStatus?.toLowerCase() == 'active'
? !(lesson.access?.isAccessible ?? false)
? _buildContainerShader()
: Container()
: !first
? _buildContainerShader()
: Container();

View File

@ -1,6 +1,6 @@
name: yimaru_app
publish_to: 'none'
version: 0.1.33+35
version: 0.1.34+36
description: A new Flutter project.
environment: