Compare commits
No commits in common. "develop" and "main" have entirely different histories.
|
|
@ -38,10 +38,6 @@ import 'package:yimaru_app/services/image_downloader_service.dart';
|
||||||
import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart';
|
import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart';
|
||||||
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';
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_view.dart';
|
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/course/course_view.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/course_practice/course_practice_view.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart';
|
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
||||||
@StackedApp(
|
@StackedApp(
|
||||||
|
|
@ -73,10 +69,6 @@ import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart';
|
||||||
MaterialRoute(page: ForgetPasswordView),
|
MaterialRoute(page: ForgetPasswordView),
|
||||||
MaterialRoute(page: LearnLessonDetailView),
|
MaterialRoute(page: LearnLessonDetailView),
|
||||||
MaterialRoute(page: LearnPracticeView),
|
MaterialRoute(page: LearnPracticeView),
|
||||||
MaterialRoute(page: CourseView),
|
|
||||||
MaterialRoute(page: CourseModuleView),
|
|
||||||
MaterialRoute(page: CoursePracticeView),
|
|
||||||
MaterialRoute(page: CoursePaymentView),
|
|
||||||
// @stacked-route
|
// @stacked-route
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
|
|
||||||
|
|
@ -5,22 +5,15 @@
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
|
import 'package:flutter/material.dart' as _i29;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/material.dart' as _i33;
|
|
||||||
import 'package:stacked/stacked.dart' as _i1;
|
import 'package:stacked/stacked.dart' as _i1;
|
||||||
import 'package:stacked_services/stacked_services.dart' as _i34;
|
import 'package:stacked_services/stacked_services.dart' as _i30;
|
||||||
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 _i10;
|
as _i10;
|
||||||
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i23;
|
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i23;
|
||||||
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 _i13;
|
as _i13;
|
||||||
import 'package:yimaru_app/ui/views/course/course_view.dart' as _i29;
|
|
||||||
import 'package:yimaru_app/ui/views/course_module/course_module_view.dart'
|
|
||||||
as _i30;
|
|
||||||
import 'package:yimaru_app/ui/views/course_payment/course_payment_view.dart'
|
|
||||||
as _i32;
|
|
||||||
import 'package:yimaru_app/ui/views/course_practice/course_practice_view.dart'
|
|
||||||
as _i31;
|
|
||||||
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/failure/failure_view.dart' as _i25;
|
import 'package:yimaru_app/ui/views/failure/failure_view.dart' as _i25;
|
||||||
import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart'
|
import 'package:yimaru_app/ui/views/forget_password/forget_password_view.dart'
|
||||||
|
|
@ -111,14 +104,6 @@ class Routes {
|
||||||
|
|
||||||
static const learnPracticeView = '/learn-practice-view';
|
static const learnPracticeView = '/learn-practice-view';
|
||||||
|
|
||||||
static const courseView = '/course-view';
|
|
||||||
|
|
||||||
static const courseModuleView = '/course-module-view';
|
|
||||||
|
|
||||||
static const coursePracticeView = '/course-practice-view';
|
|
||||||
|
|
||||||
static const coursePaymentView = '/course-payment-view';
|
|
||||||
|
|
||||||
static const all = <String>{
|
static const all = <String>{
|
||||||
homeView,
|
homeView,
|
||||||
onboardingView,
|
onboardingView,
|
||||||
|
|
@ -147,10 +132,6 @@ class Routes {
|
||||||
forgetPasswordView,
|
forgetPasswordView,
|
||||||
learnLessonDetailView,
|
learnLessonDetailView,
|
||||||
learnPracticeView,
|
learnPracticeView,
|
||||||
courseView,
|
|
||||||
courseModuleView,
|
|
||||||
coursePracticeView,
|
|
||||||
coursePaymentView,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,33 +245,17 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
Routes.learnPracticeView,
|
Routes.learnPracticeView,
|
||||||
page: _i28.LearnPracticeView,
|
page: _i28.LearnPracticeView,
|
||||||
),
|
),
|
||||||
_i1.RouteDef(
|
|
||||||
Routes.courseView,
|
|
||||||
page: _i29.CourseView,
|
|
||||||
),
|
|
||||||
_i1.RouteDef(
|
|
||||||
Routes.courseModuleView,
|
|
||||||
page: _i30.CourseModuleView,
|
|
||||||
),
|
|
||||||
_i1.RouteDef(
|
|
||||||
Routes.coursePracticeView,
|
|
||||||
page: _i31.CoursePracticeView,
|
|
||||||
),
|
|
||||||
_i1.RouteDef(
|
|
||||||
Routes.coursePaymentView,
|
|
||||||
page: _i32.CoursePaymentView,
|
|
||||||
),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
||||||
_i2.HomeView: (data) {
|
_i2.HomeView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i2.HomeView(),
|
builder: (context) => const _i2.HomeView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i3.OnboardingView: (data) {
|
_i3.OnboardingView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i3.OnboardingView(),
|
builder: (context) => const _i3.OnboardingView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
|
|
@ -299,185 +264,156 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
final args = data.getArgs<StartupViewArguments>(
|
final args = data.getArgs<StartupViewArguments>(
|
||||||
orElse: () => const StartupViewArguments(),
|
orElse: () => const StartupViewArguments(),
|
||||||
);
|
);
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => _i4.StartupView(key: args.key, label: args.label),
|
builder: (context) => _i4.StartupView(key: args.key, label: args.label),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i5.ProfileView: (data) {
|
_i5.ProfileView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i5.ProfileView(),
|
builder: (context) => const _i5.ProfileView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i6.ProfileDetailView: (data) {
|
_i6.ProfileDetailView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i6.ProfileDetailView(),
|
builder: (context) => const _i6.ProfileDetailView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i7.DownloadsView: (data) {
|
_i7.DownloadsView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i7.DownloadsView(),
|
builder: (context) => const _i7.DownloadsView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i8.ProgressView: (data) {
|
_i8.ProgressView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i8.ProgressView(),
|
builder: (context) => const _i8.ProgressView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i9.OngoingProgressView: (data) {
|
_i9.OngoingProgressView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i9.OngoingProgressView(),
|
builder: (context) => const _i9.OngoingProgressView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i10.AccountPrivacyView: (data) {
|
_i10.AccountPrivacyView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i10.AccountPrivacyView(),
|
builder: (context) => const _i10.AccountPrivacyView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i11.SupportView: (data) {
|
_i11.SupportView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i11.SupportView(),
|
builder: (context) => const _i11.SupportView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i12.TelegramSupportView: (data) {
|
_i12.TelegramSupportView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i12.TelegramSupportView(),
|
builder: (context) => const _i12.TelegramSupportView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i13.CallSupportView: (data) {
|
_i13.CallSupportView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i13.CallSupportView(),
|
builder: (context) => const _i13.CallSupportView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i14.LanguageView: (data) {
|
_i14.LanguageView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i14.LanguageView(),
|
builder: (context) => const _i14.LanguageView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i15.PrivacyPolicyView: (data) {
|
_i15.PrivacyPolicyView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i15.PrivacyPolicyView(),
|
builder: (context) => const _i15.PrivacyPolicyView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i16.TermsAndConditionsView: (data) {
|
_i16.TermsAndConditionsView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i16.TermsAndConditionsView(),
|
builder: (context) => const _i16.TermsAndConditionsView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i17.RegisterView: (data) {
|
_i17.RegisterView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i17.RegisterView(),
|
builder: (context) => const _i17.RegisterView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i18.LoginView: (data) {
|
_i18.LoginView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i18.LoginView(),
|
builder: (context) => const _i18.LoginView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i19.LearnView: (data) {
|
_i19.LearnView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i19.LearnView(),
|
builder: (context) => const _i19.LearnView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i20.LearnLevelView: (data) {
|
_i20.LearnLevelView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i20.LearnLevelView(),
|
builder: (context) => const _i20.LearnLevelView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i21.LearnModuleView: (data) {
|
_i21.LearnModuleView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i21.LearnModuleView(),
|
builder: (context) => const _i21.LearnModuleView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i22.WelcomeView: (data) {
|
_i22.WelcomeView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i22.WelcomeView(),
|
builder: (context) => const _i22.WelcomeView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i23.AssessmentView: (data) {
|
_i23.AssessmentView: (data) {
|
||||||
final args = data.getArgs<AssessmentViewArguments>(nullOk: false);
|
final args = data.getArgs<AssessmentViewArguments>(nullOk: false);
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
_i23.AssessmentView(key: args.key, data: args.data),
|
_i23.AssessmentView(key: args.key, data: args.data),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i24.LearnLessonView: (data) {
|
_i24.LearnLessonView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i24.LearnLessonView(),
|
builder: (context) => const _i24.LearnLessonView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i25.FailureView: (data) {
|
_i25.FailureView: (data) {
|
||||||
final args = data.getArgs<FailureViewArguments>(nullOk: false);
|
final args = data.getArgs<FailureViewArguments>(nullOk: false);
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) =>
|
builder: (context) =>
|
||||||
_i25.FailureView(key: args.key, label: args.label),
|
_i25.FailureView(key: args.key, label: args.label),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i26.ForgetPasswordView: (data) {
|
_i26.ForgetPasswordView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i26.ForgetPasswordView(),
|
builder: (context) => const _i26.ForgetPasswordView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i27.LearnLessonDetailView: (data) {
|
_i27.LearnLessonDetailView: (data) {
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i27.LearnLessonDetailView(),
|
builder: (context) => const _i27.LearnLessonDetailView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i28.LearnPracticeView: (data) {
|
_i28.LearnPracticeView: (data) {
|
||||||
final args = data.getArgs<LearnPracticeViewArguments>(nullOk: false);
|
return _i29.MaterialPageRoute<dynamic>(
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
builder: (context) => const _i28.LearnPracticeView(),
|
||||||
builder: (context) => _i28.LearnPracticeView(
|
|
||||||
key: args.key,
|
|
||||||
title: args.title,
|
|
||||||
subtitle: args.subtitle,
|
|
||||||
buttonLabel: args.buttonLabel),
|
|
||||||
settings: data,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_i29.CourseView: (data) {
|
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
|
||||||
builder: (context) => const _i29.CourseView(),
|
|
||||||
settings: data,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_i30.CourseModuleView: (data) {
|
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
|
||||||
builder: (context) => const _i30.CourseModuleView(),
|
|
||||||
settings: data,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_i31.CoursePracticeView: (data) {
|
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
|
||||||
builder: (context) => const _i31.CoursePracticeView(),
|
|
||||||
settings: data,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
_i32.CoursePaymentView: (data) {
|
|
||||||
return _i33.MaterialPageRoute<dynamic>(
|
|
||||||
builder: (context) => const _i32.CoursePaymentView(),
|
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -496,7 +432,7 @@ class StartupViewArguments {
|
||||||
this.label = 'Loading',
|
this.label = 'Loading',
|
||||||
});
|
});
|
||||||
|
|
||||||
final _i33.Key? key;
|
final _i29.Key? key;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
|
|
@ -523,7 +459,7 @@ class AssessmentViewArguments {
|
||||||
required this.data,
|
required this.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
final _i33.Key? key;
|
final _i29.Key? key;
|
||||||
|
|
||||||
final Map<String, dynamic> data;
|
final Map<String, dynamic> data;
|
||||||
|
|
||||||
|
|
@ -550,7 +486,7 @@ class FailureViewArguments {
|
||||||
required this.label,
|
required this.label,
|
||||||
});
|
});
|
||||||
|
|
||||||
final _i33.Key? key;
|
final _i29.Key? key;
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
|
|
@ -571,46 +507,7 @@ class FailureViewArguments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LearnPracticeViewArguments {
|
extension NavigatorStateExtension on _i30.NavigationService {
|
||||||
const LearnPracticeViewArguments({
|
|
||||||
this.key,
|
|
||||||
required this.title,
|
|
||||||
required this.subtitle,
|
|
||||||
required this.buttonLabel,
|
|
||||||
});
|
|
||||||
|
|
||||||
final _i33.Key? key;
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
final String subtitle;
|
|
||||||
|
|
||||||
final String buttonLabel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return '{"key": "$key", "title": "$title", "subtitle": "$subtitle", "buttonLabel": "$buttonLabel"}';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(covariant LearnPracticeViewArguments other) {
|
|
||||||
if (identical(this, other)) return true;
|
|
||||||
return other.key == key &&
|
|
||||||
other.title == title &&
|
|
||||||
other.subtitle == subtitle &&
|
|
||||||
other.buttonLabel == buttonLabel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
return key.hashCode ^
|
|
||||||
title.hashCode ^
|
|
||||||
subtitle.hashCode ^
|
|
||||||
buttonLabel.hashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension NavigatorStateExtension on _i34.NavigationService {
|
|
||||||
Future<dynamic> navigateToHomeView([
|
Future<dynamic> navigateToHomeView([
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -640,7 +537,7 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToStartupView({
|
Future<dynamic> navigateToStartupView({
|
||||||
_i33.Key? key,
|
_i29.Key? key,
|
||||||
String label = 'Loading',
|
String label = 'Loading',
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -909,7 +806,7 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToAssessmentView({
|
Future<dynamic> navigateToAssessmentView({
|
||||||
_i33.Key? key,
|
_i29.Key? key,
|
||||||
required Map<String, dynamic> data,
|
required Map<String, dynamic> data,
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -940,7 +837,7 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToFailureView({
|
Future<dynamic> navigateToFailureView({
|
||||||
_i33.Key? key,
|
_i29.Key? key,
|
||||||
required String label,
|
required String label,
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -984,79 +881,14 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToLearnPracticeView({
|
Future<dynamic> navigateToLearnPracticeView([
|
||||||
_i33.Key? key,
|
|
||||||
required String title,
|
|
||||||
required String subtitle,
|
|
||||||
required String buttonLabel,
|
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
Map<String, String>? parameters,
|
Map<String, String>? parameters,
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
transition,
|
transition,
|
||||||
}) async {
|
]) async {
|
||||||
return navigateTo<dynamic>(Routes.learnPracticeView,
|
return navigateTo<dynamic>(Routes.learnPracticeView,
|
||||||
arguments: LearnPracticeViewArguments(
|
|
||||||
key: key,
|
|
||||||
title: title,
|
|
||||||
subtitle: subtitle,
|
|
||||||
buttonLabel: buttonLabel),
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> navigateToCourseView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return navigateTo<dynamic>(Routes.courseView,
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> navigateToCourseModuleView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return navigateTo<dynamic>(Routes.courseModuleView,
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> navigateToCoursePracticeView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return navigateTo<dynamic>(Routes.coursePracticeView,
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> navigateToCoursePaymentView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return navigateTo<dynamic>(Routes.coursePaymentView,
|
|
||||||
id: routerId,
|
id: routerId,
|
||||||
preventDuplicates: preventDuplicates,
|
preventDuplicates: preventDuplicates,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
|
|
@ -1092,7 +924,7 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithStartupView({
|
Future<dynamic> replaceWithStartupView({
|
||||||
_i33.Key? key,
|
_i29.Key? key,
|
||||||
String label = 'Loading',
|
String label = 'Loading',
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -1361,7 +1193,7 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithAssessmentView({
|
Future<dynamic> replaceWithAssessmentView({
|
||||||
_i33.Key? key,
|
_i29.Key? key,
|
||||||
required Map<String, dynamic> data,
|
required Map<String, dynamic> data,
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -1392,7 +1224,7 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithFailureView({
|
Future<dynamic> replaceWithFailureView({
|
||||||
_i33.Key? key,
|
_i29.Key? key,
|
||||||
required String label,
|
required String label,
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -1436,79 +1268,14 @@ extension NavigatorStateExtension on _i34.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithLearnPracticeView({
|
Future<dynamic> replaceWithLearnPracticeView([
|
||||||
_i33.Key? key,
|
|
||||||
required String title,
|
|
||||||
required String subtitle,
|
|
||||||
required String buttonLabel,
|
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
Map<String, String>? parameters,
|
Map<String, String>? parameters,
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
transition,
|
transition,
|
||||||
}) async {
|
]) async {
|
||||||
return replaceWith<dynamic>(Routes.learnPracticeView,
|
return replaceWith<dynamic>(Routes.learnPracticeView,
|
||||||
arguments: LearnPracticeViewArguments(
|
|
||||||
key: key,
|
|
||||||
title: title,
|
|
||||||
subtitle: subtitle,
|
|
||||||
buttonLabel: buttonLabel),
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> replaceWithCourseView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return replaceWith<dynamic>(Routes.courseView,
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> replaceWithCourseModuleView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return replaceWith<dynamic>(Routes.courseModuleView,
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> replaceWithCoursePracticeView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return replaceWith<dynamic>(Routes.coursePracticeView,
|
|
||||||
id: routerId,
|
|
||||||
preventDuplicates: preventDuplicates,
|
|
||||||
parameters: parameters,
|
|
||||||
transition: transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<dynamic> replaceWithCoursePaymentView([
|
|
||||||
int? routerId,
|
|
||||||
bool preventDuplicates = true,
|
|
||||||
Map<String, String>? parameters,
|
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
|
||||||
transition,
|
|
||||||
]) async {
|
|
||||||
return replaceWith<dynamic>(Routes.coursePaymentView,
|
|
||||||
id: routerId,
|
id: routerId,
|
||||||
preventDuplicates: preventDuplicates,
|
preventDuplicates: preventDuplicates,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,6 @@ class Assessment {
|
||||||
|
|
||||||
final String? status;
|
final String? status;
|
||||||
|
|
||||||
final List<Option>? options;
|
|
||||||
|
|
||||||
|
|
||||||
@JsonKey(name: 'question_type')
|
@JsonKey(name: 'question_type')
|
||||||
final String? questionType;
|
final String? questionType;
|
||||||
|
|
||||||
|
|
@ -22,6 +19,7 @@ class Assessment {
|
||||||
@JsonKey(name: 'difficulty_level')
|
@JsonKey(name: 'difficulty_level')
|
||||||
final String? difficultyLevel;
|
final String? difficultyLevel;
|
||||||
|
|
||||||
|
final List<Option>? options;
|
||||||
|
|
||||||
const Assessment({
|
const Assessment({
|
||||||
this.id,
|
this.id,
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ Map<String, dynamic> _$AssessmentToJson(Assessment instance) =>
|
||||||
'id': instance.id,
|
'id': instance.id,
|
||||||
'points': instance.points,
|
'points': instance.points,
|
||||||
'status': instance.status,
|
'status': instance.status,
|
||||||
'options': instance.options,
|
|
||||||
'question_type': instance.questionType,
|
'question_type': instance.questionType,
|
||||||
'question_text': instance.questionText,
|
'question_text': instance.questionText,
|
||||||
'difficulty_level': instance.difficultyLevel,
|
'difficulty_level': instance.difficultyLevel,
|
||||||
|
'options': instance.options,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,12 @@ class UserModel {
|
||||||
|
|
||||||
final String? country;
|
final String? country;
|
||||||
|
|
||||||
|
|
||||||
final String? occupation;
|
final String? occupation;
|
||||||
|
|
||||||
final bool? userInfoLoaded;
|
final bool? userInfoLoaded;
|
||||||
|
|
||||||
|
|
||||||
@JsonKey(name: 'user_id')
|
@JsonKey(name: 'user_id')
|
||||||
final int? userId;
|
final int? userId;
|
||||||
|
|
||||||
|
|
@ -53,41 +55,10 @@ class UserModel {
|
||||||
this.accessToken,
|
this.accessToken,
|
||||||
this.refreshToken,
|
this.refreshToken,
|
||||||
this.profilePicture,
|
this.profilePicture,
|
||||||
this.userInfoLoaded,
|
this.userInfoLoaded ,
|
||||||
this.profileCompleted,
|
this.profileCompleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
UserModel copyWith(
|
|
||||||
{int? userId,
|
|
||||||
String? email,
|
|
||||||
String? gender,
|
|
||||||
String? region,
|
|
||||||
String? country,
|
|
||||||
String? lastName,
|
|
||||||
String? birthday,
|
|
||||||
String? firstName,
|
|
||||||
String? occupation,
|
|
||||||
String? accessToken,
|
|
||||||
String? refreshToken,
|
|
||||||
bool? userInfoLoaded,
|
|
||||||
bool? profileCompleted,
|
|
||||||
String? profilePicture}) =>
|
|
||||||
UserModel(
|
|
||||||
email: email ?? this.email,
|
|
||||||
userId: userId ?? this.userId,
|
|
||||||
gender: gender ?? this.gender,
|
|
||||||
region: region ?? this.region,
|
|
||||||
country: country ?? this.country,
|
|
||||||
lastName: lastName ?? this.lastName,
|
|
||||||
birthday: birthday ?? this.birthday,
|
|
||||||
firstName: firstName ?? this.firstName,
|
|
||||||
occupation: occupation ?? this.occupation,
|
|
||||||
accessToken: accessToken ?? this.accessToken,
|
|
||||||
refreshToken: refreshToken ?? this.refreshToken,
|
|
||||||
userInfoLoaded: userInfoLoaded ?? this.userInfoLoaded,
|
|
||||||
profilePicture: profilePicture ?? this.profilePicture,
|
|
||||||
profileCompleted: profileCompleted ?? this.profileCompleted);
|
|
||||||
|
|
||||||
factory UserModel.fromJson(Map<String, dynamic> json) =>
|
factory UserModel.fromJson(Map<String, dynamic> json) =>
|
||||||
_$UserModelFromJson(json);
|
_$UserModelFromJson(json);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel(
|
||||||
accessToken: json['access_token'] as String?,
|
accessToken: json['access_token'] as String?,
|
||||||
refreshToken: json['refresh_token'] as String?,
|
refreshToken: json['refresh_token'] as String?,
|
||||||
profilePicture: json['profile_picture_url'] as String?,
|
profilePicture: json['profile_picture_url'] as String?,
|
||||||
userInfoLoaded: json['userInfoLoaded'] as bool?,
|
|
||||||
profileCompleted: json['profile_completed'] as bool?,
|
profileCompleted: json['profile_completed'] as bool?,
|
||||||
|
userInfoLoaded: json['userInfoLoaded'] as bool? ?? false,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
|
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,10 @@ import '../app/app.locator.dart';
|
||||||
import '../ui/common/enmus.dart';
|
import '../ui/common/enmus.dart';
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
// Dependency injection
|
|
||||||
final _service = locator<DioService>();
|
final _service = locator<DioService>();
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
Future<Map<String, dynamic>> registerWithEmail(
|
Future<Map<String, dynamic>> registerWithEmail(Map<String, dynamic> data) async {
|
||||||
Map<String, dynamic> data) async {
|
|
||||||
try {
|
try {
|
||||||
Response response = await _service.dio.post(
|
Response response = await _service.dio.post(
|
||||||
'$kBaseUrl/$kUserUrl/$kRegisterUrl',
|
'$kBaseUrl/$kUserUrl/$kRegisterUrl',
|
||||||
|
|
@ -39,7 +37,7 @@ class ApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Email login
|
// Email Login
|
||||||
Future<Map<String, dynamic>> emailLogin(Map<String, dynamic> data) async {
|
Future<Map<String, dynamic>> emailLogin(Map<String, dynamic> data) async {
|
||||||
try {
|
try {
|
||||||
Response response = await _service.dio.post(
|
Response response = await _service.dio.post(
|
||||||
|
|
|
||||||
|
|
@ -4,20 +4,16 @@ import 'package:yimaru_app/models/user_model.dart';
|
||||||
import 'package:yimaru_app/services/secure_storage_service.dart';
|
import 'package:yimaru_app/services/secure_storage_service.dart';
|
||||||
|
|
||||||
class AuthenticationService with ListenableServiceMixin {
|
class AuthenticationService with ListenableServiceMixin {
|
||||||
// Dependency injection
|
|
||||||
final _secureService = locator<SecureStorageService>();
|
final _secureService = locator<SecureStorageService>();
|
||||||
|
|
||||||
// User data
|
|
||||||
UserModel? _user;
|
|
||||||
|
|
||||||
UserModel? get user => _user;
|
|
||||||
|
|
||||||
// Initialization
|
|
||||||
AuthenticationService() {
|
AuthenticationService() {
|
||||||
listenToReactiveValues([_user]);
|
listenToReactiveValues([_user]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check user logged in
|
UserModel? _user;
|
||||||
|
|
||||||
|
UserModel? get user => _user;
|
||||||
|
|
||||||
Future<bool> userLoggedIn() async {
|
Future<bool> userLoggedIn() async {
|
||||||
if (await _secureService.getString('userId') != null) {
|
if (await _secureService.getString('userId') != null) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -25,18 +21,14 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get access token
|
|
||||||
Future<String?> getAccessToken() async =>
|
Future<String?> getAccessToken() async =>
|
||||||
await _secureService.getString('accessToken');
|
await _secureService.getString('accessToken');
|
||||||
|
|
||||||
// Get refresh token
|
|
||||||
Future<String?> getRefreshToken() async =>
|
Future<String?> getRefreshToken() async =>
|
||||||
await _secureService.getString('refreshToken');
|
await _secureService.getString('refreshToken');
|
||||||
|
|
||||||
// Get user id
|
|
||||||
Future<int?> getUserId() async => await _secureService.getInt('userId');
|
Future<int?> getUserId() async => await _secureService.getInt('userId');
|
||||||
|
|
||||||
// Save tokens
|
|
||||||
Future<void> saveTokens({
|
Future<void> saveTokens({
|
||||||
required String access,
|
required String access,
|
||||||
required String refresh,
|
required String refresh,
|
||||||
|
|
@ -45,7 +37,7 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
await _secureService.setString('refreshToken', refresh);
|
await _secureService.setString('refreshToken', refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save user credential
|
|
||||||
Future<void> saveUserCredential(Map<String, dynamic> data) async {
|
Future<void> saveUserCredential(Map<String, dynamic> data) async {
|
||||||
await _secureService.setInt('userId', data['userId']);
|
await _secureService.setInt('userId', data['userId']);
|
||||||
await _secureService.setString('accessToken', data['accessToken']);
|
await _secureService.setString('accessToken', data['accessToken']);
|
||||||
|
|
@ -58,16 +50,10 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save profile status
|
|
||||||
Future<void> saveProfileStatus(bool value) async {
|
Future<void> saveProfileStatus(bool value) async {
|
||||||
await _secureService.setBool('profileCompleted', value);
|
await _secureService.setBool('profileCompleted', value);
|
||||||
|
|
||||||
_user = _user?.copyWith(
|
_user = UserModel(
|
||||||
userInfoLoaded: _user?.userInfoLoaded ?? false,
|
|
||||||
profileCompleted: await _secureService.getBool('profileCompleted'),
|
|
||||||
);
|
|
||||||
|
|
||||||
/* UserModel(
|
|
||||||
email: _user?.email,
|
email: _user?.email,
|
||||||
gender: _user?.gender,
|
gender: _user?.gender,
|
||||||
region: _user?.region,
|
region: _user?.region,
|
||||||
|
|
@ -82,18 +68,12 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
profilePicture: _user?.profilePicture,
|
profilePicture: _user?.profilePicture,
|
||||||
userInfoLoaded: _user?.userInfoLoaded ?? false,
|
userInfoLoaded: _user?.userInfoLoaded ?? false,
|
||||||
profileCompleted: await _secureService.getBool('profileCompleted'));
|
profileCompleted: await _secureService.getBool('profileCompleted'));
|
||||||
*/
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveProfilePicture(String image) async {
|
Future<void> saveProfileImage(String image) async {
|
||||||
await _secureService.setString('profilePicture', image);
|
await _secureService.setString('profileImage', image);
|
||||||
_user = _user?.copyWith(
|
_user = UserModel(
|
||||||
userInfoLoaded: _user?.userInfoLoaded ?? false,
|
|
||||||
profilePicture: await _secureService.getString('profilePicture'),
|
|
||||||
);
|
|
||||||
|
|
||||||
/*UserModel(
|
|
||||||
email: _user?.email,
|
email: _user?.email,
|
||||||
gender: _user?.gender,
|
gender: _user?.gender,
|
||||||
region: _user?.region,
|
region: _user?.region,
|
||||||
|
|
@ -107,9 +87,9 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
refreshToken: _user?.refreshToken,
|
refreshToken: _user?.refreshToken,
|
||||||
profileCompleted: _user?.profileCompleted,
|
profileCompleted: _user?.profileCompleted,
|
||||||
userInfoLoaded: _user?.userInfoLoaded ?? false,
|
userInfoLoaded: _user?.userInfoLoaded ?? false,
|
||||||
profilePicture: await _secureService.getString('profilePicture'),
|
profilePicture: await _secureService.getString('profileImage'),
|
||||||
);
|
);
|
||||||
*/
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,17 +137,7 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
await _secureService.setString('firstName', data['first_name']);
|
await _secureService.setString('firstName', data['first_name']);
|
||||||
await _secureService.setString('occupation', data['occupation']);
|
await _secureService.setString('occupation', data['occupation']);
|
||||||
|
|
||||||
_user = _user?.copyWith(
|
_user = UserModel(
|
||||||
region: await _secureService.getString('region'),
|
|
||||||
gender: await _secureService.getString('gender'),
|
|
||||||
country: await _secureService.getString('country'),
|
|
||||||
lastName: await _secureService.getString('lastName'),
|
|
||||||
birthday: await _secureService.getString('birthday'),
|
|
||||||
firstName: await _secureService.getString('firstName'),
|
|
||||||
occupation: await _secureService.getString('occupation'),
|
|
||||||
);
|
|
||||||
|
|
||||||
/*UserModel(
|
|
||||||
email: _user?.email,
|
email: _user?.email,
|
||||||
userId: _user?.userId,
|
userId: _user?.userId,
|
||||||
accessToken: _user?.accessToken,
|
accessToken: _user?.accessToken,
|
||||||
|
|
@ -181,7 +151,7 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
birthday: await _secureService.getString('birthday'),
|
birthday: await _secureService.getString('birthday'),
|
||||||
firstName: await _secureService.getString('firstName'),
|
firstName: await _secureService.getString('firstName'),
|
||||||
occupation: await _secureService.getString('occupation'),
|
occupation: await _secureService.getString('occupation'),
|
||||||
);*/
|
);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,8 +175,8 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
occupation: await _secureService.getString('occupation'),
|
occupation: await _secureService.getString('occupation'),
|
||||||
accessToken: await _secureService.getString('accessToken'),
|
accessToken: await _secureService.getString('accessToken'),
|
||||||
refreshToken: await _secureService.getString('refreshToken'),
|
refreshToken: await _secureService.getString('refreshToken'),
|
||||||
|
profilePicture: await _secureService.getString('profileImage'),
|
||||||
userInfoLoaded: await _secureService.getBool('userInfoLoaded'),
|
userInfoLoaded: await _secureService.getBool('userInfoLoaded'),
|
||||||
profilePicture: await _secureService.getString('profilePicture'),
|
|
||||||
profileCompleted: await _secureService.getBool('profileCompleted'),
|
profileCompleted: await _secureService.getBool('profileCompleted'),
|
||||||
);
|
);
|
||||||
return _user;
|
return _user;
|
||||||
|
|
|
||||||
|
|
@ -9,21 +9,15 @@ import '../app/app.locator.dart';
|
||||||
import '../ui/common/app_constants.dart';
|
import '../ui/common/app_constants.dart';
|
||||||
|
|
||||||
class DioService {
|
class DioService {
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
// Initialization
|
|
||||||
final Dio _dio = Dio();
|
final Dio _dio = Dio();
|
||||||
|
|
||||||
Dio get dio => _dio;
|
|
||||||
|
|
||||||
final Dio _refreshDio = Dio(); // separate instance
|
final Dio _refreshDio = Dio(); // separate instance
|
||||||
|
|
||||||
bool _isRefreshing = false;
|
bool _isRefreshing = false;
|
||||||
final List<void Function()> _retryQueue = [];
|
final List<void Function()> _retryQueue = [];
|
||||||
|
|
||||||
// Initialization
|
|
||||||
DioService() {
|
DioService() {
|
||||||
_dio.options
|
_dio.options
|
||||||
..baseUrl = kBaseUrl
|
..baseUrl = kBaseUrl
|
||||||
|
|
@ -39,7 +33,6 @@ class DioService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Response logger
|
|
||||||
void _onResponse(
|
void _onResponse(
|
||||||
Response response,
|
Response response,
|
||||||
ResponseInterceptorHandler handler,
|
ResponseInterceptorHandler handler,
|
||||||
|
|
@ -76,7 +69,6 @@ class DioService {
|
||||||
handler.next(options);
|
handler.next(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error logger
|
|
||||||
Future<void> _onError(
|
Future<void> _onError(
|
||||||
DioException error,
|
DioException error,
|
||||||
ErrorInterceptorHandler handler,
|
ErrorInterceptorHandler handler,
|
||||||
|
|
@ -133,7 +125,6 @@ class DioService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh token
|
|
||||||
Future<bool> _refreshToken() async {
|
Future<bool> _refreshToken() async {
|
||||||
final UserModel? user = await _authenticationService.getUser();
|
final UserModel? user = await _authenticationService.getUser();
|
||||||
|
|
||||||
|
|
@ -164,8 +155,9 @@ class DioService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check request if immediately after token refreshed
|
|
||||||
bool _isRefreshRequest(RequestOptions options) {
|
bool _isRefreshRequest(RequestOptions options) {
|
||||||
return options.path.contains(kRefreshTokenUrl);
|
return options.path.contains(kRefreshTokenUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dio get dio => _dio;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,8 @@ import 'package:google_sign_in/google_sign_in.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_constants.dart';
|
import 'package:yimaru_app/ui/common/app_constants.dart';
|
||||||
|
|
||||||
class GoogleAuthService {
|
class GoogleAuthService {
|
||||||
// Initialization
|
|
||||||
final GoogleSignIn signIn = GoogleSignIn.instance;
|
final GoogleSignIn signIn = GoogleSignIn.instance;
|
||||||
|
|
||||||
// Google authentication
|
|
||||||
Future<GoogleSignInAccount?> googleAuth() async {
|
Future<GoogleSignInAccount?> googleAuth() async {
|
||||||
try {
|
try {
|
||||||
GoogleSignInAccount? googleUser;
|
GoogleSignInAccount? googleUser;
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,8 @@ import '../ui/common/app_constants.dart';
|
||||||
import 'dio_service.dart';
|
import 'dio_service.dart';
|
||||||
|
|
||||||
class ImageDownloaderService {
|
class ImageDownloaderService {
|
||||||
// Dependency injection
|
|
||||||
final _service = locator<DioService>();
|
final _service = locator<DioService>();
|
||||||
|
|
||||||
// Image downloader
|
|
||||||
Future<String> downloader(String? networkImage) async {
|
Future<String> downloader(String? networkImage) async {
|
||||||
late File image;
|
late File image;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,10 @@ import '../app/app.locator.dart';
|
||||||
import '../ui/common/ui_helpers.dart';
|
import '../ui/common/ui_helpers.dart';
|
||||||
|
|
||||||
class ImagePickerService {
|
class ImagePickerService {
|
||||||
// Dependency injection
|
|
||||||
final _permissionHandler = locator<PermissionHandlerService>();
|
final _permissionHandler = locator<PermissionHandlerService>();
|
||||||
|
|
||||||
// Initialization
|
|
||||||
final ImagePicker _picker = ImagePicker();
|
final ImagePicker _picker = ImagePicker();
|
||||||
|
|
||||||
// Pick image from gallery
|
|
||||||
Future<String?> gallery() async {
|
Future<String?> gallery() async {
|
||||||
try {
|
try {
|
||||||
PermissionStatus status =
|
PermissionStatus status =
|
||||||
|
|
@ -35,7 +32,6 @@ class ImagePickerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick image from camera
|
|
||||||
Future<String?> camera() async {
|
Future<String?> camera() async {
|
||||||
try {
|
try {
|
||||||
PermissionStatus status =
|
PermissionStatus status =
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ import 'package:permission_handler/permission_handler.dart';
|
||||||
import '../ui/common/ui_helpers.dart';
|
import '../ui/common/ui_helpers.dart';
|
||||||
|
|
||||||
class PermissionHandlerService {
|
class PermissionHandlerService {
|
||||||
|
|
||||||
// Check permission category
|
|
||||||
Future<PermissionStatus> requestPermission(
|
Future<PermissionStatus> requestPermission(
|
||||||
Permission requestedPermission) async {
|
Permission requestedPermission) async {
|
||||||
if (requestedPermission == Permission.camera) {
|
if (requestedPermission == Permission.camera) {
|
||||||
|
|
@ -19,7 +17,6 @@ class PermissionHandlerService {
|
||||||
return PermissionStatus.denied;
|
return PermissionStatus.denied;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request permission
|
|
||||||
Future<PermissionStatus> request(Permission permission) async {
|
Future<PermissionStatus> request(Permission permission) async {
|
||||||
if (await permission.isDenied) {
|
if (await permission.isDenied) {
|
||||||
final PermissionStatus status = await permission.request();
|
final PermissionStatus status = await permission.request();
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@ extension BoolParsing on String {
|
||||||
}
|
}
|
||||||
|
|
||||||
class SecureStorageService {
|
class SecureStorageService {
|
||||||
// Initialization
|
// Create storage
|
||||||
|
|
||||||
late final FlutterSecureStorage _storage;
|
late final FlutterSecureStorage _storage;
|
||||||
|
|
||||||
SecureStorageService() {
|
SecureStorageService() {
|
||||||
|
|
@ -30,40 +31,33 @@ class SecureStorageService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear storage data
|
|
||||||
Future<void> clear() async {
|
Future<void> clear() async {
|
||||||
_storage.deleteAll();
|
_storage.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get boolean data from storage
|
|
||||||
Future<bool?> getBool(String key) async {
|
Future<bool?> getBool(String key) async {
|
||||||
String? result = await _storage.read(key: key);
|
String? result = await _storage.read(key: key);
|
||||||
return result?.parseBool();
|
return result?.parseBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get string data from storage
|
|
||||||
Future<String?> getString(String key) async {
|
Future<String?> getString(String key) async {
|
||||||
return await _storage.read(key: key);
|
return await _storage.read(key: key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get integer data from storage
|
|
||||||
Future<int?> getInt(String key) async {
|
Future<int?> getInt(String key) async {
|
||||||
return await _storage.read(key: key) == null
|
return await _storage.read(key: key) == null
|
||||||
? null
|
? null
|
||||||
: int.parse(await _storage.read(key: key) ?? '0');
|
: int.parse(await _storage.read(key: key) ?? '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save string data to storage
|
|
||||||
Future<void> setString(String key, String value) async {
|
Future<void> setString(String key, String value) async {
|
||||||
await _storage.write(key: key, value: value);
|
await _storage.write(key: key, value: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save integer data to storage
|
|
||||||
Future<void> setInt(String key, int value) async {
|
Future<void> setInt(String key, int value) async {
|
||||||
await _storage.write(key: key, value: value.toString());
|
await _storage.write(key: key, value: value.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save boolean data to storage
|
|
||||||
Future<void> setBool(String key, bool value) async {
|
Future<void> setBool(String key, bool value) async {
|
||||||
await _storage.write(key: key, value: value.toString());
|
await _storage.write(key: key, value: value.toString());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,28 +8,34 @@ import 'package:yimaru_app/services/secure_storage_service.dart';
|
||||||
import '../app/app.locator.dart';
|
import '../app/app.locator.dart';
|
||||||
|
|
||||||
class StatusCheckerService {
|
class StatusCheckerService {
|
||||||
// Dependency injection
|
|
||||||
final storage = locator<SecureStorageService>();
|
final storage = locator<SecureStorageService>();
|
||||||
|
|
||||||
// Initialization
|
|
||||||
bool _previousConnection = true;
|
bool _previousConnection = true;
|
||||||
|
|
||||||
bool get previousConnection => _previousConnection;
|
bool get previousConnection => _previousConnection;
|
||||||
|
|
||||||
// Get phone battery level
|
|
||||||
Future<int> getBatteryLevel() async {
|
Future<int> getBatteryLevel() async {
|
||||||
final battery = Battery();
|
final battery = Battery();
|
||||||
final batteryLevel = await battery.batteryLevel;
|
final batteryLevel = await battery.batteryLevel;
|
||||||
return batteryLevel;
|
return batteryLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check internet connection
|
Future<bool> userAuthenticated() async {
|
||||||
|
await checkAndUpdate();
|
||||||
|
|
||||||
|
if (await storage.getString('authenticated') != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> checkConnection() async {
|
Future<bool> checkConnection() async {
|
||||||
if (await InternetConnection().hasInternetAccess) {
|
if (await InternetConnection().hasInternetAccess) {
|
||||||
_previousConnection = true;
|
_previousConnection = true;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (_previousConnection) {
|
if (_previousConnection) {
|
||||||
|
// showErrorToast('Check your internet connection');
|
||||||
_previousConnection = false;
|
_previousConnection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +43,6 @@ class StatusCheckerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check phone available storage
|
|
||||||
Future<int> getAvailableStorage() async {
|
Future<int> getAvailableStorage() async {
|
||||||
try {
|
try {
|
||||||
final availableStorage =
|
final availableStorage =
|
||||||
|
|
@ -48,7 +53,6 @@ class StatusCheckerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for latest update
|
|
||||||
Future<void> checkAndUpdate() async {
|
Future<void> checkAndUpdate() async {
|
||||||
const requiredStorage = 500 * 1024 * 1024;
|
const requiredStorage = 500 * 1024 * 1024;
|
||||||
|
|
||||||
|
|
@ -58,12 +62,16 @@ class StatusCheckerService {
|
||||||
await getAvailableStorage(); // Implement getAvailableStorage
|
await getAvailableStorage(); // Implement getAvailableStorage
|
||||||
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
||||||
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
||||||
|
// KewedeConst().showErrorToast(
|
||||||
// 'Unable to update app, please charge your phone & free up space.');
|
// 'Unable to update app, please charge your phone & free up space.');
|
||||||
} else if (batteryLevel < 20) {
|
} else if (batteryLevel < 20) {
|
||||||
|
// KewedeConst()
|
||||||
// .showErrorToast('Unable to update app, please charge your phone.');
|
// .showErrorToast('Unable to update app, please charge your phone.');
|
||||||
} else if (storageAvailable < requiredStorage) {
|
} else if (storageAvailable < requiredStorage) {
|
||||||
|
// KewedeConst()
|
||||||
// .showErrorToast('Unable to update app, please free up space.');
|
// .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)
|
||||||
return; // Prevent update from starting
|
return; // Prevent update from starting
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
const Color kcBlack = Colors.black;
|
const Color kcBlack = Colors.black;
|
||||||
const Color kcRed = Color(0xffFF4C4C);
|
const Color kcRed = Color(0xffFF4C4C);
|
||||||
const Color kcBlue = Color(0xff135BEC);
|
|
||||||
const Color kcGreen = Color(0xFF1DE964);
|
const Color kcGreen = Color(0xFF1DE964);
|
||||||
const Color kcBackgroundColor = kcWhite;
|
const Color kcBackgroundColor = kcWhite;
|
||||||
const Color kcWhite = Color(0xFFFFFFFF);
|
const Color kcWhite = Color(0xFFFFFFFF);
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,8 @@ String kGoogleAuthUrl = 'api/v1/auth/google/android';
|
||||||
|
|
||||||
String kAssessmentsUrl = 'api/v1/assessment/questions';
|
String kAssessmentsUrl = 'api/v1/assessment/questions';
|
||||||
|
|
||||||
|
String kServerClientId =
|
||||||
|
'574860813475-n5o17gpprdqmhcml99tiqhafb17rob0r.apps.googleusercontent.com';
|
||||||
|
|
||||||
String kSampleVideoUrl =
|
String kSampleVideoUrl =
|
||||||
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4';
|
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4';
|
||||||
|
|
||||||
String kServerClientId =
|
|
||||||
'574860813475-n5o17gpprdqmhcml99tiqhafb17rob0r.apps.googleusercontent.com';
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
const String ksHomeBottomSheetTitle = 'Build Great Apps!';
|
|
||||||
|
|
||||||
const String ksSuggestion =
|
const String ksSuggestion =
|
||||||
"15 minutes a day can make you 3x more fluent in 3 month";
|
"15 minutes a day can make you 3x more fluent in 3 month";
|
||||||
const String ksHomeBottomSheetDescription =
|
const String ksHomeBottomSheetTitle = 'Build Great Apps!';
|
||||||
'Stacked is built to help you build better apps. Give us a chance and we\'ll prove it to you. Check out stacked.filledstacks.com to learn more';
|
|
||||||
|
|
||||||
const String ksPrivacyPolicy =
|
const String ksPrivacyPolicy =
|
||||||
'A brief, simple overview of Yimaru’s commitment to user privacy. Our goal is to be transparent about the data we collect and how we use it to enhance your learning experience.';
|
'A brief, simple overview of Yimaru’s commitment to user privacy. Our goal is to be transparent about the data we collect and how we use it to enhance your learning experience.';
|
||||||
|
const String ksHomeBottomSheetDescription =
|
||||||
|
'Stacked is built to help you build better apps. Give us a chance and we\'ll prove it to you. Check out stacked.filledstacks.com to learn more';
|
||||||
|
|
||||||
const String ksTerms = """
|
const String ksTerms = """
|
||||||
<p style="color:#9C2C91;font-size:13px;">
|
<p style="color:#9C2C91;font-size:13px;">
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,16 @@
|
||||||
// Registration type
|
// Registration type
|
||||||
enum RegistrationType { phone, email }
|
enum RegistrationType { phone, email }
|
||||||
|
|
||||||
// Response status
|
// Report status
|
||||||
enum ResponseStatus { success, failure }
|
enum ResponseStatus { success, failure }
|
||||||
|
|
||||||
|
enum ProgressStatuses { pending, started, completed }
|
||||||
|
|
||||||
// Levels
|
// Levels
|
||||||
enum ProficiencyLevels { a1, a2, b1, b2, none }
|
enum ProficiencyLevels { a1, a2, b1, b2, none }
|
||||||
|
|
||||||
// Progress status
|
|
||||||
enum ProgressStatuses { pending, started, completed }
|
|
||||||
|
|
||||||
// State object
|
// State object
|
||||||
enum StateObjects {
|
enum StateObjects {
|
||||||
homeView,
|
|
||||||
verifyOtp,
|
verifyOtp,
|
||||||
resendOtp,
|
resendOtp,
|
||||||
profileImage,
|
profileImage,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
// Split full name
|
|
||||||
Map<String, String> splitFullName(String fullName) {
|
Map<String, String> splitFullName(String fullName) {
|
||||||
final parts = fullName.trim().split(RegExp(r'\s+'));
|
final parts = fullName.trim().split(RegExp(r'\s+'));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,12 +178,6 @@ TextStyle style18P600 = const TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style16W600 = const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: kcWhite,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style18W600 = const TextStyle(
|
TextStyle style18W600 = const TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: kcWhite,
|
color: kcWhite,
|
||||||
|
|
@ -196,11 +190,6 @@ TextStyle style25W600 = const TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style12RP600 = const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: kcPrimaryColor,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style12R700 = const TextStyle(
|
TextStyle style12R700 = const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
|
@ -208,19 +197,10 @@ TextStyle style12R700 = const TextStyle(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style12DG400 = const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style14P400 = const TextStyle(
|
TextStyle style14P400 = const TextStyle(
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style14B400 = const TextStyle(
|
|
||||||
color: kcBlue,
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style14P600 = const TextStyle(
|
TextStyle style14P600 = const TextStyle(
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -238,45 +218,22 @@ TextStyle style25DG600 = const TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style16P600 = const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: kcPrimaryColor,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style16DG500 = const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style16DG600 = const TextStyle(
|
TextStyle style16DG600 = const TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: kcDarkGrey,
|
color: kcDarkGrey,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style16B600 = const TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: kcBlue,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style18DG500 = const TextStyle(
|
TextStyle style18DG500 = const TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: kcDarkGrey,
|
color: kcDarkGrey,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style18DG700 = const TextStyle(
|
TextStyle style18DG600 = const TextStyle(
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: kcDarkGrey,
|
color: kcDarkGrey,
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w600,
|
||||||
);
|
|
||||||
|
|
||||||
TextStyle style20DG700 = const TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
TextStyle style16DG400 = const TextStyle(
|
TextStyle style16DG400 = const TextStyle(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:email_validator/email_validator.dart';
|
import 'package:email_validator/email_validator.dart';
|
||||||
|
|
||||||
class FormValidator {
|
class FormValidator {
|
||||||
// Form validator
|
|
||||||
static String? validateForm(String? value) {
|
static String? validateForm(String? value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -13,37 +12,6 @@ class FormValidator {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Email validator
|
|
||||||
static String? validateEmail(String? value) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.isEmpty) {
|
|
||||||
return 'The field is required';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!EmailValidator.validate(value)) {
|
|
||||||
return 'Invalid email format';
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Password validator
|
|
||||||
static String? validatePassword(String? value) {
|
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value.isEmpty) {
|
|
||||||
return 'The field is required';
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phone number validator
|
|
||||||
static String? validatePhoneNumber(String? value) {
|
static String? validatePhoneNumber(String? value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -67,4 +35,30 @@ class FormValidator {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String? validateEmail(String? value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.isEmpty) {
|
||||||
|
return 'The field is required';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EmailValidator.validate(value)) {
|
||||||
|
return 'Invalid email format';
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String? validatePassword(String? value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.isEmpty) {
|
||||||
|
return 'The field is required';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ class AccountPrivacyView extends StackedView<AccountPrivacyViewModel> {
|
||||||
const AccountPrivacyView({Key? key}) : super(key: key);
|
const AccountPrivacyView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AccountPrivacyViewModel viewModelBuilder(BuildContext context) =>
|
AccountPrivacyViewModel viewModelBuilder(
|
||||||
|
BuildContext context,
|
||||||
|
) =>
|
||||||
AccountPrivacyViewModel();
|
AccountPrivacyViewModel();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -55,9 +57,8 @@ class AccountPrivacyView extends StackedView<AccountPrivacyViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(AccountPrivacyViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(AccountPrivacyViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.pop,
|
|
||||||
title: 'Account Privacy',
|
title: 'Account Privacy',
|
||||||
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(AccountPrivacyViewModel viewModel) =>
|
Widget _buildContentWrapper(AccountPrivacyViewModel viewModel) =>
|
||||||
|
|
@ -106,7 +107,7 @@ class AccountPrivacyView extends StackedView<AccountPrivacyViewModel> {
|
||||||
|
|
||||||
Widget _buildHeader(String title) => Text(
|
Widget _buildHeader(String title) => Text(
|
||||||
title,
|
title,
|
||||||
style: style18DG700,
|
style: style18DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLanguageMenu(AccountPrivacyViewModel viewModel) =>
|
Widget _buildLanguageMenu(AccountPrivacyViewModel viewModel) =>
|
||||||
|
|
@ -145,8 +146,8 @@ class AccountPrivacyView extends StackedView<AccountPrivacyViewModel> {
|
||||||
);
|
);
|
||||||
Widget _buildDeleteButton() => CustomElevatedButton(
|
Widget _buildDeleteButton() => CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
|
||||||
text: 'Delete Account',
|
text: 'Delete Account',
|
||||||
|
borderRadius: 12,
|
||||||
foregroundColor: kcRed,
|
foregroundColor: kcRed,
|
||||||
backgroundColor: kcRed.withOpacity(0.25),
|
backgroundColor: kcRed.withOpacity(0.25),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import 'package:yimaru_app/app/app.router.dart';
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
|
|
||||||
class AccountPrivacyViewModel extends BaseViewModel {
|
class AccountPrivacyViewModel extends BaseViewModel {
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,6 @@ class AssessmentView extends StackedView<AssessmentViewModel> {
|
||||||
super.onViewModelReady(viewModel);
|
super.onViewModelReady(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
AssessmentViewModel viewModelBuilder(BuildContext context) => AssessmentViewModel();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget builder(
|
Widget builder(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
|
@ -68,5 +65,9 @@ class AssessmentView extends StackedView<AssessmentViewModel> {
|
||||||
|
|
||||||
Widget _buildStartLesson() => const StartLessonScreen();
|
Widget _buildStartLesson() => const StartLessonScreen();
|
||||||
|
|
||||||
|
@override
|
||||||
|
AssessmentViewModel viewModelBuilder(
|
||||||
|
BuildContext context,
|
||||||
|
) =>
|
||||||
|
AssessmentViewModel();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ import '../../common/ui_helpers.dart';
|
||||||
import '../home/home_view.dart';
|
import '../home/home_view.dart';
|
||||||
|
|
||||||
class AssessmentViewModel extends BaseViewModel {
|
class AssessmentViewModel extends BaseViewModel {
|
||||||
// Dependency injection
|
|
||||||
final _apiService = locator<ApiService>();
|
final _apiService = locator<ApiService>();
|
||||||
final _dialogService = locator<DialogService>();
|
final _dialogService = locator<DialogService>();
|
||||||
final _statusChecker = locator<StatusCheckerService>();
|
final _statusChecker = locator<StatusCheckerService>();
|
||||||
|
|
@ -208,7 +207,6 @@ class AssessmentViewModel extends BaseViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// In-app navigation
|
|
||||||
void next({int? page}) async {
|
void next({int? page}) async {
|
||||||
if (page == null) {
|
if (page == null) {
|
||||||
if (_previousPage != 0) {
|
if (_previousPage != 0) {
|
||||||
|
|
@ -237,7 +235,7 @@ class AssessmentViewModel extends BaseViewModel {
|
||||||
await _navigationService.navigateToLanguageView();
|
await _navigationService.navigateToLanguageView();
|
||||||
|
|
||||||
Future<void> replaceWithHome() async =>
|
Future<void> replaceWithHome() async =>
|
||||||
await _navigationService.clearStackAndShow(Routes.homeView);
|
await _navigationService.clearStackAndShowView(const HomeView());
|
||||||
|
|
||||||
// Remote api call
|
// Remote api call
|
||||||
Future<void> getAssessments() async => await runBusyFuture(_getAssessments());
|
Future<void> getAssessments() async => await runBusyFuture(_getAssessments());
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@ class AssessmentCompletionScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'We’re now analyzing your speaking skills',
|
'We’re now analyzing your speaking skills',
|
||||||
style: style14MG400,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,8 @@ class AssessmentFailureScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'Your assessment wasn’t long enough for us to analyze your speaking level. You can retake the call to get accurate results ',
|
'Your assessment wasn’t long enough for us to analyze your speaking level. You can retake the call to get accurate results ',
|
||||||
style: style14MG400,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLowerColumn(AssessmentViewModel viewModel) => Column(
|
Widget _buildLowerColumn(AssessmentViewModel viewModel) => Column(
|
||||||
|
|
@ -98,9 +97,9 @@ class AssessmentFailureScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
height: 55,
|
height: 55,
|
||||||
safe: false,
|
safe: false,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
|
||||||
text: 'Continue Assessment',
|
text: 'Continue Assessment',
|
||||||
onTap: () => viewModel.next(),
|
onTap: () => viewModel.next(),
|
||||||
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,9 @@ class AssessmentFormScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
text: viewModel.currentQuestion == viewModel.assessments.length - 1
|
||||||
|
? 'Finish'
|
||||||
|
: 'Continue',
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
viewModel.selectedAnswers.containsKey(question.toString())
|
viewModel.selectedAnswers.containsKey(question.toString())
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
|
|
@ -162,8 +165,5 @@ class AssessmentFormScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
onTap: viewModel.selectedAnswers.containsKey(question.toString())
|
onTap: viewModel.selectedAnswers.containsKey(question.toString())
|
||||||
? () => viewModel.nextQuestion()
|
? () => viewModel.nextQuestion()
|
||||||
: null,
|
: null,
|
||||||
text: viewModel.currentQuestion == viewModel.assessments.length - 1
|
|
||||||
? 'Finish'
|
|
||||||
: 'Continue',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart';
|
import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart';
|
||||||
|
|
||||||
import '../../../common/app_colors.dart';
|
import '../../../common/app_colors.dart';
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ class AssessmentResultScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
|
|
||||||
Widget _buildPrimarySubtitle() => Text(
|
Widget _buildPrimarySubtitle() => Text(
|
||||||
'Great Job! Here’s your next step to keep improving.',
|
'Great Job! Here’s your next step to keep improving.',
|
||||||
style: style14MG400,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: style14MG400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildIconWrapper(AssessmentViewModel viewModel) =>
|
Widget _buildIconWrapper(AssessmentViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -100,9 +100,9 @@ class RetakeAssessmentScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
height: 55,
|
height: 55,
|
||||||
safe: false,
|
safe: false,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
|
||||||
text: 'Retake Assessment',
|
text: 'Retake Assessment',
|
||||||
onTap: () => viewModel.next(),
|
onTap: () => viewModel.next(),
|
||||||
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -116,9 +116,9 @@ class RetakeAssessmentScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Skip',
|
text: 'Skip',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
backgroundColor: kcWhite,
|
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
onTap: () => viewModel.next(),
|
onTap: () => viewModel.next(),
|
||||||
|
backgroundColor: kcWhite,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
||||||
const CallSupportView({Key? key}) : super(key: key);
|
const CallSupportView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
CallSupportViewModel viewModelBuilder(BuildContext context) =>
|
CallSupportViewModel viewModelBuilder(
|
||||||
|
BuildContext context,
|
||||||
|
) =>
|
||||||
CallSupportViewModel();
|
CallSupportViewModel();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -48,9 +50,8 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(CallSupportViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(CallSupportViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.pop,
|
|
||||||
title: 'Call Support',
|
title: 'Call Support',
|
||||||
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedColumn(CallSupportViewModel viewModel) =>
|
Widget _buildExpandedColumn(CallSupportViewModel viewModel) =>
|
||||||
|
|
@ -83,9 +84,9 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildSubtitle('+2519012345678'),
|
_buildSubTitle('+2519012345678'),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSubtitle('+2519012345678'),
|
_buildSubTitle('+2519012345678'),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildIcon() =>
|
Widget _buildIcon() =>
|
||||||
|
|
@ -97,10 +98,10 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle(String title) => Text(
|
Widget _buildSubTitle(String title) => Text(
|
||||||
title,
|
title,
|
||||||
style: style14P400,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: const TextStyle(color: kcPrimaryColor),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(CallSupportViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(CallSupportViewModel viewModel) => Padding(
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,6 @@ import 'package:stacked_services/stacked_services.dart';
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
|
|
||||||
class CallSupportViewModel extends BaseViewModel {
|
class CallSupportViewModel extends BaseViewModel {
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/course_card.dart';
|
|
||||||
|
|
||||||
import '../../common/app_colors.dart';
|
|
||||||
import '../../common/ui_helpers.dart';
|
|
||||||
import '../../widgets/learn_app_bar.dart';
|
|
||||||
import 'course_viewmodel.dart';
|
|
||||||
|
|
||||||
class CourseView extends StackedView<CourseViewModel> {
|
|
||||||
const CourseView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
CourseViewModel viewModelBuilder(BuildContext context) => CourseViewModel();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget builder(
|
|
||||||
BuildContext context,
|
|
||||||
CourseViewModel viewModel,
|
|
||||||
Widget? child,
|
|
||||||
) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(CourseViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(CourseViewModel viewModel) =>
|
|
||||||
SafeArea(child: _buildBody(viewModel));
|
|
||||||
|
|
||||||
Widget _buildBody(CourseViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildColumn(CourseViewModel viewModel) => Column(
|
|
||||||
children: [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildCourseColumnWrapper(viewModel)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAppBar(CourseViewModel viewModel) => LearnAppBar(
|
|
||||||
name: viewModel.user?.firstName,
|
|
||||||
profileImage: viewModel.user?.profilePicture,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildCourseColumnWrapper(CourseViewModel viewModel) =>
|
|
||||||
Expanded(child: _buildCourseColumnScrollView(viewModel));
|
|
||||||
|
|
||||||
Widget _buildCourseColumnScrollView(CourseViewModel viewModel) =>
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: _buildCourseColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildCourseColumn(CourseViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildLevelsColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLevelsColumnChildren(CourseViewModel viewModel) => [
|
|
||||||
verticalSpaceLarge,
|
|
||||||
_buildTitle(),
|
|
||||||
_buildSubtitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildListView(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
'Courses',
|
|
||||||
style: style20DG700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
'Choose a course to improve your professional or exam skills.',
|
|
||||||
style: style14DG400,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildListView(CourseViewModel viewModel) => ListView.separated(
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: viewModel.courses.length,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) => _buildTile(
|
|
||||||
title: viewModel.courses[index]['title'],
|
|
||||||
subtitle: viewModel.courses[index]['subtitle'],
|
|
||||||
onTap: () async => await viewModel.navigateToCourseModule(),
|
|
||||||
),
|
|
||||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
|
||||||
Widget _buildTile({
|
|
||||||
required String title,
|
|
||||||
required String subtitle,
|
|
||||||
required GestureTapCallback onTap,
|
|
||||||
}) =>
|
|
||||||
CourseCard(
|
|
||||||
title: title,
|
|
||||||
onTap: onTap,
|
|
||||||
subtitle: subtitle,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
|
||||||
import 'package:yimaru_app/app/app.router.dart';
|
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
|
||||||
import '../../../models/user_model.dart';
|
|
||||||
import '../../../services/authentication_service.dart';
|
|
||||||
|
|
||||||
class CourseViewModel extends ReactiveViewModel {
|
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
|
||||||
[_authenticationService];
|
|
||||||
|
|
||||||
// Current user
|
|
||||||
UserModel? get _user => _authenticationService.user;
|
|
||||||
|
|
||||||
UserModel? get user => _user;
|
|
||||||
|
|
||||||
// Courses
|
|
||||||
final List<Map<String, dynamic>> _courses = [
|
|
||||||
{
|
|
||||||
'title': 'English Proficiency Exams',
|
|
||||||
'subtitle':
|
|
||||||
'Prepare for IELTS, TOEFL, or Duolingo with structured practice.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'Skill-Based Courses',
|
|
||||||
'subtitle':
|
|
||||||
'Learn English for the workplace, travel, and real-life communication.',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> get courses => _courses;
|
|
||||||
|
|
||||||
// Navigation
|
|
||||||
Future<void> navigateToCourseModule() async =>
|
|
||||||
_navigationService.navigateToCourseModuleView();
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/course_module_tile.dart';
|
|
||||||
|
|
||||||
import '../../common/app_colors.dart';
|
|
||||||
import '../../common/ui_helpers.dart';
|
|
||||||
import '../../widgets/small_app_bar.dart';
|
|
||||||
import 'course_module_viewmodel.dart';
|
|
||||||
|
|
||||||
class CourseModuleView extends StackedView<CourseModuleViewModel> {
|
|
||||||
const CourseModuleView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
CourseModuleViewModel viewModelBuilder(BuildContext context) =>
|
|
||||||
CourseModuleViewModel();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget builder(
|
|
||||||
BuildContext context,
|
|
||||||
CourseModuleViewModel viewModel,
|
|
||||||
Widget? child,
|
|
||||||
) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(CourseModuleViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(CourseModuleViewModel viewModel) =>
|
|
||||||
SafeArea(child: _buildBody(viewModel));
|
|
||||||
|
|
||||||
Widget _buildBody(CourseModuleViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildColumn(CourseModuleViewModel viewModel) => Column(
|
|
||||||
children: [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildLevelsColumnWrapper(viewModel),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAppBar(CourseModuleViewModel viewModel) => SmallAppBar(
|
|
||||||
onTap: viewModel.pop,
|
|
||||||
showBackButton: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLevelsColumnWrapper(CourseModuleViewModel viewModel) =>
|
|
||||||
Expanded(child: _buildLevelsColumnScrollView(viewModel));
|
|
||||||
|
|
||||||
Widget _buildLevelsColumnScrollView(CourseModuleViewModel viewModel) =>
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: _buildLevelsColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLevelsColumn(CourseModuleViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildLevelsColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLevelsColumnChildren(CourseModuleViewModel viewModel) => [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildTitle(),
|
|
||||||
_buildSubtitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildListView(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
'English Proficiency Exams',
|
|
||||||
style: style20DG700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
'Select your target exam and start preparing',
|
|
||||||
style: style14DG400,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildListView(CourseModuleViewModel viewModel) => ListView.separated(
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: viewModel.modules.length,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) => _buildTile(
|
|
||||||
title: viewModel.modules[index]['title'],
|
|
||||||
onPracticeTap: () async =>
|
|
||||||
await viewModel.navigateToCoursePractice(),
|
|
||||||
onCourseTap: () async => await viewModel.navigateToCoursePayment()),
|
|
||||||
separatorBuilder: (context, index) => verticalSpaceMedium,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildTile({
|
|
||||||
required String title,
|
|
||||||
GestureTapCallback? onCourseTap,
|
|
||||||
GestureTapCallback? onPracticeTap,
|
|
||||||
}) =>
|
|
||||||
CourseModuleTile(
|
|
||||||
title: title,
|
|
||||||
onCourseTap: onCourseTap,
|
|
||||||
onPracticeTap: onPracticeTap,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
|
||||||
import 'package:yimaru_app/app/app.router.dart';
|
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
|
||||||
|
|
||||||
class CourseModuleViewModel extends BaseViewModel {
|
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
|
||||||
|
|
||||||
// Course modules
|
|
||||||
final List<Map<String, dynamic>> _modules = [
|
|
||||||
{
|
|
||||||
'title': 'Duolingo English Test',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'IELTS',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> get modules => _modules;
|
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
|
||||||
|
|
||||||
Future<void> navigateToCoursePractice() async =>
|
|
||||||
_navigationService.navigateToCoursePracticeView();
|
|
||||||
|
|
||||||
Future<void> navigateToCoursePayment() async =>
|
|
||||||
_navigationService.navigateToCoursePaymentView();
|
|
||||||
}
|
|
||||||
|
|
@ -1,91 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/course_payment_card.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_list_tile.dart';
|
|
||||||
|
|
||||||
import '../../common/app_colors.dart';
|
|
||||||
import '../../common/ui_helpers.dart';
|
|
||||||
import '../../widgets/small_app_bar.dart';
|
|
||||||
import 'course_payment_viewmodel.dart';
|
|
||||||
|
|
||||||
class CoursePaymentView extends StackedView<CoursePaymentViewModel> {
|
|
||||||
const CoursePaymentView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
CoursePaymentViewModel viewModelBuilder(BuildContext context) =>
|
|
||||||
CoursePaymentViewModel();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget builder(
|
|
||||||
BuildContext context,
|
|
||||||
CoursePaymentViewModel viewModel,
|
|
||||||
Widget? child,
|
|
||||||
) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(CoursePaymentViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(CoursePaymentViewModel viewModel) =>
|
|
||||||
SafeArea(child: _buildBody(viewModel));
|
|
||||||
|
|
||||||
Widget _buildBody(CoursePaymentViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildColumn(CoursePaymentViewModel viewModel) => Column(
|
|
||||||
children: [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildPracticeColumnWrapper(viewModel),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAppBar(CoursePaymentViewModel viewModel) => SmallAppBar(
|
|
||||||
onTap: viewModel.pop,
|
|
||||||
showBackButton: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildPracticeColumnWrapper(CoursePaymentViewModel viewModel) =>
|
|
||||||
Expanded(child: _buildPracticeColumnScrollView(viewModel));
|
|
||||||
|
|
||||||
Widget _buildPracticeColumnScrollView(CoursePaymentViewModel viewModel) =>
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: _buildPracticeColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildPracticeColumn(CoursePaymentViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: _buildPracticeColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildPracticeColumnChildren(CoursePaymentViewModel viewModel) =>
|
|
||||||
[
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildFirstCard(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildSecondCard()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
'Unlock All Lessons & Practices',
|
|
||||||
style: style20DG700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildFirstCard() => const CoursePaymentCard(
|
|
||||||
icon: Icons.school,
|
|
||||||
title: '50+ New Lessons',
|
|
||||||
subtitle: 'Access fresh, advanced content',
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSecondCard() => const CoursePaymentCard(
|
|
||||||
icon: Icons.developer_board,
|
|
||||||
title: 'Mastery Through Practice',
|
|
||||||
subtitle: 'Practice All Question Types & Take Mock Exams',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
|
||||||
|
|
||||||
class CoursePaymentViewModel extends BaseViewModel {
|
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
|
||||||
}
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/course_practice_card.dart';
|
|
||||||
|
|
||||||
import '../../common/app_colors.dart';
|
|
||||||
import '../../common/ui_helpers.dart';
|
|
||||||
import '../../widgets/small_app_bar.dart';
|
|
||||||
import 'course_practice_viewmodel.dart';
|
|
||||||
|
|
||||||
class CoursePracticeView extends StackedView<CoursePracticeViewModel> {
|
|
||||||
const CoursePracticeView({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
CoursePracticeViewModel viewModelBuilder(BuildContext context) =>
|
|
||||||
CoursePracticeViewModel();
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget builder(
|
|
||||||
BuildContext context,
|
|
||||||
CoursePracticeViewModel viewModel,
|
|
||||||
Widget? child,
|
|
||||||
) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(CoursePracticeViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(CoursePracticeViewModel viewModel) =>
|
|
||||||
SafeArea(child: _buildBody(viewModel));
|
|
||||||
|
|
||||||
Widget _buildBody(CoursePracticeViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildColumn(CoursePracticeViewModel viewModel) => Column(
|
|
||||||
children: [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildPracticeColumnWrapper(viewModel),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAppBar(CoursePracticeViewModel viewModel) => SmallAppBar(
|
|
||||||
onTap: viewModel.pop,
|
|
||||||
showBackButton: true,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildPracticeColumnWrapper(CoursePracticeViewModel viewModel) =>
|
|
||||||
Expanded(child: _buildPracticeColumnScrollView(viewModel));
|
|
||||||
|
|
||||||
Widget _buildPracticeColumnScrollView(CoursePracticeViewModel viewModel) =>
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: _buildPracticeColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildPracticeColumn(CoursePracticeViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildPracticeColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildPracticeColumnChildren(
|
|
||||||
CoursePracticeViewModel viewModel) =>
|
|
||||||
[
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildTitle(),
|
|
||||||
_buildSubtitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildListView(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
'Duolingo Mock Tests',
|
|
||||||
style: style20DG700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
'Select your target exam and start preparing',
|
|
||||||
style: style14DG400,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildListView(CoursePracticeViewModel viewModel) => GridView.builder(
|
|
||||||
itemCount: 6,
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) =>
|
|
||||||
_buildCard(title: viewModel.practices[index]['title']),
|
|
||||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
|
||||||
crossAxisCount: 2,
|
|
||||||
mainAxisSpacing: 15,
|
|
||||||
crossAxisSpacing: 15,
|
|
||||||
childAspectRatio: 1.45,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildCard({
|
|
||||||
required String title,
|
|
||||||
}) =>
|
|
||||||
CoursePracticeCard(title: title);
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
|
||||||
|
|
||||||
class CoursePracticeViewModel extends BaseViewModel {
|
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
|
||||||
|
|
||||||
// Practices
|
|
||||||
final List<Map<String, dynamic>> _practices = [
|
|
||||||
{
|
|
||||||
'title': 'Test 01',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'Test 02',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'Test 03',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'Test 04',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'Test 05',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'title': 'Test 06',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> get practices => _practices;
|
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
|
||||||
}
|
|
||||||
|
|
@ -13,7 +13,9 @@ class DownloadsView extends StackedView<DownloadsViewModel> {
|
||||||
const DownloadsView({Key? key}) : super(key: key);
|
const DownloadsView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
DownloadsViewModel viewModelBuilder(BuildContext context) =>
|
DownloadsViewModel viewModelBuilder(
|
||||||
|
BuildContext context,
|
||||||
|
) =>
|
||||||
DownloadsViewModel();
|
DownloadsViewModel();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -52,9 +54,8 @@ class DownloadsView extends StackedView<DownloadsViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppbar(DownloadsViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(DownloadsViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
|
||||||
showBackButton: true,
|
|
||||||
title: 'Offline Downloads',
|
title: 'Offline Downloads',
|
||||||
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(DownloadsViewModel viewModel) =>
|
Widget _buildContentWrapper(DownloadsViewModel viewModel) =>
|
||||||
|
|
@ -93,11 +94,20 @@ class DownloadsView extends StackedView<DownloadsViewModel> {
|
||||||
List<Widget> _buildStorageInfoChildren(DownloadsViewModel viewModel) =>
|
List<Widget> _buildStorageInfoChildren(DownloadsViewModel viewModel) =>
|
||||||
[_buildStorageInfo(), _buildManageButton(viewModel)];
|
[_buildStorageInfo(), _buildManageButton(viewModel)];
|
||||||
|
|
||||||
Widget _buildStorageInfo() => Text.rich(
|
Widget _buildStorageInfo() => const Text.rich(
|
||||||
TextSpan(text: '1.2GB', style: style14P600, children: [
|
TextSpan(
|
||||||
|
text: '1.2GB',
|
||||||
|
style: TextStyle(
|
||||||
|
color: kcPrimaryColor,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' used of 2GB',
|
text: ' used of 2GB',
|
||||||
style: style14DG600,
|
style: TextStyle(
|
||||||
|
color: kcDarkGrey,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
@ -105,9 +115,12 @@ class DownloadsView extends StackedView<DownloadsViewModel> {
|
||||||
Widget _buildManageButton(DownloadsViewModel viewModel) => TextButton(
|
Widget _buildManageButton(DownloadsViewModel viewModel) => TextButton(
|
||||||
onPressed: viewModel.setShowDownload, child: _buildManageText());
|
onPressed: viewModel.setShowDownload, child: _buildManageText());
|
||||||
|
|
||||||
Widget _buildManageText() => Text(
|
Widget _buildManageText() => const Text(
|
||||||
'Manage Storage',
|
'Manage Storage',
|
||||||
style: style14P600,
|
style: TextStyle(
|
||||||
|
color: kcPrimaryColor,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildStorageIndicator() => const CustomLinearProgressIndicator(
|
Widget _buildStorageIndicator() => const CustomLinearProgressIndicator(
|
||||||
|
|
@ -174,16 +187,20 @@ class DownloadsView extends StackedView<DownloadsViewModel> {
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildEmptyTitle() => Text(
|
Widget _buildEmptyTitle() => const Text(
|
||||||
'Looking for something to download?',
|
'Looking for something to download?',
|
||||||
style: style25DG600,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 25,
|
||||||
|
color: kcDarkGrey,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildEmptySubtitle() => Text(
|
Widget _buildEmptySubtitle() => const Text(
|
||||||
'Start by exploring your learning materials and save them for offline access.',
|
'Start by exploring your learning materials and save them for offline access.',
|
||||||
style: style14MG400,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildGoButtonWrapper(DownloadsViewModel viewModel) => Padding(
|
Widget _buildGoButtonWrapper(DownloadsViewModel viewModel) => Padding(
|
||||||
|
|
@ -193,9 +210,9 @@ class DownloadsView extends StackedView<DownloadsViewModel> {
|
||||||
Widget _buildGoButton(DownloadsViewModel viewModel) => CustomElevatedButton(
|
Widget _buildGoButton(DownloadsViewModel viewModel) => CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
|
||||||
text: 'Go to Learn Section',
|
text: 'Go to Learn Section',
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
onTap: viewModel.setShowDownload,
|
onTap: viewModel.setShowDownload,
|
||||||
|
foregroundColor: kcWhite,
|
||||||
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,11 @@ import 'package:stacked_services/stacked_services.dart';
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
|
|
||||||
class DownloadsViewModel extends BaseViewModel {
|
class DownloadsViewModel extends BaseViewModel {
|
||||||
// Dependency injection
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
// Show download
|
|
||||||
bool _showDownload = false;
|
bool _showDownload = false;
|
||||||
|
|
||||||
bool get showDownload => _showDownload;
|
bool get showDownload => _showDownload;
|
||||||
|
|
||||||
// Downloads
|
// Downloads
|
||||||
final List<Map<String, dynamic>> _downloads = [
|
final List<Map<String, dynamic>> _downloads = [
|
||||||
{
|
{
|
||||||
|
|
@ -36,12 +33,10 @@ class DownloadsViewModel extends BaseViewModel {
|
||||||
|
|
||||||
List<Map<String, dynamic>> get downloads => _downloads;
|
List<Map<String, dynamic>> get downloads => _downloads;
|
||||||
|
|
||||||
// Show download
|
|
||||||
void setShowDownload() {
|
void setShowDownload() {
|
||||||
_showDownload = !_showDownload;
|
_showDownload = !_showDownload;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ class ForgetPasswordView extends StackedView<ForgetPasswordViewModel>
|
||||||
confirmPasswordController.clear();
|
confirmPasswordController.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void _clearDataOnNavigation(ForgetPasswordViewModel viewModel) {
|
void _clearDataOnNavigation(ForgetPasswordViewModel viewModel) {
|
||||||
if (viewModel.currentPage == 0) {
|
if (viewModel.currentPage == 0) {
|
||||||
emailController.clear();
|
emailController.clear();
|
||||||
|
|
@ -75,6 +77,10 @@ class ForgetPasswordView extends StackedView<ForgetPasswordViewModel>
|
||||||
_pop(value: value, viewModel: viewModel),
|
_pop(value: value, viewModel: viewModel),
|
||||||
child: _buildBody(viewModel));
|
child: _buildBody(viewModel));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildBody(ForgetPasswordViewModel viewModel) =>
|
Widget _buildBody(ForgetPasswordViewModel viewModel) =>
|
||||||
IndexedStack(index: viewModel.currentPage, children: _buildScreens());
|
IndexedStack(index: viewModel.currentPage, children: _buildScreens());
|
||||||
|
|
||||||
|
|
@ -90,4 +96,6 @@ class ForgetPasswordView extends StackedView<ForgetPasswordViewModel>
|
||||||
passwordController: passwordController,
|
passwordController: passwordController,
|
||||||
resetCodeController: resetCodeController,
|
resetCodeController: resetCodeController,
|
||||||
confirmPasswordController: confirmPasswordController);
|
confirmPasswordController: confirmPasswordController);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:yimaru_app/ui/views/login/login_view.dart';
|
import 'package:yimaru_app/ui/views/login/login_view.dart';
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../app/app.router.dart';
|
|
||||||
import '../../../services/api_service.dart';
|
import '../../../services/api_service.dart';
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
import '../../common/enmus.dart';
|
import '../../common/enmus.dart';
|
||||||
|
|
@ -191,7 +190,7 @@ class ForgetPasswordViewModel extends FormViewModel {
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> replaceWithLogin() async =>
|
Future<void> replaceWithLogin() async =>
|
||||||
await _navigationService.clearStackAndShow(Routes.loginView);
|
await _navigationService.clearStackAndShowView(const LoginView());
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,10 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
required this.emailController,
|
required this.emailController,
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget getPadding(context) {
|
|
||||||
double half = screenHeight(context) / 2;
|
Widget getPadding(context){
|
||||||
return SizedBox(
|
double half = screenHeight(context)/2;
|
||||||
height: half + 375 - half,
|
return SizedBox(height: half + 375 - half,);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _inAppPop(ForgetPasswordViewModel viewModel) {
|
void _inAppPop(ForgetPasswordViewModel viewModel) {
|
||||||
|
|
@ -35,6 +34,7 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
void _clearDataOnNavigation(ForgetPasswordViewModel viewModel) {
|
void _clearDataOnNavigation(ForgetPasswordViewModel viewModel) {
|
||||||
emailController.clear();
|
emailController.clear();
|
||||||
viewModel.resetRequestResetCodeScreen();
|
viewModel.resetRequestResetCodeScreen();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addUserData(ForgetPasswordViewModel viewModel) async {
|
Future<void> _addUserData(ForgetPasswordViewModel viewModel) async {
|
||||||
|
|
@ -48,44 +48,34 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
await viewModel.requestResetCode();
|
await viewModel.requestResetCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ForgetPasswordViewModel viewModel) =>
|
Widget build(BuildContext context, ForgetPasswordViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
Widget _buildScaffoldWrapper( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required ForgetPasswordViewModel viewModel}) => Scaffold(
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldStack(
|
Widget _buildScaffoldStack( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required ForgetPasswordViewModel viewModel}) => Stack(
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
|
||||||
Stack(
|
|
||||||
children: [
|
children: [
|
||||||
_buildScaffold(context: context, viewModel: viewModel),
|
_buildScaffold(context: context,viewModel: viewModel),
|
||||||
_buildRequestResetCodeState(viewModel),
|
_buildRequestResetCodeState(viewModel),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
Widget _buildScaffold( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required ForgetPasswordViewModel viewModel}) => Column(
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children:
|
children: _buildScaffoldChildren(context: context, viewModel: viewModel),
|
||||||
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(
|
List<Widget> _buildScaffoldChildren( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
[
|
[_buildAppBar(viewModel), _buildExpandedBody(context: context, viewModel: viewModel)];
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildExpandedBody(context: context, viewModel: viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar(ForgetPasswordViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(ForgetPasswordViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
|
|
@ -93,44 +83,34 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
onPop: () => _inAppPop(viewModel),
|
onPop: () => _inAppPop(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
Expanded(
|
Expanded(child: _buildColumnScroller(context: context, viewModel: viewModel));
|
||||||
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildColumnScroller(
|
Widget _buildColumnScroller( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(
|
Widget _buildBodyWrapper( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required ForgetPasswordViewModel viewModel}) => Padding(
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(context: context, viewModel: viewModel),
|
child: _buildBody(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(
|
Widget _buildBody( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required ForgetPasswordViewModel viewModel}) => Column(
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(context: context, viewModel: viewModel),
|
children: _buildBodyChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(
|
List<Widget> _buildBodyChildren( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
[
|
[_buildUpperColumn(viewModel),getPadding(context), _buildContinueButtonWrapper(viewModel)];
|
||||||
_buildUpperColumn(viewModel),
|
|
||||||
getPadding(context),
|
|
||||||
_buildContinueButtonWrapper(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn(ForgetPasswordViewModel viewModel) => Column(
|
Widget _buildUpperColumn(ForgetPasswordViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
|
||||||
|
|
@ -31,10 +31,12 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _clearDataOnNavigation(ForgetPasswordViewModel viewModel) {
|
void _clearDataOnNavigation(ForgetPasswordViewModel viewModel) {
|
||||||
|
|
||||||
passwordController.clear();
|
passwordController.clear();
|
||||||
resetCodeController.clear();
|
resetCodeController.clear();
|
||||||
confirmPasswordController.clear();
|
confirmPasswordController.clear();
|
||||||
viewModel.resetResetPasswordScreen();
|
viewModel.resetResetPasswordScreen();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _reset(ForgetPasswordViewModel viewModel) async {
|
Future<void> _reset(ForgetPasswordViewModel viewModel) async {
|
||||||
|
|
@ -53,30 +55,26 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
Widget build(BuildContext context, ForgetPasswordViewModel viewModel) =>
|
Widget build(BuildContext context, ForgetPasswordViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
Widget _buildScaffoldWrapper( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required ForgetPasswordViewModel viewModel}) => Scaffold(
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldStack(
|
Widget _buildScaffoldStack( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required ForgetPasswordViewModel viewModel}) => Stack(
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
|
||||||
Stack(
|
|
||||||
children: [
|
children: [
|
||||||
_buildScaffold(viewModel),
|
_buildScaffold(viewModel),
|
||||||
_buildResetPasswordState(viewModel),
|
_buildResetPasswordState(viewModel),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(ForgetPasswordViewModel viewModel) => Column(
|
Widget _buildScaffold( ForgetPasswordViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(ForgetPasswordViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren( ForgetPasswordViewModel viewModel) =>
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildAppBar(ForgetPasswordViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(ForgetPasswordViewModel viewModel) => LargeAppBar(
|
||||||
|
|
@ -85,15 +83,15 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
onPop: () => _inAppPop(viewModel),
|
onPop: () => _inAppPop(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(ForgetPasswordViewModel viewModel) =>
|
Widget _buildExpandedBody( ForgetPasswordViewModel viewModel) =>
|
||||||
Expanded(child: _buildColumnScroller(viewModel));
|
Expanded(child: _buildColumnScroller(viewModel));
|
||||||
|
|
||||||
Widget _buildColumnScroller(ForgetPasswordViewModel viewModel) =>
|
Widget _buildColumnScroller( ForgetPasswordViewModel viewModel) =>
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(viewModel),
|
child: _buildBodyWrapper(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(ForgetPasswordViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper( ForgetPasswordViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
@ -104,6 +102,10 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
children: _buildBodyColumnChildren(viewModel),
|
children: _buildBodyColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildBodyColumnChildren(ForgetPasswordViewModel viewModel) => [
|
List<Widget> _buildBodyColumnChildren(ForgetPasswordViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/course/course_view.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn/learn_view.dart';
|
import 'package:yimaru_app/ui/views/learn/learn_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/profile/profile_view.dart';
|
import 'package:yimaru_app/ui/views/profile/profile_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/startup/startup_view.dart';
|
import 'package:yimaru_app/ui/views/startup/startup_view.dart';
|
||||||
|
|
@ -19,20 +16,17 @@ class HomeView extends StackedView<HomeViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(HomeViewModel viewModel) async {
|
void onViewModelReady(HomeViewModel viewModel) async {
|
||||||
await _init(viewModel);
|
await viewModel.getProfileStatus();
|
||||||
|
await viewModel.getProfileData();
|
||||||
super.onViewModelReady(viewModel);
|
super.onViewModelReady(viewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _init(HomeViewModel viewModel) async =>
|
|
||||||
await viewModel.initialize();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget builder(
|
Widget builder(
|
||||||
BuildContext context, HomeViewModel viewModel, Widget? child) =>
|
BuildContext context, HomeViewModel viewModel, Widget? child) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(HomeViewModel viewModel) =>
|
Widget _buildScaffoldWrapper(HomeViewModel viewModel) => viewModel.isBusy
|
||||||
viewModel.busy(StateObjects.homeView)
|
|
||||||
? const StartupView(label: 'Checking user info')
|
? const StartupView(label: 'Checking user info')
|
||||||
: _buildScaffold(viewModel);
|
: _buildScaffold(viewModel);
|
||||||
|
|
||||||
|
|
@ -77,7 +71,7 @@ Widget getViewForIndex(int index) {
|
||||||
case 0:
|
case 0:
|
||||||
return const LearnView();
|
return const LearnView();
|
||||||
case 1:
|
case 1:
|
||||||
return const CourseView();
|
return const ComingSoon();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return const ProfileView();
|
return const ProfileView();
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ class HomeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
int get currentIndex => _currentIndex;
|
int get currentIndex => _currentIndex;
|
||||||
|
|
||||||
// Bottom navigation
|
|
||||||
void setCurrentIndex(int index) {
|
void setCurrentIndex(int index) {
|
||||||
_currentIndex = index;
|
_currentIndex = index;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
|
|
@ -64,58 +63,25 @@ class HomeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
Future<void> replaceWithFailure() async =>
|
Future<void> replaceWithFailure() async =>
|
||||||
await _navigationService.clearStackAndShow(Routes.failureView,
|
await _navigationService.clearStackAndShowView(
|
||||||
arguments: 'Check your internet connection to proceed');
|
const FailureView(label: 'Check your internet connection to proceed'),
|
||||||
|
);
|
||||||
|
|
||||||
Future<void> replaceWithOnboarding() async =>
|
Future<void> replaceWithOnboarding() async =>
|
||||||
await _navigationService.replaceWithOnboardingView();
|
await _navigationService.replaceWithOnboardingView();
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
// Initialize user data
|
|
||||||
Future<void> initialize() async =>
|
|
||||||
await runBusyFuture(_initialize(), busyObject: StateObjects.homeView);
|
|
||||||
|
|
||||||
Future<void> _initialize() async {
|
|
||||||
await _getProfileStatus();
|
|
||||||
await _getProfileData();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Profile status
|
|
||||||
Future<void> _getProfileStatus() async {
|
|
||||||
Map<String, dynamic> response = {};
|
|
||||||
if (_user?.profileCompleted == null) {
|
|
||||||
if (await _statusChecker.checkConnection()) {
|
|
||||||
print('BREAK-POINT 1');
|
|
||||||
response = await _apiService.getProfileStatus(_user);
|
|
||||||
} else {
|
|
||||||
print('BREAK-POINT 2');
|
|
||||||
await replaceWithFailure();
|
|
||||||
}
|
|
||||||
} else if (!(_user?.profileCompleted ?? false)) {
|
|
||||||
print('BREAK-POINT 3');
|
|
||||||
response = {'data': false, 'status': ResponseStatus.success};
|
|
||||||
} else {
|
|
||||||
print('BREAK-POINT 4');
|
|
||||||
response = {'data': true, 'status': ResponseStatus.success};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response['status'] == ResponseStatus.success && !response['data']) {
|
|
||||||
print('BREAK-POINT 5');
|
|
||||||
await replaceWithOnboarding();
|
|
||||||
} else if (response['status'] == ResponseStatus.success &&
|
|
||||||
response['data']) {
|
|
||||||
print('BREAK-POINT 6');
|
|
||||||
await saveProfileStatus(response['data']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Profile data
|
// Profile data
|
||||||
|
Future<void> getProfileData() async => await runBusyFuture(_getProfileData());
|
||||||
|
|
||||||
Future<void> _getProfileData() async {
|
Future<void> _getProfileData() async {
|
||||||
|
print('RESPONSE FOR USER DATA ${_user?.firstName}');
|
||||||
|
|
||||||
if (!(_user?.userInfoLoaded ?? false)) {
|
if (!(_user?.userInfoLoaded ?? false)) {
|
||||||
|
print('RESPONSE FOR USER DATA 1');
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
Map<String, dynamic> response = {};
|
Map<String, dynamic> response = {};
|
||||||
print('BREAK-POINT: Profile-Completed ${_user?.profileCompleted}');
|
|
||||||
|
|
||||||
if (_user?.profileCompleted != null &&
|
if (_user?.profileCompleted != null &&
|
||||||
(_user?.profileCompleted ?? false)) {
|
(_user?.profileCompleted ?? false)) {
|
||||||
|
|
@ -123,17 +89,46 @@ class HomeViewModel extends ReactiveViewModel {
|
||||||
response = await _apiService.getProfileData(_user?.userId);
|
response = await _apiService.getProfileData(_user?.userId);
|
||||||
|
|
||||||
if (response['status'] == ResponseStatus.success) {
|
if (response['status'] == ResponseStatus.success) {
|
||||||
print('BREAK-POINT 8');
|
|
||||||
|
|
||||||
UserModel user = response['data'] as UserModel;
|
UserModel user = response['data'] as UserModel;
|
||||||
|
|
||||||
String image =
|
String image =
|
||||||
await _imageDownloaderService.downloader(user.profilePicture);
|
await _imageDownloaderService.downloader(user.profilePicture);
|
||||||
|
|
||||||
await _authenticationService.saveUserData(image: image, data: user);
|
await _authenticationService.saveUserData(
|
||||||
|
image: image, data: user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Profile status
|
||||||
|
Future<void> getProfileStatus() async =>
|
||||||
|
await runBusyFuture(_getProfileStatus());
|
||||||
|
|
||||||
|
Future<void> _getProfileStatus() async {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
Map<String, dynamic> response = {};
|
||||||
|
|
||||||
|
if (_user?.profileCompleted == null) {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
response = await _apiService.getProfileStatus(_user);
|
||||||
|
} else {
|
||||||
|
await replaceWithFailure();
|
||||||
|
}
|
||||||
|
} else if (!(_user?.profileCompleted ?? false)) {
|
||||||
|
response = {'data': false, 'status': ResponseStatus.success};
|
||||||
|
} else {
|
||||||
|
response = {'data': true, 'status': ResponseStatus.success};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response['status'] == ResponseStatus.success && !response['data']) {
|
||||||
|
await replaceWithOnboarding();
|
||||||
|
} else if (response['status'] == ResponseStatus.success &&
|
||||||
|
response['data']) {
|
||||||
|
await saveProfileStatus(response['data']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,6 @@ class LanguageView extends StackedView<LanguageViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(LanguageViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(LanguageViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
title: 'Language Preference',
|
title: 'Language Preference',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,7 @@ class LearnViewModel extends ReactiveViewModel {
|
||||||
[_authenticationService];
|
[_authenticationService];
|
||||||
|
|
||||||
// Current user
|
// Current user
|
||||||
UserModel? get _user => _authenticationService.user;
|
UserModel? get user => _authenticationService.user;
|
||||||
|
|
||||||
UserModel? get user => _user;
|
|
||||||
|
|
||||||
final List<Map<String, dynamic>> _learnLevels = [
|
final List<Map<String, dynamic>> _learnLevels = [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
|
|
||||||
Widget _buildAppBar(LearnLessonViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnLessonViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
showBackButton: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLevelsColumnWrapper(LearnLessonViewModel viewModel) =>
|
Widget _buildLevelsColumnWrapper(LearnLessonViewModel viewModel) =>
|
||||||
|
|
@ -110,7 +109,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
|
|
||||||
Widget _buildHeader() => Text(
|
Widget _buildHeader() => Text(
|
||||||
'Module 1: Greetings & Introductions',
|
'Module 1: Greetings & Introductions',
|
||||||
style: style18DG700,
|
style: style18DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildListView(LearnLessonViewModel viewModel) => ListView.builder(
|
Widget _buildListView(LearnLessonViewModel viewModel) => ListView.builder(
|
||||||
|
|
@ -123,7 +122,6 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
thumbnail: viewModel.lessons[index]['thumbnail'],
|
thumbnail: viewModel.lessons[index]['thumbnail'],
|
||||||
onLessonTap: () async =>
|
onLessonTap: () async =>
|
||||||
await viewModel.navigateToLearnLessonDetail(),
|
await viewModel.navigateToLearnLessonDetail(),
|
||||||
onPracticeTap: () async => await viewModel.navigateToLearnPractice(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -132,13 +130,11 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
required String thumbnail,
|
required String thumbnail,
|
||||||
GestureTapCallback? onLessonTap,
|
GestureTapCallback? onLessonTap,
|
||||||
required ProgressStatuses status,
|
required ProgressStatuses status,
|
||||||
GestureTapCallback? onPracticeTap,
|
|
||||||
}) =>
|
}) =>
|
||||||
LearnLessonTile(
|
LearnLessonTile(
|
||||||
title: title,
|
title: title,
|
||||||
status: status,
|
status: status,
|
||||||
thumbnail: thumbnail,
|
thumbnail: thumbnail,
|
||||||
onLessonTap: onLessonTap,
|
onLessonTap: onLessonTap,
|
||||||
onPracticeTap: onPracticeTap,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,4 @@ class LearnLessonViewModel extends BaseViewModel {
|
||||||
|
|
||||||
Future<void> navigateToLearnLessonDetail() async =>
|
Future<void> navigateToLearnLessonDetail() async =>
|
||||||
await _navigationService.navigateToLearnLessonDetailView();
|
await _navigationService.navigateToLearnLessonDetailView();
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice() async =>
|
|
||||||
await _navigationService.navigateToLearnPracticeView(
|
|
||||||
buttonLabel: 'Start Practice',
|
|
||||||
title: 'Let \'s practice what you just learnt!',
|
|
||||||
subtitle:
|
|
||||||
'I’ll ask you a few questions, and you can respond naturally.',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,13 @@ import 'learn_lesson_detail_viewmodel.dart';
|
||||||
class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
const LearnLessonDetailView({Key? key}) : super(key: key);
|
const LearnLessonDetailView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
Future<void> _navigate(LearnLessonDetailViewModel viewModel) async {
|
|
||||||
|
Future<void> _navigate(LearnLessonDetailViewModel viewModel)async{
|
||||||
await viewModel.pause();
|
await viewModel.pause();
|
||||||
await viewModel.navigateToLearnPractice();
|
await viewModel.navigateToLearnPractice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// @override
|
// @override
|
||||||
// void onDispose(LearnLessonDetailViewModel viewModel) {
|
// void onDispose(LearnLessonDetailViewModel viewModel) {
|
||||||
// print('DISPOSED');
|
// print('DISPOSED');
|
||||||
|
|
@ -68,7 +70,6 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
|
|
||||||
Widget _buildAppBar(LearnLessonDetailViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnLessonDetailViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
showBackButton: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyColumnWrapper(LearnLessonDetailViewModel viewModel) =>
|
Widget _buildBodyColumnWrapper(LearnLessonDetailViewModel viewModel) =>
|
||||||
|
|
@ -172,6 +173,6 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await _navigate(viewModel),
|
onTap: ()async => await _navigate(viewModel),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class LearnLessonDetailViewModel extends BaseViewModel {
|
||||||
// rebuildUi();
|
// rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pause() async {
|
Future<void> pause()async{
|
||||||
await _chewieController?.pause();
|
await _chewieController?.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,11 +67,6 @@ class LearnLessonDetailViewModel extends BaseViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice() async =>
|
Future<void> navigateToLearnPractice() async=>await _navigationService.navigateToLearnPracticeView();
|
||||||
await _navigationService.navigateToLearnPracticeView(
|
|
||||||
buttonLabel: 'Start Practice',
|
|
||||||
title: 'Let \'s practice what you just learnt!',
|
|
||||||
subtitle:
|
|
||||||
'I’ll ask you a few questions, and you can respond naturally.',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ class LearnLevelView extends StackedView<LearnLevelViewModel> {
|
||||||
|
|
||||||
Widget _buildAppBar(LearnLevelViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnLevelViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
showBackButton: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLevelsColumnWrapper(LearnLevelViewModel viewModel) =>
|
Widget _buildLevelsColumnWrapper(LearnLevelViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -22,16 +22,8 @@ class LearnLevelViewModel extends BaseViewModel {
|
||||||
|
|
||||||
List<Map<String, dynamic>> get learnSubLevels => _learnSubLevels;
|
List<Map<String, dynamic>> get learnSubLevels => _learnSubLevels;
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
|
||||||
|
|
||||||
Future<void> navigateToLearnModule() async =>
|
Future<void> navigateToLearnModule() async =>
|
||||||
_navigationService.navigateToLearnModuleView();
|
_navigationService.navigateToLearnModuleView();
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice() async =>
|
void pop() => _navigationService.back();
|
||||||
await _navigationService.navigateToLearnPracticeView(
|
|
||||||
title: 'Let’s Practice Level 1',
|
|
||||||
buttonLabel: 'Begin Level Practice',
|
|
||||||
subtitle: 'Let’s quickly review what you’ve learned in this level! ',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
|
|
||||||
Widget _buildAppBar(LearnModuleViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnModuleViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
showBackButton: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLevelsColumnWrapper(LearnModuleViewModel viewModel) =>
|
Widget _buildLevelsColumnWrapper(LearnModuleViewModel viewModel) =>
|
||||||
|
|
@ -67,7 +66,7 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
List<Widget> _buildLevelsColumnChildren(LearnModuleViewModel viewModel) => [
|
List<Widget> _buildLevelsColumnChildren(LearnModuleViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
_buildSubtitle(),
|
_buildSubTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildOverallProgress(),
|
_buildOverallProgress(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
|
@ -79,7 +78,7 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
style: style18P600,
|
style: style18P600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubTitle() => Text(
|
||||||
'Your Current Level',
|
'Your Current Level',
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,15 @@ import '../../common/enmus.dart';
|
||||||
class LearnModuleViewModel extends BaseViewModel {
|
class LearnModuleViewModel extends BaseViewModel {
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
// Modules
|
|
||||||
final List<Map<String, dynamic>> _modules = [
|
final List<Map<String, dynamic>> _modules = [
|
||||||
{
|
{
|
||||||
'status': ProgressStatuses.completed,
|
'status': ProgressStatuses.started,
|
||||||
'title': 'Module 1: Greetings & Introductions',
|
'title': 'Module 1: Greetings & Introductions',
|
||||||
'subtitle':
|
'subtitle':
|
||||||
'Learn how to introduce yourself, talk about your surroundings, and start simple conversations.',
|
'Learn how to introduce yourself, talk about your surroundings, and start simple conversations.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'status': ProgressStatuses.started,
|
'status': ProgressStatuses.pending,
|
||||||
'title': 'Module 2: Everyday Basics',
|
'title': 'Module 2: Everyday Basics',
|
||||||
'subtitle': 'Learn numbers, colors, and common objects.',
|
'subtitle': 'Learn numbers, colors, and common objects.',
|
||||||
},
|
},
|
||||||
|
|
@ -36,16 +35,8 @@ class LearnModuleViewModel extends BaseViewModel {
|
||||||
|
|
||||||
List<Map<String, dynamic>> get modules => _modules;
|
List<Map<String, dynamic>> get modules => _modules;
|
||||||
|
|
||||||
// Navigation
|
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToLearnLesson() async =>
|
Future<void> navigateToLearnLesson() async =>
|
||||||
await _navigationService.navigateToLearnLessonView();
|
await _navigationService.navigateToLearnLessonView();
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice() async =>
|
|
||||||
await _navigationService.navigateToLearnPracticeView(
|
|
||||||
title: 'Let’s Practice Module 1',
|
|
||||||
buttonLabel: 'Begin Module Practice',
|
|
||||||
subtitle: 'Let’s quickly review what you’ve learned in this module! ',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
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/views/learn_practice/screens/finish_learn_practice_screen.dart';
|
import 'package:yimaru_app/ui/views/learn_practice/screens/listen_speaker_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practice_completion_screen.dart';
|
import 'package:yimaru_app/ui/views/learn_practice/screens/practice_intro_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practice_result_screen.dart';
|
import 'package:yimaru_app/ui/views/learn_practice/screens/start_practice_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/screens/listen_learn_practice_speaker_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/screens/learn_practice_intro_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/screens/speak_to_learn_practice_listener_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/screens/start_learn_practice_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/profile_image.dart';
|
import 'package:yimaru_app/ui/widgets/profile_image.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/speaking_partner_image.dart';
|
import 'package:yimaru_app/ui/widgets/speaking_partner_image.dart';
|
||||||
|
|
||||||
|
|
@ -17,16 +13,7 @@ import '../../widgets/small_app_bar.dart';
|
||||||
import 'learn_practice_viewmodel.dart';
|
import 'learn_practice_viewmodel.dart';
|
||||||
|
|
||||||
class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
||||||
final String title;
|
const LearnPracticeView({Key? key}) : super(key: key);
|
||||||
final String subtitle;
|
|
||||||
final String buttonLabel;
|
|
||||||
|
|
||||||
const LearnPracticeView(
|
|
||||||
{Key? key,
|
|
||||||
required this.title,
|
|
||||||
required this.subtitle,
|
|
||||||
required this.buttonLabel})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
LearnPracticeViewModel viewModelBuilder(BuildContext context) =>
|
LearnPracticeViewModel viewModelBuilder(BuildContext context) =>
|
||||||
|
|
@ -40,13 +27,13 @@ class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
||||||
) =>
|
) =>
|
||||||
_buildPracticeScreensWrapper(viewModel);
|
_buildPracticeScreensWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildPracticeScreensWrapper(LearnPracticeViewModel viewModel) =>
|
|
||||||
PopScope(
|
|
||||||
|
Widget _buildPracticeScreensWrapper(LearnPracticeViewModel viewModel) => PopScope(
|
||||||
canPop: true,
|
canPop: true,
|
||||||
onPopInvokedWithResult: (value, data) {
|
onPopInvokedWithResult: (value, data) {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
WidgetsBinding.instance
|
WidgetsBinding.instance.addPostFrameCallback((_) => viewModel.goBack());
|
||||||
.addPostFrameCallback((_) => viewModel.goBack());
|
|
||||||
},
|
},
|
||||||
child: _buildScaffoldWrapper(viewModel));
|
child: _buildScaffoldWrapper(viewModel));
|
||||||
|
|
||||||
|
|
@ -55,44 +42,31 @@ class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
||||||
body: _buildScaffoldStack(viewModel),
|
body: _buildScaffoldStack(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldStack(LearnPracticeViewModel viewModel) =>
|
Widget _buildScaffoldStack(LearnPracticeViewModel viewModel) => Stack(children: [
|
||||||
Stack(children: [
|
|
||||||
_buildBody(viewModel),
|
_buildBody(viewModel),
|
||||||
//_buildLoginWithEmailState(viewModel),
|
//_buildLoginWithEmailState(viewModel),
|
||||||
//_buildLoginWithGoogleState(viewModel)
|
//_buildLoginWithGoogleState(viewModel)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildBody(LearnPracticeViewModel viewModel) =>
|
Widget _buildBody(LearnPracticeViewModel viewModel) =>
|
||||||
IndexedStack(index: viewModel.currentIndex, children: _buildScreens());
|
IndexedStack(
|
||||||
|
|
||||||
|
index: viewModel.currentIndex, children: _buildScreens());
|
||||||
|
|
||||||
List<Widget> _buildScreens() => [
|
List<Widget> _buildScreens() => [
|
||||||
_buildLearnPracticeIntroScreen(),
|
_buildPracticeIntroScreen(),
|
||||||
_buildStartLearnPracticeScreen(),
|
_buildStartPracticeScreen(),
|
||||||
_buildListenLearnPracticeSpeakerScreen(),
|
_buildListenSpeakerScreen()
|
||||||
_buildSpeakToLearnPracticeListenerScreen(),
|
|
||||||
_buildFinishLearnPracticeScreen(),
|
|
||||||
_buildLearnPracticeResultScreen(),
|
|
||||||
_buildLearnPracticeCompletionScreen()
|
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildLearnPracticeIntroScreen() => LearnPracticeIntroScreen(
|
Widget _buildPracticeIntroScreen() => const PracticeIntroScreen();
|
||||||
title: title,
|
|
||||||
subtitle: subtitle,
|
|
||||||
buttonLabel: buttonLabel,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildStartLearnPracticeScreen() => const StartLearnPracticeScreen();
|
Widget _buildStartPracticeScreen() => const StartPracticeScreen();
|
||||||
|
|
||||||
Widget _buildListenLearnPracticeSpeakerScreen() =>
|
Widget _buildListenSpeakerScreen() => const ListenSpeakerScreen();
|
||||||
const ListenLearnPracticeSpeakerScreen();
|
|
||||||
|
|
||||||
Widget _buildSpeakToLearnPracticeListenerScreen() =>
|
|
||||||
const SpeakToLearnPracticeListenerScreen();
|
|
||||||
|
|
||||||
Widget _buildFinishLearnPracticeScreen() => const FinishLearnPracticeScreen();
|
|
||||||
|
|
||||||
Widget _buildLearnPracticeResultScreen() => const LearnPracticeResultScreen();
|
|
||||||
|
|
||||||
Widget _buildLearnPracticeCompletionScreen() =>
|
|
||||||
const LearnPracticeCompletionScreen();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,30 +11,24 @@ class LearnPracticeViewModel extends BaseViewModel {
|
||||||
|
|
||||||
int get currentIndex => _currentIndex;
|
int get currentIndex => _currentIndex;
|
||||||
|
|
||||||
// Practice results
|
|
||||||
final List<Map<String, dynamic>> _practiceResults = [
|
|
||||||
{'question': 'What is your name?'},
|
|
||||||
{'question': 'Where are you from?'},
|
|
||||||
{'question': 'Where are you from?'}
|
|
||||||
];
|
|
||||||
|
|
||||||
List<Map<String, dynamic>> get practiceResults => _practiceResults;
|
|
||||||
|
|
||||||
// In-app navigation
|
// In-app navigation
|
||||||
void goTo(int page) {
|
void goTo(int page) {
|
||||||
|
|
||||||
_currentIndex = page;
|
_currentIndex = page;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void goBack() {
|
void goBack() {
|
||||||
if (_currentIndex == 0) {
|
if(_currentIndex == 0){
|
||||||
pop();
|
pop();
|
||||||
} else {
|
}else{
|
||||||
_currentIndex--;
|
_currentIndex--;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/cancel_learn_practice_sheet.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
|
|
||||||
|
|
||||||
import '../../../common/app_colors.dart';
|
|
||||||
import '../../../common/ui_helpers.dart';
|
|
||||||
import '../../../widgets/custom_column_button.dart';
|
|
||||||
import '../../../widgets/custom_elevated_button.dart';
|
|
||||||
import '../../../widgets/small_app_bar.dart';
|
|
||||||
|
|
||||||
class FinishLearnPracticeScreen
|
|
||||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
|
||||||
const FinishLearnPracticeScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(LearnPracticeViewModel viewModel) =>
|
|
||||||
SafeArea(child: _buildBodyColumnWrapper(viewModel));
|
|
||||||
|
|
||||||
Widget _buildBodyColumnWrapper(LearnPracticeViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildBodyColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBodyColumn(viewModel) => Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildBodyColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildBodyColumnChildren(LearnPracticeViewModel viewModel) => [
|
|
||||||
_buildAppBarWrapper(viewModel),
|
|
||||||
_buildSpeakingIndicatorWrapper(viewModel),
|
|
||||||
_buildLowerButtonsSectionWrapper(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBarWrapper(LearnPracticeViewModel viewModel) => Column(
|
|
||||||
children: [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
|
||||||
showBackButton: false,
|
|
||||||
onTap: viewModel.goBack,
|
|
||||||
title: 'Practice Speaking',
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: _buildSpeakingIndicatorChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildSpeakingIndicatorChildren() => [
|
|
||||||
_buildIcon(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildTitle(),
|
|
||||||
_buildSubtitle(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset('assets/icons/success.svg');
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
'Practice Completed!',
|
|
||||||
style: style25DG600,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
'You sound more confident this time - great improvement!',
|
|
||||||
style: style14DG400,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerButtonsSectionWrapper(LearnPracticeViewModel viewModel) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
|
||||||
child: _buildLowerButtonsSection(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerButtonsSection(LearnPracticeViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: _buildLowerButtonsSectionChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerButtonsSectionChildren(
|
|
||||||
LearnPracticeViewModel viewModel) =>
|
|
||||||
[
|
|
||||||
_buildContinueButton(viewModel),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildPracticeAgainButton(viewModel),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildContinueButton(LearnPracticeViewModel viewModel) =>
|
|
||||||
CustomElevatedButton(
|
|
||||||
height: 55,
|
|
||||||
borderRadius: 12,
|
|
||||||
foregroundColor: kcWhite,
|
|
||||||
text: 'Continue Practice',
|
|
||||||
onTap: () => viewModel.goTo(5),
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildPracticeAgainButton(LearnPracticeViewModel viewModel) =>
|
|
||||||
CustomElevatedButton(
|
|
||||||
height: 55,
|
|
||||||
borderRadius: 12,
|
|
||||||
text: 'Practice Again',
|
|
||||||
backgroundColor: kcWhite,
|
|
||||||
borderColor: kcPrimaryColor,
|
|
||||||
onTap: () => viewModel.goTo(1),
|
|
||||||
foregroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/small_app_bar.dart';
|
|
||||||
|
|
||||||
import '../../../common/app_colors.dart';
|
|
||||||
import '../../../common/ui_helpers.dart';
|
|
||||||
import '../../../widgets/custom_elevated_button.dart';
|
|
||||||
|
|
||||||
class LearnPracticeCompletionScreen
|
|
||||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
|
||||||
const LearnPracticeCompletionScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildBodyWrapper(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBodyWrapper(LearnPracticeViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildBody(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBody(LearnPracticeViewModel viewModel) => Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: _buildBodyChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(LearnPracticeViewModel viewModel) =>
|
|
||||||
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn(LearnPracticeViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(LearnPracticeViewModel viewModel) => [
|
|
||||||
verticalSpaceMassive,
|
|
||||||
_buildIcon(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildSubtitle(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
|
||||||
'assets/icons/complete.svg',
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
'Yay, you’ve completed A1 ',
|
|
||||||
style: style25DG600,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
'We’re now analyzing your speaking skills',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: style14MG400,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(LearnPracticeViewModel viewModel) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
|
||||||
child: _buildContinueButton(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildContinueButton(LearnPracticeViewModel viewModel) =>
|
|
||||||
CustomElevatedButton(
|
|
||||||
height: 55,
|
|
||||||
borderRadius: 12,
|
|
||||||
text: 'Continue',
|
|
||||||
foregroundColor: kcWhite,
|
|
||||||
onTap: () => viewModel.pop(),
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
|
||||||
import 'package:flutter_svg/svg.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/cancel_learn_practice_sheet.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/learn_practice_tip_section.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/practice_results_wrapper.dart';
|
|
||||||
|
|
||||||
import '../../../common/app_colors.dart';
|
|
||||||
import '../../../common/ui_helpers.dart';
|
|
||||||
import '../../../widgets/custom_column_button.dart';
|
|
||||||
import '../../../widgets/custom_elevated_button.dart';
|
|
||||||
import '../../../widgets/small_app_bar.dart';
|
|
||||||
|
|
||||||
class LearnPracticeResultScreen
|
|
||||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
|
||||||
const LearnPracticeResultScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(LearnPracticeViewModel viewModel) =>
|
|
||||||
SafeArea(child: _buildBodyColumnWrapper(viewModel));
|
|
||||||
|
|
||||||
Widget _buildBodyColumnWrapper(LearnPracticeViewModel viewModel) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildBodyColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBodyColumn(viewModel) => Column(
|
|
||||||
children: _buildBodyColumnChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildBodyColumnChildren(LearnPracticeViewModel viewModel) => [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildBodyWrapper(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
|
||||||
title: 'Result',
|
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.goBack,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBodyWrapper(LearnPracticeViewModel viewMode) => Expanded(
|
|
||||||
child: _buildBodyScroller(viewMode),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBodyScroller(LearnPracticeViewModel viewModel) =>
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: _buildBody(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBody(LearnPracticeViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: _buildBodyChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(LearnPracticeViewModel viewModel) => [
|
|
||||||
_buildResultsSection(viewModel),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildLearnPracticeTipSection(),
|
|
||||||
verticalSpaceLarge,
|
|
||||||
_buildLowerButtonsSection(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildResultsSection(LearnPracticeViewModel viewModel) =>
|
|
||||||
PracticeResultsWrapper(data: viewModel.practiceResults);
|
|
||||||
|
|
||||||
Widget _buildLearnPracticeTipSection() => const LearnPracticeTipSection();
|
|
||||||
|
|
||||||
Widget _buildLowerButtonsSection(LearnPracticeViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: _buildLowerButtonsSectionChildren(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerButtonsSectionChildren(
|
|
||||||
LearnPracticeViewModel viewModel) =>
|
|
||||||
[
|
|
||||||
_buildContinueButton(viewModel),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildPracticeAgainButton(viewModel),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildContinueButton(LearnPracticeViewModel viewModel) =>
|
|
||||||
CustomElevatedButton(
|
|
||||||
height: 55,
|
|
||||||
text: 'Continue',
|
|
||||||
borderRadius: 12,
|
|
||||||
foregroundColor: kcWhite,
|
|
||||||
onTap: () => viewModel.goTo(6),
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildPracticeAgainButton(LearnPracticeViewModel viewModel) =>
|
|
||||||
CustomElevatedButton(
|
|
||||||
height: 55,
|
|
||||||
text: 'Retry',
|
|
||||||
borderRadius: 12,
|
|
||||||
backgroundColor: kcWhite,
|
|
||||||
borderColor: kcPrimaryColor,
|
|
||||||
onTap: () => viewModel.goTo(1),
|
|
||||||
foregroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -10,9 +10,8 @@ import '../../../common/ui_helpers.dart';
|
||||||
import '../../../widgets/custom_column_button.dart';
|
import '../../../widgets/custom_column_button.dart';
|
||||||
import '../../../widgets/small_app_bar.dart';
|
import '../../../widgets/small_app_bar.dart';
|
||||||
|
|
||||||
class ListenLearnPracticeSpeakerScreen
|
class ListenSpeakerScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
const ListenSpeakerScreen({super.key});
|
||||||
const ListenLearnPracticeSpeakerScreen({super.key});
|
|
||||||
|
|
||||||
Future<void> _showSheet(
|
Future<void> _showSheet(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
|
|
@ -87,7 +86,6 @@ class ListenLearnPracticeSpeakerScreen
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.goBack,
|
onTap: viewModel.goBack,
|
||||||
title: 'Practice Speaking',
|
title: 'Practice Speaking',
|
||||||
);
|
);
|
||||||
|
|
@ -192,7 +190,7 @@ class ListenLearnPracticeSpeakerScreen
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
[
|
[
|
||||||
_buildReplyButtonWrapper(),
|
_buildReplyButtonWrapper(),
|
||||||
_buildMicButtonWrapper(viewModel),
|
_buildMicButtonWrapper(),
|
||||||
_buildCancelButtonWrapper(context: context, viewModel: viewModel)
|
_buildCancelButtonWrapper(context: context, viewModel: viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -201,11 +199,10 @@ class ListenLearnPracticeSpeakerScreen
|
||||||
Widget _buildReplyButton() => const CustomColumnButton(
|
Widget _buildReplyButton() => const CustomColumnButton(
|
||||||
icon: Icons.replay, label: 'Reply', color: kcPrimaryColor);
|
icon: Icons.replay, label: 'Reply', color: kcPrimaryColor);
|
||||||
|
|
||||||
Widget _buildMicButtonWrapper(LearnPracticeViewModel viewModel) =>
|
Widget _buildMicButtonWrapper() => Expanded(child: _buildMicButton());
|
||||||
Expanded(child: _buildMicButton(viewModel));
|
|
||||||
|
|
||||||
Widget _buildMicButton(LearnPracticeViewModel viewModel) => ElevatedButton(
|
Widget _buildMicButton() => ElevatedButton(
|
||||||
onPressed: () => viewModel.goTo(3),
|
onPressed: () {},
|
||||||
style: const ButtonStyle(
|
style: const ButtonStyle(
|
||||||
shape: WidgetStatePropertyAll(CircleBorder()),
|
shape: WidgetStatePropertyAll(CircleBorder()),
|
||||||
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
||||||
|
|
@ -9,20 +9,13 @@ import '../../../widgets/custom_elevated_button.dart';
|
||||||
import '../../../widgets/small_app_bar.dart';
|
import '../../../widgets/small_app_bar.dart';
|
||||||
import '../../../widgets/speaking_partner_image.dart';
|
import '../../../widgets/speaking_partner_image.dart';
|
||||||
|
|
||||||
class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
class PracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
final String title;
|
const PracticeIntroScreen({super.key});
|
||||||
final String subtitle;
|
|
||||||
final String buttonLabel;
|
|
||||||
|
|
||||||
const LearnPracticeIntroScreen(
|
|
||||||
{super.key,
|
|
||||||
required this.title,
|
|
||||||
required this.subtitle,
|
|
||||||
required this.buttonLabel});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
Widget build(BuildContext context,LearnPracticeViewModel viewModel) => _buildScaffoldWrapper(viewModel);
|
||||||
_buildScaffoldWrapper(viewModel);
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
|
|
@ -46,7 +39,6 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.goBack,
|
onTap: viewModel.goBack,
|
||||||
title: 'Practice Speaking',
|
title: 'Practice Speaking',
|
||||||
);
|
);
|
||||||
|
|
@ -91,9 +83,7 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
_buildSubtitle()
|
_buildSubtitle()
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildImage() => const SpeakingPartnerImage(
|
Widget _buildImage() => const SpeakingPartnerImage(radius: 75,);
|
||||||
radius: 75,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildPartnerName() => Text.rich(
|
Widget _buildPartnerName() => Text.rich(
|
||||||
TextSpan(text: 'Daniel', style: style14DG600, children: [
|
TextSpan(text: 'Daniel', style: style14DG600, children: [
|
||||||
|
|
@ -105,13 +95,13 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
title,
|
'Let \'s practice what you just learnt!',
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
subtitle,
|
'I’ll ask you a few questions, and you can respond naturally.',
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -126,9 +116,9 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
text: buttonLabel,
|
text: 'Start Practice',
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: () => viewModel.goTo(1),
|
onTap: ()=> viewModel.goTo(1),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,232 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_spinkit/flutter_spinkit.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/cancel_learn_practice_sheet.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
|
|
||||||
|
|
||||||
import '../../../common/app_colors.dart';
|
|
||||||
import '../../../common/ui_helpers.dart';
|
|
||||||
import '../../../widgets/custom_column_button.dart';
|
|
||||||
import '../../../widgets/small_app_bar.dart';
|
|
||||||
|
|
||||||
class SpeakToLearnPracticeListenerScreen
|
|
||||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
|
||||||
const SpeakToLearnPracticeListenerScreen({super.key});
|
|
||||||
|
|
||||||
Future<void> _showSheet(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) async =>
|
|
||||||
await showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
isScrollControlled: true,
|
|
||||||
backgroundColor: kcTransparent,
|
|
||||||
builder: (_) => _buildSheet(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(context: context, viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
SafeArea(
|
|
||||||
child:
|
|
||||||
_buildBodyColumnWrapper(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildBodyColumnWrapper(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildBodyStack(context: context, viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBodyStack(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Stack(
|
|
||||||
children: [
|
|
||||||
_buildBodyColumn(context: context, viewModel: viewModel),
|
|
||||||
_buildProgressIndicatorWrapper()
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBodyColumn(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children:
|
|
||||||
_buildBodyColumnChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildBodyColumnChildren(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
[
|
|
||||||
_buildAppBarWrapper(viewModel),
|
|
||||||
_buildSpeakingIndicatorWrapper(viewModel),
|
|
||||||
_buildLowerButtonsSectionWrapper(context: context, viewModel: viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBarWrapper(LearnPracticeViewModel viewModel) => Column(
|
|
||||||
children: [
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
|
||||||
onTap: viewModel.goBack,
|
|
||||||
showBackButton: true,
|
|
||||||
title: 'Practice Speaking',
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
children: _buildSpeakingIndicatorChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildSpeakingIndicatorChildren() =>
|
|
||||||
[_buildSpeakerLabel(), verticalSpaceMedium, _buildSpeakingIndicator()];
|
|
||||||
|
|
||||||
Widget _buildSpeakerLabel() => Text(
|
|
||||||
'You are speaking...',
|
|
||||||
style: style14P400,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSpeakingIndicator() => Container(
|
|
||||||
height: 100,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: _buildSpinner(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSpinner() => const SpinKitWave(
|
|
||||||
size: 75,
|
|
||||||
color: kcPrimaryColor,
|
|
||||||
type: SpinKitWaveType.center,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerButtonsSectionWrapper(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
|
||||||
child:
|
|
||||||
_buildLowerButtonsSection(context: context, viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLowerButtonsSection(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: _buildLowerButtonsSectionChildren(
|
|
||||||
context: context, viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildLowerButtonsSectionChildren(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
[
|
|
||||||
_buildActionLabel(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildButtonsRowWrapper(context: context, viewModel: viewModel),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildActionLabel() => Text(
|
|
||||||
'Tap the microphone to speak',
|
|
||||||
style: style14DG400,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildButtonsRowWrapper(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children:
|
|
||||||
_buildButtonsRowChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildButtonsRowChildren(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
[
|
|
||||||
_buildEmptySpace(),
|
|
||||||
_buildCheckButtonWrapper(viewModel),
|
|
||||||
_buildCancelButtonWrapper(context: context, viewModel: viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildEmptySpace() => Expanded(child: Container());
|
|
||||||
|
|
||||||
Widget _buildCheckButtonWrapper(LearnPracticeViewModel viewModel) =>
|
|
||||||
Expanded(child: _buildCheckButton(viewModel));
|
|
||||||
|
|
||||||
Widget _buildCheckButton(LearnPracticeViewModel viewModel) => ElevatedButton(
|
|
||||||
onPressed: () => viewModel.goTo(4),
|
|
||||||
style: const ButtonStyle(
|
|
||||||
shape: WidgetStatePropertyAll(CircleBorder()),
|
|
||||||
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
|
||||||
shadowColor: WidgetStatePropertyAll(kcPrimaryColor),
|
|
||||||
backgroundColor: WidgetStatePropertyAll(kcPrimaryColor),
|
|
||||||
),
|
|
||||||
child: _buildCheckIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildCheckIcon() => const Icon(
|
|
||||||
Icons.check,
|
|
||||||
size: 35,
|
|
||||||
color: kcWhite,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildCancelButtonWrapper(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
Expanded(
|
|
||||||
child: _buildCancelButton(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildCancelButton(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
|
||||||
CustomColumnButton(
|
|
||||||
color: kcRed,
|
|
||||||
label: 'Cancel',
|
|
||||||
icon: Icons.close,
|
|
||||||
onTap: () async =>
|
|
||||||
await _showSheet(context: context, viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
|
||||||
CancelLearnPracticeSheet(
|
|
||||||
onTap: viewModel.pop,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildProgressIndicatorWrapper() => Positioned(
|
|
||||||
top: 75,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
child: _buildProgressIndicator(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildProgressIndicator() => const CustomLinearProgressIndicator(
|
|
||||||
progress: 0.7,
|
|
||||||
activeColor: kcPrimaryColor,
|
|
||||||
backgroundColor: kcVeryLightGrey);
|
|
||||||
}
|
|
||||||
|
|
@ -7,8 +7,8 @@ import '../../../common/app_colors.dart';
|
||||||
import '../../../common/ui_helpers.dart';
|
import '../../../common/ui_helpers.dart';
|
||||||
import '../../../widgets/small_app_bar.dart';
|
import '../../../widgets/small_app_bar.dart';
|
||||||
|
|
||||||
class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
class StartPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
const StartLearnPracticeScreen({super.key});
|
const StartPracticeScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||||
|
|
@ -47,7 +47,6 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
|
|
||||||
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
Widget _buildAppBar(LearnPracticeViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.goBack,
|
onTap: viewModel.goBack,
|
||||||
showBackButton: true,
|
|
||||||
title: 'Practice Speaking',
|
title: 'Practice Speaking',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -123,7 +122,7 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
[
|
[
|
||||||
_buildActionLabel(),
|
_buildActionLabel(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildButtonsRowWrapper(viewModel),
|
_buildButtonsRowWrapper(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -133,15 +132,15 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonsRowWrapper(LearnPracticeViewModel viewModel) => Row(
|
Widget _buildButtonsRowWrapper() => Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildButtonsRowChildren(viewModel),
|
children: _buildButtonsRowChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildButtonsRowChildren(LearnPracticeViewModel viewModel) => [
|
List<Widget> _buildButtonsRowChildren() => [
|
||||||
_buildReplyButtonWrapper(),
|
_buildReplyButtonWrapper(),
|
||||||
_buildMicButtonWrapper(viewModel),
|
_buildMicButtonWrapper(),
|
||||||
_buildEmptySpace()
|
_buildEmptySpace()
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -150,11 +149,10 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
Widget _buildReplyButton() => const CustomColumnButton(
|
Widget _buildReplyButton() => const CustomColumnButton(
|
||||||
icon: Icons.replay, label: 'Reply', color: kcPrimaryColor);
|
icon: Icons.replay, label: 'Reply', color: kcPrimaryColor);
|
||||||
|
|
||||||
Widget _buildMicButtonWrapper(LearnPracticeViewModel viewModel) =>
|
Widget _buildMicButtonWrapper() => Expanded(child: _buildMicButton());
|
||||||
Expanded(child: _buildMicButton(viewModel));
|
|
||||||
|
|
||||||
Widget _buildMicButton(LearnPracticeViewModel viewModel) => ElevatedButton(
|
Widget _buildMicButton() => ElevatedButton(
|
||||||
onPressed: () => viewModel.goTo(2),
|
onPressed: () {},
|
||||||
style: const ButtonStyle(
|
style: const ButtonStyle(
|
||||||
shape: WidgetStatePropertyAll(CircleBorder()),
|
shape: WidgetStatePropertyAll(CircleBorder()),
|
||||||
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
||||||
|
|
@ -56,6 +56,10 @@ class LoginView extends StackedView<LoginViewModel> with $LoginView {
|
||||||
},
|
},
|
||||||
child: _buildBody(viewModel));
|
child: _buildBody(viewModel));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildBody(LoginViewModel viewModel) =>
|
Widget _buildBody(LoginViewModel viewModel) =>
|
||||||
IndexedStack(index: viewModel.currentIndex, children: _buildScreens());
|
IndexedStack(index: viewModel.currentIndex, children: _buildScreens());
|
||||||
|
|
||||||
|
|
@ -74,4 +78,5 @@ class LoginView extends StackedView<LoginViewModel> with $LoginView {
|
||||||
Widget _buildLoginOtpScreen() => LoginOtpScreen(
|
Widget _buildLoginOtpScreen() => LoginOtpScreen(
|
||||||
otpController: otpController,
|
otpController: otpController,
|
||||||
phoneNumberController: phoneNumberController);
|
phoneNumberController: phoneNumberController);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ class LoginViewModel extends FormViewModel {
|
||||||
await _navigationService.navigateToForgetPasswordView();
|
await _navigationService.navigateToForgetPasswordView();
|
||||||
|
|
||||||
Future<void> replaceWithHome() async =>
|
Future<void> replaceWithHome() async =>
|
||||||
await _navigationService.clearStackAndShow(Routes.homeView);
|
await _navigationService.clearStackAndShowView(const HomeView());
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
|
|
@ -171,8 +171,7 @@ class LoginViewModel extends FormViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> signInWithGoogle() async =>
|
Future<void> signInWithGoogle() async => await runBusyFuture(_signInWithGoogle(),
|
||||||
await runBusyFuture(_signInWithGoogle(),
|
|
||||||
busyObject: StateObjects.loginWithGoogle);
|
busyObject: StateObjects.loginWithGoogle);
|
||||||
|
|
||||||
Future<void> _signInWithGoogle() async {
|
Future<void> _signInWithGoogle() async {
|
||||||
|
|
|
||||||
|
|
@ -21,77 +21,61 @@ class LoginOtpScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
required this.otpController,
|
required this.otpController,
|
||||||
required this.phoneNumberController});
|
required this.phoneNumberController});
|
||||||
|
|
||||||
Widget getPadding(context) {
|
Widget getPadding(context){
|
||||||
double half = screenHeight(context) / 2;
|
double half = screenHeight(context)/2;
|
||||||
return SizedBox(
|
return SizedBox(height: half + 325 - half,);
|
||||||
height: half + 325 - half,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LoginViewModel viewModel) =>
|
Widget build(BuildContext context, LoginViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
_buildScaffoldWrapper(context: context,viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
Widget _buildScaffoldWrapper({required BuildContext context,required LoginViewModel viewModel}) => Scaffold(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(context: context, viewModel: viewModel),
|
body: _buildScaffold(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Column(
|
Widget _buildScaffold({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children:
|
children: _buildScaffoldChildren(context: context,viewModel: viewModel),
|
||||||
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(
|
List<Widget> _buildScaffoldChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
[_buildAppBar(viewModel), _buildExpandedBody(context: context,viewModel: viewModel)];
|
||||||
[
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildExpandedBody(context: context, viewModel: viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar(LoginViewModel viewModel) => const LargeAppBar(
|
Widget _buildAppBar(LoginViewModel viewModel) => const LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
Expanded(child: _buildColumnScroller(context: context,viewModel: viewModel));
|
||||||
Expanded(
|
|
||||||
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildColumnScroller(
|
Widget _buildColumnScroller({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
child: _buildBodyWrapper(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(
|
Widget _buildBodyWrapper({required BuildContext context,required LoginViewModel viewModel}) => Padding(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(context: context, viewModel: viewModel),
|
child: _buildBody(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(
|
Widget _buildBody({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(context: context, viewModel: viewModel),
|
children: _buildBodyChildren(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(
|
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
[
|
|
||||||
_buildUpperColumn(viewModel),
|
List<Widget> _buildBodyChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
getPadding(context),
|
[_buildUpperColumn(viewModel),getPadding(context), _buildContinueButton(viewModel)];
|
||||||
_buildContinueButton(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -99,6 +83,7 @@ class LoginOtpScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(LoginViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(LoginViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,10 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
required this.emailController,
|
required this.emailController,
|
||||||
required this.passwordController});
|
required this.passwordController});
|
||||||
|
|
||||||
Widget getPadding(context) {
|
|
||||||
double half = screenHeight(context) / 2;
|
Widget getPadding(context){
|
||||||
return SizedBox(
|
double half = screenHeight(context)/2;
|
||||||
height: half + 25 - half,
|
return SizedBox(height: half + 25 - half,);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _login(LoginViewModel viewModel) async {
|
Future<void> _login(LoginViewModel viewModel) async {
|
||||||
|
|
@ -43,75 +42,57 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LoginViewModel viewModel) =>
|
Widget build(BuildContext context, LoginViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
_buildScaffoldWrapper(context: context,viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
Widget _buildScaffoldWrapper({required BuildContext context,required LoginViewModel viewModel}) => Scaffold(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
body: _buildScaffoldStack(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldStack(
|
Widget _buildScaffoldStack({required BuildContext context,required LoginViewModel viewModel}) => Stack(children: [
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
_buildScaffold(context: context,viewModel: viewModel),
|
||||||
Stack(children: [
|
|
||||||
_buildScaffold(context: context, viewModel: viewModel),
|
|
||||||
_buildLoginWithEmailState(viewModel),
|
_buildLoginWithEmailState(viewModel),
|
||||||
_buildLoginWithGoogleState(viewModel)
|
_buildLoginWithGoogleState(viewModel)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
Widget _buildScaffold({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children:
|
children: _buildScaffoldChildren(context: context,viewModel: viewModel),
|
||||||
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(
|
List<Widget> _buildScaffoldChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
[_buildAppBar(viewModel), _buildExpandedBody(context: context,viewModel: viewModel)];
|
||||||
[
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildExpandedBody(context: context, viewModel: viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar(LoginViewModel viewModel) => const LargeAppBar(
|
Widget _buildAppBar(LoginViewModel viewModel) => const LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
Expanded(child: _buildColumnScroller(context: context,viewModel: viewModel));
|
||||||
Expanded(
|
|
||||||
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildColumnScroller(
|
Widget _buildColumnScroller({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
child: _buildBodyWrapper(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(
|
Widget _buildBodyWrapper({required BuildContext context,required LoginViewModel viewModel}) => Padding(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(context: context, viewModel: viewModel),
|
child: _buildBody(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(
|
Widget _buildBody({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildBodyChildren(context: context, viewModel: viewModel),
|
children: _buildBodyChildren(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(
|
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
[
|
|
||||||
_buildUpperColumn(viewModel),
|
List<Widget> _buildBodyChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
getPadding(context),
|
[_buildUpperColumn(viewModel),getPadding(context), _buildLowerColumn(viewModel)];
|
||||||
_buildLowerColumn(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -265,6 +246,7 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
text: 'Login with Phone Number',
|
text: 'Login with Phone Number',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
Widget _buildLoginWithEmailState(LoginViewModel viewModel) =>
|
Widget _buildLoginWithEmailState(LoginViewModel viewModel) =>
|
||||||
viewModel.busy(StateObjects.loginWithEmail)
|
viewModel.busy(StateObjects.loginWithEmail)
|
||||||
? const PageLoadingIndicator()
|
? const PageLoadingIndicator()
|
||||||
|
|
|
||||||
|
|
@ -18,76 +18,63 @@ class LoginWithPhoneNumberScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
const LoginWithPhoneNumberScreen(
|
const LoginWithPhoneNumberScreen(
|
||||||
{super.key, required this.phoneNumberController});
|
{super.key, required this.phoneNumberController});
|
||||||
|
|
||||||
Widget getPadding(context) {
|
Widget getPadding(context){
|
||||||
double half = screenHeight(context) / 2;
|
double half = screenHeight(context)/2;
|
||||||
return SizedBox(
|
return SizedBox(height: half + 175 - half,);
|
||||||
height: half + 175 - half,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LoginViewModel viewModel) =>
|
Widget build(BuildContext context, LoginViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
_buildScaffoldWrapper(context: context,viewModel: viewModel);
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
|
|
||||||
|
Widget _buildScaffoldWrapper({required BuildContext context,required LoginViewModel viewModel}) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(context: context, viewModel: viewModel),
|
body: _buildScaffold(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Column(
|
Widget _buildScaffold({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children:
|
children: _buildScaffoldChildren(context: context,viewModel: viewModel),
|
||||||
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(
|
List<Widget> _buildScaffoldChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
[_buildAppBar(viewModel), _buildExpandedBody(context: context,viewModel: viewModel)];
|
||||||
[
|
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildExpandedBody(context: context, viewModel: viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar(LoginViewModel viewModel) => const LargeAppBar(
|
Widget _buildAppBar(LoginViewModel viewModel) => const LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
Expanded(child: _buildColumnScroller(context: context,viewModel: viewModel));
|
||||||
Expanded(
|
|
||||||
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildColumnScroller(
|
Widget _buildColumnScroller({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
child: _buildBodyWrapper(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(
|
Widget _buildBodyWrapper({required BuildContext context,required LoginViewModel viewModel}) => Padding(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(context: context, viewModel: viewModel),
|
child: _buildBody(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(
|
Widget _buildBody({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildBodyChildren(context: context, viewModel: viewModel),
|
children: _buildBodyChildren(context: context,viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(
|
|
||||||
{required BuildContext context, required LoginViewModel viewModel}) =>
|
|
||||||
[
|
|
||||||
_buildUpperColumn(viewModel),
|
List<Widget> _buildBodyChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
||||||
getPadding(context),
|
[_buildUpperColumn(viewModel),getPadding(context), _buildLowerColumn(viewModel)];
|
||||||
_buildLowerColumn(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -95,6 +82,7 @@ class LoginWithPhoneNumberScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(LoginViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(LoginViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
|
|
|
||||||
|
|
@ -481,5 +481,5 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
await _navigationService.navigateToAssessmentView(data: _userData);
|
await _navigationService.navigateToAssessmentView(data: _userData);
|
||||||
|
|
||||||
Future<void> replaceWithHome() async =>
|
Future<void> replaceWithHome() async =>
|
||||||
await _navigationService.clearStackAndShow(Routes.homeView);
|
await _navigationService.clearStackAndShowView(const HomeView());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSubtitle(),
|
_buildSubTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAgeGroups(viewModel)
|
_buildAgeGroups(viewModel)
|
||||||
];
|
];
|
||||||
|
|
@ -91,7 +91,7 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubTitle() => Text(
|
||||||
'We’ll personalize your learning experience based on your age.',
|
'We’ll personalize your learning experience based on your age.',
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ class EducationalBackgroundFormScreen
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSubtitle(),
|
_buildSubTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildEducationalLevels(viewModel)
|
_buildEducationalLevels(viewModel)
|
||||||
];
|
];
|
||||||
|
|
@ -97,7 +97,7 @@ class EducationalBackgroundFormScreen
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => const Text(
|
Widget _buildSubTitle() => const Text(
|
||||||
'This helps us tailor your lessons to your experience.',
|
'This helps us tailor your lessons to your experience.',
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ class OngoingProgressView extends StackedView<OngoingProgressViewModel> {
|
||||||
|
|
||||||
Widget _buildAppbar(OngoingProgressViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(OngoingProgressViewModel viewModel) => SmallAppBar(
|
||||||
title: 'My Progress',
|
title: 'My Progress',
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,8 @@ class PrivacyPolicyView extends StackedView<PrivacyPolicyViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(PrivacyPolicyViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(PrivacyPolicyViewModel viewModel) => SmallAppBar(
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.pop,
|
|
||||||
title: 'Privacy Policy',
|
title: 'Privacy Policy',
|
||||||
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(PrivacyPolicyViewModel viewModel) =>
|
Widget _buildContentWrapper(PrivacyPolicyViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class ProfileViewModel extends ReactiveViewModel {
|
||||||
pop();
|
pop();
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
await updateProfilePicture(image);
|
await updateProfilePicture(image);
|
||||||
await _authenticationService.saveProfilePicture(image);
|
await _authenticationService.saveProfileImage(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ class ProfileViewModel extends ReactiveViewModel {
|
||||||
pop();
|
pop();
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
await updateProfilePicture(image);
|
await updateProfilePicture(image);
|
||||||
await _authenticationService.saveProfilePicture(image);
|
await _authenticationService.saveProfileImage(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,9 +148,8 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppbar(ProfileDetailViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(ProfileDetailViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
|
||||||
showBackButton: true,
|
|
||||||
title: 'Edit Profile',
|
title: 'Edit Profile',
|
||||||
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildColumnWrapper(
|
Widget _buildColumnWrapper(
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
pop();
|
pop();
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
await updateProfilePicture(image);
|
await updateProfilePicture(image);
|
||||||
await _authenticationService.saveProfilePicture(image);
|
await _authenticationService.saveProfileImage(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,7 +197,7 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
pop();
|
pop();
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
await updateProfilePicture(image);
|
await updateProfilePicture(image);
|
||||||
await _authenticationService.saveProfilePicture(image);
|
await _authenticationService.saveProfileImage(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
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/widgets/course_progress_card.dart';
|
import 'package:yimaru_app/ui/widgets/course_level_card.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/skill_progress.dart';
|
import 'package:yimaru_app/ui/widgets/skill_progress.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/suggestion_card.dart';
|
import 'package:yimaru_app/ui/widgets/suggestion_card.dart';
|
||||||
|
|
||||||
|
|
@ -57,7 +57,6 @@ class ProgressView extends StackedView<ProgressViewModel> {
|
||||||
Widget _buildAppbar(ProgressViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(ProgressViewModel viewModel) => SmallAppBar(
|
||||||
title: 'My Progress',
|
title: 'My Progress',
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
showBackButton: true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(ProgressViewModel viewModel) =>
|
Widget _buildContentWrapper(ProgressViewModel viewModel) =>
|
||||||
|
|
@ -115,7 +114,7 @@ class ProgressView extends StackedView<ProgressViewModel> {
|
||||||
required String subtitle,
|
required String subtitle,
|
||||||
required bool isCompleted,
|
required bool isCompleted,
|
||||||
required ProgressViewModel viewModel}) =>
|
required ProgressViewModel viewModel}) =>
|
||||||
CourseProgressCard(
|
CourseLevelCard(
|
||||||
icon: icon,
|
icon: icon,
|
||||||
title: title,
|
title: title,
|
||||||
color: color,
|
color: color,
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,8 @@ class RegisterView extends StackedView<RegisterViewModel> with $RegisterView {
|
||||||
_pop(value: value, viewModel: viewModel),
|
_pop(value: value, viewModel: viewModel),
|
||||||
child: _buildBody(viewModel));
|
child: _buildBody(viewModel));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildBody(RegisterViewModel viewModel) =>
|
Widget _buildBody(RegisterViewModel viewModel) =>
|
||||||
IndexedStack(index: viewModel.currentPage, children: _buildScreens());
|
IndexedStack(index: viewModel.currentPage, children: _buildScreens());
|
||||||
|
|
||||||
|
|
@ -112,4 +114,5 @@ class RegisterView extends StackedView<RegisterViewModel> with $RegisterView {
|
||||||
Widget _buildCreatePasswordScreen() => CreatePasswordScreen(
|
Widget _buildCreatePasswordScreen() => CreatePasswordScreen(
|
||||||
passwordController: passwordController,
|
passwordController: passwordController,
|
||||||
confirmPasswordController: confirmPasswordController);
|
confirmPasswordController: confirmPasswordController);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ class RegisterViewModel extends FormViewModel {
|
||||||
|
|
||||||
final _googleAuthService = locator<GoogleAuthService>();
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
|
|
@ -283,18 +284,17 @@ class RegisterViewModel extends FormViewModel {
|
||||||
await _navigationService.replaceWithLoginView();
|
await _navigationService.replaceWithLoginView();
|
||||||
|
|
||||||
Future<void> replaceWithHome() async =>
|
Future<void> replaceWithHome() async =>
|
||||||
await _navigationService.clearStackAndShow(Routes.homeView);
|
await _navigationService.clearStackAndShowView(const HomeView());
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
Future<void> registerWithEmail() async => await runBusyFuture(_register(),
|
Future<void> registerWithEmail() async =>
|
||||||
busyObject: StateObjects.registerWithEmail);
|
await runBusyFuture(_register(), busyObject: StateObjects.registerWithEmail);
|
||||||
|
|
||||||
Future<void> _register() async {
|
Future<void> _register() async {
|
||||||
if (await _statusChecker.checkConnection()) {
|
if (await _statusChecker.checkConnection()) {
|
||||||
Map<String, dynamic> response =
|
Map<String, dynamic> response = await _apiService.registerWithEmail(_userData);
|
||||||
await _apiService.registerWithEmail(_userData);
|
|
||||||
|
|
||||||
if (response['status'] == ResponseStatus.success) {
|
if (response['status'] == ResponseStatus.success) {
|
||||||
goTo(page: 3);
|
goTo(page: 3);
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,8 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
onTap: () => viewModel.goTo(page: 1),
|
onTap: () => viewModel.goTo(page: 1),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildRegisterWithGoogleState(RegisterViewModel viewModel) =>
|
Widget _buildRegisterWithGoogleState(RegisterViewModel viewModel) =>
|
||||||
viewModel.busy(StateObjects.registerWithEmail)
|
viewModel.busy(StateObjects.registerWithEmail)
|
||||||
? const PageLoadingIndicator()
|
? const PageLoadingIndicator()
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,10 @@ class RegistrationOtpScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
required this.emailController,
|
required this.emailController,
|
||||||
required this.phoneNumberController});
|
required this.phoneNumberController});
|
||||||
|
|
||||||
Widget getPadding(context) {
|
|
||||||
double half = screenHeight(context) / 2;
|
Widget getPadding(context){
|
||||||
return SizedBox(
|
double half = screenHeight(context)/2;
|
||||||
height: half + 325 - half,
|
return SizedBox(height: half + 325 - half,);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _verifyOtp(RegisterViewModel viewModel) async {
|
Future<void> _verifyOtp(RegisterViewModel viewModel) async {
|
||||||
|
|
@ -46,14 +45,13 @@ class RegistrationOtpScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
await viewModel.verifyOtp();
|
await viewModel.verifyOtp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, RegisterViewModel viewModel) =>
|
Widget build(BuildContext context, RegisterViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
Widget _buildScaffoldWrapper( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required RegisterViewModel viewModel}) => Scaffold(
|
||||||
required RegisterViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
@ -68,66 +66,49 @@ class RegistrationOtpScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
Widget _buildScaffold( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required RegisterViewModel viewModel}) => Column(
|
||||||
required RegisterViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children:
|
children: _buildScaffoldChildren(context: context, viewModel: viewModel),
|
||||||
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(
|
List<Widget> _buildScaffoldChildren( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required RegisterViewModel viewModel}) =>
|
required RegisterViewModel viewModel}) =>
|
||||||
[
|
[_buildAppBar(viewModel), _buildExpandedBody(context: context, viewModel: viewModel)];
|
||||||
_buildAppBar(viewModel),
|
|
||||||
_buildExpandedBody(context: context, viewModel: viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar(RegisterViewModel viewModel) => const LargeAppBar(
|
Widget _buildAppBar(RegisterViewModel viewModel) => const LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(
|
Widget _buildExpandedBody( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required RegisterViewModel viewModel}) =>
|
required RegisterViewModel viewModel}) =>
|
||||||
Expanded(
|
Expanded(child: _buildColumnScroller(context: context, viewModel: viewModel));
|
||||||
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildColumnScroller(
|
Widget _buildColumnScroller( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required RegisterViewModel viewModel}) =>
|
required RegisterViewModel viewModel}) =>
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(
|
Widget _buildBodyWrapper( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required RegisterViewModel viewModel}) => Padding(
|
||||||
required RegisterViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(context: context, viewModel: viewModel),
|
child: _buildBody(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(
|
Widget _buildBody( {required BuildContext context,
|
||||||
{required BuildContext context,
|
required RegisterViewModel viewModel}) => Column(
|
||||||
required RegisterViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(context: context, viewModel: viewModel),
|
children: _buildBodyChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(
|
List<Widget> _buildBodyChildren( {required BuildContext context,
|
||||||
{required BuildContext context,
|
|
||||||
required RegisterViewModel viewModel}) =>
|
required RegisterViewModel viewModel}) =>
|
||||||
[
|
[_buildUpperColumn(viewModel),getPadding(context), _buildContinueButtonWrapper(viewModel)];
|
||||||
_buildUpperColumn(viewModel),
|
|
||||||
getPadding(context),
|
|
||||||
_buildContinueButtonWrapper(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildUpperColumn(RegisterViewModel viewModel) => Column(
|
Widget _buildUpperColumn(RegisterViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,8 @@ class StartupView extends StackedView<StartupViewModel> {
|
||||||
_buildIndicatorWrapper(),
|
_buildIndicatorWrapper(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildLoadingText() => Text('$label ...', style: style16W600);
|
Widget _buildLoadingText() =>
|
||||||
|
Text('$label ...', style: const TextStyle(color: kcWhite, fontSize: 16));
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
Widget _buildIndicatorWrapper() => SizedBox(
|
||||||
width: 16,
|
width: 16,
|
||||||
|
|
@ -82,7 +83,7 @@ class StartupView extends StackedView<StartupViewModel> {
|
||||||
const CustomCircularProgressIndicator(color: kcWhite);
|
const CustomCircularProgressIndicator(color: kcWhite);
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Padding(
|
Widget _buildIconWrapper() => Padding(
|
||||||
padding: const EdgeInsets.only(top: 120),
|
padding: const EdgeInsets.only(top: 100),
|
||||||
child: _buildIcon(),
|
child: _buildIcon(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,6 @@ class SupportView extends StackedView<SupportViewModel> {
|
||||||
|
|
||||||
Widget _buildAppbar(SupportViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(SupportViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Need Help?',
|
title: 'Need Help?',
|
||||||
showBackButton: true,
|
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,8 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(TelegramSupportViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(TelegramSupportViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
|
||||||
showBackButton: true,
|
|
||||||
title: 'Telegram Support',
|
title: 'Telegram Support',
|
||||||
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedColumn(TelegramSupportViewModel viewModel) =>
|
Widget _buildExpandedColumn(TelegramSupportViewModel viewModel) =>
|
||||||
|
|
@ -85,7 +84,7 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSubtitle(),
|
_buildSubTitle(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildIcon() =>
|
Widget _buildIcon() =>
|
||||||
|
|
@ -101,7 +100,7 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => const Text(
|
Widget _buildSubTitle() => const Text(
|
||||||
'Connect with our support team instantly on Telegram for quick assistance and community updates',
|
'Connect with our support team instantly on Telegram for quick assistance and community updates',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
|
|
|
||||||
|
|
@ -57,9 +57,8 @@ class TermsAndConditionsView extends StackedView<TermsAndConditionsViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(TermsAndConditionsViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(TermsAndConditionsViewModel viewModel) => SmallAppBar(
|
||||||
onTap: viewModel.pop,
|
|
||||||
showBackButton: true,
|
|
||||||
title: 'Terms and Conditions',
|
title: 'Terms and Conditions',
|
||||||
|
onTap: viewModel.pop,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(TermsAndConditionsViewModel viewModel) =>
|
Widget _buildContentWrapper(TermsAndConditionsViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -59,10 +59,14 @@ class FirstWelcomeScreen extends ViewModelWidget<WelcomeViewModel> {
|
||||||
height: 50,
|
height: 50,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => const Text(
|
||||||
'Small daily practice. Big lifelong results.',
|
'Small daily practice. Big lifelong results.',
|
||||||
style: style25W600,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 30,
|
||||||
|
color: kcWhite,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(WelcomeViewModel viewModel) => Align(
|
Widget _buildContinueButtonWrapper(WelcomeViewModel viewModel) => Align(
|
||||||
|
|
@ -81,8 +85,8 @@ class FirstWelcomeScreen extends ViewModelWidget<WelcomeViewModel> {
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
text: 'Start Learning',
|
text: 'Start Learning',
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
|
trailingIcon: Icons.arrow_forward,
|
||||||
onTap: () => viewModel.next(),
|
onTap: () => viewModel.next(),
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
trailingIcon: Icons.arrow_forward,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ class BirthdaySelector extends StatelessWidget {
|
||||||
context: context,
|
context: context,
|
||||||
is24HourMode: false,
|
is24HourMode: false,
|
||||||
isShowSeconds: false,
|
isShowSeconds: false,
|
||||||
title: _buildTitle(),
|
|
||||||
lastDate: DateTime.now(),
|
lastDate: DateTime.now(),
|
||||||
firstDate: DateTime(1900),
|
firstDate: DateTime(1900),
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
|
|
@ -35,6 +34,7 @@ class BirthdaySelector extends StatelessWidget {
|
||||||
type: OmniDateTimePickerType.date,
|
type: OmniDateTimePickerType.date,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
||||||
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 24),
|
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 24),
|
||||||
|
title: const Text('Birthday', style: TextStyle(fontSize: 16)),
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme:
|
colorScheme:
|
||||||
const ColorScheme.light().copyWith(primary: kcPrimaryColor),
|
const ColorScheme.light().copyWith(primary: kcPrimaryColor),
|
||||||
|
|
@ -72,8 +72,6 @@ class BirthdaySelector extends StatelessWidget {
|
||||||
child: _buildContainer(),
|
child: _buildContainer(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text('Birthday', style: style16DG600);
|
|
||||||
|
|
||||||
Widget _buildContainer() => Container(
|
Widget _buildContainer() => Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ class CancelLearnPracticeSheet extends StatelessWidget {
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildContinueButton(),
|
_buildContinueButton(),
|
||||||
_buildEndButton(),
|
_buildEndButton(),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildImage() => const SpeakingPartnerImage(
|
Widget _buildImage() => const SpeakingPartnerImage(
|
||||||
|
|
@ -44,7 +45,7 @@ class CancelLearnPracticeSheet extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildMessage() => Text.rich(
|
Widget _buildMessage() => Text.rich(
|
||||||
TextSpan(text: 'You’re almost there,', style: style18DG700, children: [
|
TextSpan(text: 'You’re almost there,', style: style18DG600, children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ' Johnny!',
|
text: ' Johnny!',
|
||||||
style: style18P600,
|
style: style18P600,
|
||||||
|
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import '../common/app_colors.dart';
|
|
||||||
import '../common/ui_helpers.dart';
|
|
||||||
import 'custom_elevated_button.dart';
|
|
||||||
|
|
||||||
class CourseCard extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
final String subtitle;
|
|
||||||
final GestureTapCallback? onTap;
|
|
||||||
|
|
||||||
const CourseCard(
|
|
||||||
{super.key, this.onTap, required this.title, required this.subtitle});
|
|
||||||
|
|
||||||
Color _getColor() {
|
|
||||||
if (title == 'English Proficiency Exams') {
|
|
||||||
return kcRed.withValues(alpha: 0.2);
|
|
||||||
} else {
|
|
||||||
return kcAquamarine.withValues(alpha: 0.2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => _buildContainer();
|
|
||||||
|
|
||||||
Widget _buildContainer() => Container(
|
|
||||||
height: 200,
|
|
||||||
padding: const EdgeInsets.all(15),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: _getColor(),
|
|
||||||
borderRadius: BorderRadius.circular(5),
|
|
||||||
),
|
|
||||||
child: _buildColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildColumn() => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildColumnChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren() => [
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceTiny,
|
|
||||||
_buildSubtitle(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
__buildStartButtonWrapper(),
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
title,
|
|
||||||
style: style18DG700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
subtitle,
|
|
||||||
style: style16DG400,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget __buildStartButtonWrapper() => SizedBox(
|
|
||||||
height: 40,
|
|
||||||
child: _buildStartButton(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildStartButton() => CustomElevatedButton(
|
|
||||||
height: 50,
|
|
||||||
width: 200,
|
|
||||||
onTap: onTap,
|
|
||||||
borderRadius: 12,
|
|
||||||
text: 'Start Course',
|
|
||||||
foregroundColor: kcWhite,
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -6,7 +6,7 @@ import '../common/app_colors.dart';
|
||||||
import '../common/ui_helpers.dart';
|
import '../common/ui_helpers.dart';
|
||||||
import 'custom_elevated_button.dart';
|
import 'custom_elevated_button.dart';
|
||||||
|
|
||||||
class CourseProgressCard extends StatelessWidget {
|
class CourseLevelCard extends StatelessWidget {
|
||||||
final Color color;
|
final Color color;
|
||||||
final String icon;
|
final String icon;
|
||||||
final String title;
|
final String title;
|
||||||
|
|
@ -15,7 +15,7 @@ class CourseProgressCard extends StatelessWidget {
|
||||||
final bool isCompleted;
|
final bool isCompleted;
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback? onTap;
|
||||||
|
|
||||||
const CourseProgressCard({
|
const CourseLevelCard({
|
||||||
super.key,
|
super.key,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
required this.icon,
|
required this.icon,
|
||||||
|
|
@ -56,7 +56,7 @@ class CourseProgressCard extends StatelessWidget {
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSubtitle(),
|
_buildSubTitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildActionButton()
|
_buildActionButton()
|
||||||
];
|
];
|
||||||
|
|
@ -89,7 +89,7 @@ class CourseProgressCard extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Expanded(
|
Widget _buildSubTitle() => Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
subtitle,
|
subtitle,
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
|
|
@ -1,132 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:iconsax/iconsax.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/course_module/course_module_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/learn_module/learn_module_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_linear_progress_indicator.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/finish_practice_sheet.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/progress_status.dart';
|
|
||||||
|
|
||||||
import '../common/app_colors.dart';
|
|
||||||
import '../common/enmus.dart';
|
|
||||||
import '../common/ui_helpers.dart';
|
|
||||||
import 'custom_elevated_button.dart';
|
|
||||||
|
|
||||||
class CourseModuleTile extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
final GestureTapCallback? onCourseTap;
|
|
||||||
final GestureTapCallback? onPracticeTap;
|
|
||||||
|
|
||||||
const CourseModuleTile({
|
|
||||||
super.key,
|
|
||||||
this.onCourseTap,
|
|
||||||
this.onPracticeTap,
|
|
||||||
required this.title,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => _buildExpansionTileCard();
|
|
||||||
|
|
||||||
Widget _buildExpansionTileCard() => Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(5),
|
|
||||||
border: Border.all(
|
|
||||||
color: kcPrimaryColor.withOpacity(0.2),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: _buildExpansionTile(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildExpansionTile() => ExpansionTile(
|
|
||||||
enabled: true,
|
|
||||||
title: _buildTitle(),
|
|
||||||
textColor: kcDarkGrey,
|
|
||||||
showTrailingIcon: false,
|
|
||||||
initiallyExpanded: false,
|
|
||||||
collapsedIconColor: kcDarkGrey,
|
|
||||||
collapsedTextColor: kcDarkGrey,
|
|
||||||
shape: Border.all(color: kcTransparent),
|
|
||||||
expandedAlignment: Alignment.centerLeft,
|
|
||||||
backgroundColor: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
controlAffinity: ListTileControlAffinity.trailing,
|
|
||||||
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
childrenPadding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
children: _buildExpansionTileChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildExpansionTileChildren() => [
|
|
||||||
_buildProgressRow(),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildActionButtonWrapper(),
|
|
||||||
verticalSpaceSmall
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
title,
|
|
||||||
style: style16P600,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildProgressRow() => Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: _buildProgressChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildProgressChildren() =>
|
|
||||||
[_buildProgressStatusWrapper(), horizontalSpaceSmall, _buildProgress()];
|
|
||||||
|
|
||||||
Widget _buildProgressStatusWrapper() => Expanded(
|
|
||||||
child: _buildProgressStatus(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildProgressStatus() => const CustomLinearProgressIndicator(
|
|
||||||
progress: 0.75,
|
|
||||||
activeColor: kcPrimaryColor,
|
|
||||||
backgroundColor: kcVeryLightGrey);
|
|
||||||
|
|
||||||
Widget _buildProgress() => const Text(
|
|
||||||
'75%',
|
|
||||||
style: TextStyle(color: kcDarkGrey),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildActionButtonWrapper() => SizedBox(
|
|
||||||
height: 40,
|
|
||||||
width: 300,
|
|
||||||
child: _buildActionButtons(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildActionButtons() => Row(
|
|
||||||
children: [
|
|
||||||
_buildStartButtonWrapper(),
|
|
||||||
horizontalSpaceSmall,
|
|
||||||
_buildExamButtonWrapper()
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildStartButtonWrapper() => Expanded(
|
|
||||||
child: _buildStartButton(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildStartButton() => CustomElevatedButton(
|
|
||||||
height: 15,
|
|
||||||
borderRadius: 8,
|
|
||||||
onTap: onCourseTap,
|
|
||||||
text: 'Start Course',
|
|
||||||
foregroundColor: kcWhite,
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildExamButtonWrapper() => Expanded(
|
|
||||||
child: _buildExamButton(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildExamButton() => CustomElevatedButton(
|
|
||||||
height: 15,
|
|
||||||
borderRadius: 8,
|
|
||||||
onTap: onPracticeTap,
|
|
||||||
text: 'Take Mock Exam',
|
|
||||||
backgroundColor: kcWhite,
|
|
||||||
borderColor: kcPrimaryColor,
|
|
||||||
foregroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
|
|
||||||
import '../common/ui_helpers.dart';
|
|
||||||
|
|
||||||
class CoursePaymentCard extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
final IconData icon;
|
|
||||||
final String subtitle;
|
|
||||||
|
|
||||||
const CoursePaymentCard(
|
|
||||||
{super.key,
|
|
||||||
required this.icon,
|
|
||||||
required this.title,
|
|
||||||
required this.subtitle});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => _buildListTile();
|
|
||||||
|
|
||||||
Widget _buildListTile() => ListTile(
|
|
||||||
title: _buildTitle(),
|
|
||||||
leading: _buildLeading(),
|
|
||||||
subtitle: _buildSubtitle(),
|
|
||||||
tileColor: kcPrimaryColor.withValues(alpha: 0.1),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
side: BorderSide(color: kcPrimaryColor.withValues(alpha: 0.25)),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
title,
|
|
||||||
style: style16DG600,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
subtitle,
|
|
||||||
style: style14DG400,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLeading() => CircleAvatar(
|
|
||||||
radius: 25,
|
|
||||||
backgroundColor: kcPrimaryColor.withValues(alpha: 0.25),
|
|
||||||
child: _buildIcon(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildIcon() => Icon(
|
|
||||||
icon,
|
|
||||||
size: 25,
|
|
||||||
color: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
|
||||||
|
|
||||||
import '../common/ui_helpers.dart';
|
|
||||||
import 'custom_elevated_button.dart';
|
|
||||||
|
|
||||||
class CoursePracticeCard extends StatelessWidget {
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
const CoursePracticeCard({super.key, required this.title});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => _buildContainer();
|
|
||||||
|
|
||||||
Widget _buildContainer() => Container(
|
|
||||||
height: 200,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(5),
|
|
||||||
color: kcPrimaryColor.withValues(alpha: 0.25),
|
|
||||||
),
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 12),
|
|
||||||
child: _buildColumn(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildColumn() =>
|
|
||||||
Column(mainAxisSize: MainAxisSize.min, children: _buildColumnChildren());
|
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren() => [
|
|
||||||
verticalSpaceTiny,
|
|
||||||
_buildTitle(),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildStartButtonWrapper()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
|
||||||
title,
|
|
||||||
style: style18DG700,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildStartButtonWrapper() => SizedBox(
|
|
||||||
height: 40,
|
|
||||||
child: _buildStartButton(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildStartButton() => CustomElevatedButton(
|
|
||||||
height: 50,
|
|
||||||
width: 200,
|
|
||||||
borderRadius: 8,
|
|
||||||
text: 'Start Test',
|
|
||||||
foregroundColor: kcWhite,
|
|
||||||
backgroundColor: kcPrimaryColor,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -9,6 +9,6 @@ class CustomCircularProgressIndicator extends StatelessWidget {
|
||||||
|
|
||||||
Widget _buildIndicator() => CircularProgressIndicator(
|
Widget _buildIndicator() => CircularProgressIndicator(
|
||||||
color: color,
|
color: color,
|
||||||
strokeWidth: 5,
|
strokeWidth: 6,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user