Compare commits
No commits in common. "2e23d8808c6e704b651e2375145e44a8e9192fdb" and "c45f90ad82b88f3fac2eb459a188afca26a1afb4" have entirely different histories.
2e23d8808c
...
c45f90ad82
|
|
@ -182,9 +182,8 @@
|
||||||
"lets_start_practice": "ልምምድህን እንጀምር",
|
"lets_start_practice": "ልምምድህን እንጀምር",
|
||||||
"welcome_abroad": "እንኳን ደህና መጣህ",
|
"welcome_abroad": "እንኳን ደህና መጣህ",
|
||||||
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
||||||
"finish": "አጠናቅቅ",
|
"finish": "አጠናቅቅ"
|
||||||
|
|
||||||
"finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@
|
||||||
"open_in_telegram": "Open in Telegram",
|
"open_in_telegram": "Open in Telegram",
|
||||||
"search_for": "Search for",
|
"search_for": "Search for",
|
||||||
"current_level": "Current Level",
|
"current_level": "Current Level",
|
||||||
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
|
"keep_up_the_great_work": "Keep up the great work! You\\'re doing amazing.",
|
||||||
"no_practice_available": "No practice available!",
|
"no_practice_available": "No practice available!",
|
||||||
"begin_module_practice": "Begin Module Practice",
|
"begin_module_practice": "Begin Module Practice",
|
||||||
"lets_practice_lesson": "Let’s Practice",
|
"lets_practice_lesson": "Let’s Practice",
|
||||||
|
|
@ -182,6 +182,5 @@
|
||||||
"lets_start_practice": "Let's start your practice",
|
"lets_start_practice": "Let's start your practice",
|
||||||
"welcome_abroad": "Welcome aboard",
|
"welcome_abroad": "Welcome aboard",
|
||||||
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
||||||
"finish": "Finish",
|
"finish": "Finish"
|
||||||
"finish_all_practice": "Finish all the practices in the lessons to take this practice"
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:toastification/toastification.dart';
|
import 'package:toastification/toastification.dart';
|
||||||
import 'package:yimaru_app/app/app.bottomsheets.dart';
|
import 'package:yimaru_app/app/app.bottomsheets.dart';
|
||||||
import 'package:yimaru_app/app/app.dialogs.dart';
|
import 'package:yimaru_app/app/app.dialogs.dart';
|
||||||
|
|
@ -14,15 +13,12 @@ import 'firebase_options.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
await setupLocator();
|
await setupLocator();
|
||||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||||
await locator<NotificationService>().initialize();
|
await locator<NotificationService>().initialize();
|
||||||
await EasyLocalization.ensureInitialized();
|
await EasyLocalization.ensureInitialized();
|
||||||
setupDialogUi();
|
setupDialogUi();
|
||||||
setupBottomSheetUi();
|
setupBottomSheetUi();
|
||||||
await SystemChrome.setPreferredOrientations(
|
|
||||||
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
|
||||||
runApp(
|
runApp(
|
||||||
EasyLocalization(
|
EasyLocalization(
|
||||||
supportedLocales: const [
|
supportedLocales: const [
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class Access {
|
||||||
final int? progressPercent;
|
final int? progressPercent;
|
||||||
|
|
||||||
@JsonKey(name: 'progress_percent_precise')
|
@JsonKey(name: 'progress_percent_precise')
|
||||||
final double? progressPercentPrecise;
|
final int? progressPercentPrecise;
|
||||||
|
|
||||||
const Access({
|
const Access({
|
||||||
this.reason,
|
this.reason,
|
||||||
|
|
@ -40,7 +40,7 @@ class Access {
|
||||||
bool? isAccessible,
|
bool? isAccessible,
|
||||||
int? completedCount,
|
int? completedCount,
|
||||||
int? progressPercent,
|
int? progressPercent,
|
||||||
double? progressPercentPrecise,
|
int? progressPercentPrecise,
|
||||||
}) {
|
}) {
|
||||||
return Access(
|
return Access(
|
||||||
reason: reason ?? this.reason,
|
reason: reason ?? this.reason,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ Access _$AccessFromJson(Map<String, dynamic> json) => Access(
|
||||||
completedCount: (json['completed_count'] as num?)?.toInt(),
|
completedCount: (json['completed_count'] as num?)?.toInt(),
|
||||||
progressPercent: (json['progress_percent'] as num?)?.toInt(),
|
progressPercent: (json['progress_percent'] as num?)?.toInt(),
|
||||||
progressPercentPrecise:
|
progressPercentPrecise:
|
||||||
(json['progress_percent_precise'] as num?)?.toDouble(),
|
(json['progress_percent_precise'] as num?)?.toInt(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$AccessToJson(Access instance) => <String, dynamic>{
|
Map<String, dynamic> _$AccessToJson(Access instance) => <String, dynamic>{
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,8 @@ class User {
|
||||||
@JsonKey(name: 'profile_picture_url')
|
@JsonKey(name: 'profile_picture_url')
|
||||||
final String? profilePicture;
|
final String? profilePicture;
|
||||||
|
|
||||||
const User(
|
const User({
|
||||||
{this.email,
|
this.email,
|
||||||
this.region,
|
this.region,
|
||||||
this.gender,
|
this.gender,
|
||||||
this.userId,
|
this.userId,
|
||||||
|
|
@ -58,7 +58,8 @@ class User {
|
||||||
this.profilePicture,
|
this.profilePicture,
|
||||||
this.userInfoLoaded,
|
this.userInfoLoaded,
|
||||||
this.profileCompleted,
|
this.profileCompleted,
|
||||||
this.subscriptionStatus});
|
this.subscriptionStatus
|
||||||
|
});
|
||||||
|
|
||||||
User copyWith(
|
User copyWith(
|
||||||
{int? userId,
|
{int? userId,
|
||||||
|
|
@ -74,8 +75,7 @@ class User {
|
||||||
String? refreshToken,
|
String? refreshToken,
|
||||||
bool? userInfoLoaded,
|
bool? userInfoLoaded,
|
||||||
bool? profileCompleted,
|
bool? profileCompleted,
|
||||||
String? profilePicture,
|
String? profilePicture}) =>
|
||||||
String? subscriptionStatus}) =>
|
|
||||||
User(
|
User(
|
||||||
email: email ?? this.email,
|
email: email ?? this.email,
|
||||||
userId: userId ?? this.userId,
|
userId: userId ?? this.userId,
|
||||||
|
|
@ -90,8 +90,7 @@ class User {
|
||||||
refreshToken: refreshToken ?? this.refreshToken,
|
refreshToken: refreshToken ?? this.refreshToken,
|
||||||
userInfoLoaded: userInfoLoaded ?? this.userInfoLoaded,
|
userInfoLoaded: userInfoLoaded ?? this.userInfoLoaded,
|
||||||
profilePicture: profilePicture ?? this.profilePicture,
|
profilePicture: profilePicture ?? this.profilePicture,
|
||||||
profileCompleted: profileCompleted ?? this.profileCompleted,
|
profileCompleted: profileCompleted ?? this.profileCompleted);
|
||||||
subscriptionStatus: subscriptionStatus ?? this.subscriptionStatus);
|
|
||||||
|
|
||||||
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
|
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ User _$UserFromJson(Map<String, dynamic> json) => User(
|
||||||
profilePicture: json['profile_picture_url'] as String?,
|
profilePicture: json['profile_picture_url'] as String?,
|
||||||
userInfoLoaded: json['userInfoLoaded'] as bool?,
|
userInfoLoaded: json['userInfoLoaded'] as bool?,
|
||||||
profileCompleted: json['profile_completed'] as bool?,
|
profileCompleted: json['profile_completed'] as bool?,
|
||||||
subscriptionStatus: json['subscription_status'] as String?,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
|
Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
|
||||||
|
|
@ -38,6 +37,5 @@ Map<String, dynamic> _$UserToJson(User instance) => <String, dynamic>{
|
||||||
'access_token': instance.accessToken,
|
'access_token': instance.accessToken,
|
||||||
'refresh_token': instance.refreshToken,
|
'refresh_token': instance.refreshToken,
|
||||||
'profile_completed': instance.profileCompleted,
|
'profile_completed': instance.profileCompleted,
|
||||||
'subscription_status': instance.subscriptionStatus,
|
|
||||||
'profile_picture_url': instance.profilePicture,
|
'profile_picture_url': instance.profilePicture,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ class DioService {
|
||||||
DioService() {
|
DioService() {
|
||||||
_dio.options
|
_dio.options
|
||||||
..baseUrl = kBaseUrl
|
..baseUrl = kBaseUrl
|
||||||
..connectTimeout = const Duration(seconds: 10)
|
..connectTimeout = const Duration(seconds: 5)
|
||||||
..receiveTimeout = const Duration(seconds: 15);
|
..receiveTimeout = const Duration(seconds: 15);
|
||||||
|
|
||||||
_dio.interceptors.add(
|
_dio.interceptors.add(
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class LearnService with ListenableServiceMixin {
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
learnService() {
|
learnService() {
|
||||||
listenToReactiveValues([_programs,_courses, _lessons, _modules]);
|
listenToReactiveValues([_programs, _lessons, _modules]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Learn program
|
// Learn program
|
||||||
|
|
@ -89,6 +89,7 @@ class LearnService with ListenableServiceMixin {
|
||||||
// Learn progress
|
// Learn progress
|
||||||
Future<void> getLearnProgressSummary() async {
|
Future<void> getLearnProgressSummary() async {
|
||||||
final summaries = await _apiService.getProgressSummary();
|
final summaries = await _apiService.getProgressSummary();
|
||||||
|
print('MY SUMMARIES: ${summaries.length}');
|
||||||
|
|
||||||
/// PROGRAM ACCESS MAP
|
/// PROGRAM ACCESS MAP
|
||||||
final Map<int, Access?> programAccessMap = {};
|
final Map<int, Access?> programAccessMap = {};
|
||||||
|
|
@ -148,11 +149,6 @@ class LearnService with ListenableServiceMixin {
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
print('MY SUMMARIES - COMPLETED COUNT: ${_modules.first.access?.completedCount}');
|
|
||||||
print('PROGRESS PERCENT: ${_modules.first.access?.progressPercent}');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// UPDATE LESSONS
|
/// UPDATE LESSONS
|
||||||
_lessons = _lessons.map((lesson) {
|
_lessons = _lessons.map((lesson) {
|
||||||
return lesson.copyWith(
|
return lesson.copyWith(
|
||||||
|
|
@ -162,24 +158,4 @@ class LearnService with ListenableServiceMixin {
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
LearnModule? getLearnModuleById(int id) {
|
|
||||||
try {
|
|
||||||
return _modules.firstWhere((e) => e.id == id);
|
|
||||||
} catch (_) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
LearnCourse? getLearnCourseById(int id) {
|
|
||||||
try {
|
|
||||||
return _courses.firstWhere((e) => e.id == id);
|
|
||||||
} catch (_) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ enum StateObjects {
|
||||||
learnModules,
|
learnModules,
|
||||||
learnCourses,
|
learnCourses,
|
||||||
profileImage,
|
profileImage,
|
||||||
paymentStatus,
|
|
||||||
profileDetail,
|
profileDetail,
|
||||||
learnPrograms,
|
learnPrograms,
|
||||||
courseLessons,
|
courseLessons,
|
||||||
|
|
|
||||||
|
|
@ -198,8 +198,7 @@ class CodegenLoader extends AssetLoader{
|
||||||
"lets_start_practice": "ልምምድህን እንጀምር",
|
"lets_start_practice": "ልምምድህን እንጀምር",
|
||||||
"welcome_abroad": "እንኳን ደህና መጣህ",
|
"welcome_abroad": "እንኳን ደህና መጣህ",
|
||||||
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
"ready_to_explore": "የግል ትምህርቶችህን ለማሰስ ዝግጁ ነህ።",
|
||||||
"finish": "አጠናቅቅ",
|
"finish": "አጠናቅቅ"
|
||||||
"finish_all_practice": "ልምምዱን ለመውሰድ በትምህርቶቹ ውስጥ ያሉትን ሁሉንም ልምምዶች ያጠናቅቁ።"
|
|
||||||
};
|
};
|
||||||
static const Map<String,dynamic> _en = {
|
static const Map<String,dynamic> _en = {
|
||||||
"loading": "Loading",
|
"loading": "Loading",
|
||||||
|
|
@ -328,7 +327,7 @@ static const Map<String,dynamic> _en = {
|
||||||
"open_in_telegram": "Open in Telegram",
|
"open_in_telegram": "Open in Telegram",
|
||||||
"search_for": "Search for",
|
"search_for": "Search for",
|
||||||
"current_level": "Current Level",
|
"current_level": "Current Level",
|
||||||
"keep_up_the_great_work": "Keep up the great work! You're doing amazing.",
|
"keep_up_the_great_work": "Keep up the great work! You\\'re doing amazing.",
|
||||||
"no_practice_available": "No practice available!",
|
"no_practice_available": "No practice available!",
|
||||||
"begin_module_practice": "Begin Module Practice",
|
"begin_module_practice": "Begin Module Practice",
|
||||||
"lets_practice_lesson": "Let’s Practice",
|
"lets_practice_lesson": "Let’s Practice",
|
||||||
|
|
@ -385,8 +384,7 @@ static const Map<String,dynamic> _en = {
|
||||||
"lets_start_practice": "Let's start your practice",
|
"lets_start_practice": "Let's start your practice",
|
||||||
"welcome_abroad": "Welcome aboard",
|
"welcome_abroad": "Welcome aboard",
|
||||||
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
"ready_to_explore": "You’re ready to explore your personalized lessons.",
|
||||||
"finish": "Finish",
|
"finish": "Finish"
|
||||||
"finish_all_practice": "Finish all the practices in the lessons to take this practice"
|
|
||||||
};
|
};
|
||||||
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en};
|
static const Map<String, Map<String,dynamic>> mapLocales = {"am": _am, "en": _en};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,5 @@ abstract class LocaleKeys {
|
||||||
static const welcome_abroad = 'welcome_abroad';
|
static const welcome_abroad = 'welcome_abroad';
|
||||||
static const ready_to_explore = 'ready_to_explore';
|
static const ready_to_explore = 'ready_to_explore';
|
||||||
static const finish = 'finish';
|
static const finish = 'finish';
|
||||||
static const finish_all_practice = 'finish_all_practice';
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,12 @@ class ArifPayView extends StackedView<ArifPayViewModel> {
|
||||||
|
|
||||||
const ArifPayView({Key? key, required this.phone}) : super(key: key);
|
const ArifPayView({Key? key, required this.phone}) : super(key: key);
|
||||||
|
|
||||||
|
void _pop(ArifPayViewModel viewModel) => viewModel.pop;
|
||||||
|
|
||||||
void _error(ArifPayViewModel viewModel) => viewModel.pop();
|
void _error(ArifPayViewModel viewModel) => viewModel.pop();
|
||||||
|
|
||||||
|
Future<void> _success(ArifPayViewModel viewModel) async =>
|
||||||
Future<void> _success(ArifPayViewModel viewModel) async {
|
|
||||||
|
|
||||||
await viewModel.updatePaymentStatus();
|
|
||||||
|
|
||||||
await viewModel.replaceWithHome();
|
await viewModel.replaceWithHome();
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(ArifPayViewModel viewModel) async {
|
void onViewModelReady(ArifPayViewModel viewModel) async {
|
||||||
|
|
@ -49,8 +45,6 @@ class ArifPayView extends StackedView<ArifPayViewModel> {
|
||||||
? const PageLoadingIndicator()
|
? const PageLoadingIndicator()
|
||||||
: _buildScaffold(viewModel);
|
: _buildScaffold(viewModel);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildScaffold(ArifPayViewModel viewModel) =>
|
Widget _buildScaffold(ArifPayViewModel viewModel) =>
|
||||||
SafeArea(child: _buildBody(viewModel));
|
SafeArea(child: _buildBody(viewModel));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,10 @@ import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../app/app.router.dart';
|
import '../../../app/app.router.dart';
|
||||||
import '../../../models/learn_subscription_request.dart';
|
import '../../../models/learn_subscription_request.dart';
|
||||||
import '../../../models/user.dart';
|
|
||||||
import '../../../services/api_service.dart';
|
import '../../../services/api_service.dart';
|
||||||
import '../../../services/authentication_service.dart';
|
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
import '../../common/ui_helpers.dart';
|
|
||||||
|
|
||||||
class ArifPayViewModel extends ReactiveViewModel {
|
class ArifPayViewModel extends BaseViewModel {
|
||||||
// Dependency injection
|
// Dependency injection
|
||||||
|
|
||||||
final _apiService = locator<ApiService>();
|
final _apiService = locator<ApiService>();
|
||||||
|
|
@ -20,16 +17,6 @@ class ArifPayViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<ListenableServiceMixin> get listenableServices =>
|
|
||||||
[_authenticationService];
|
|
||||||
|
|
||||||
// Current user
|
|
||||||
User? get _user => _authenticationService.user;
|
|
||||||
|
|
||||||
User? get user => _user;
|
|
||||||
// Learn subscription request
|
// Learn subscription request
|
||||||
LearnSubscriptionRequest? _request;
|
LearnSubscriptionRequest? _request;
|
||||||
|
|
||||||
|
|
@ -49,7 +36,6 @@ class ArifPayViewModel extends ReactiveViewModel {
|
||||||
busyObject: StateObjects.learnSubscription);
|
busyObject: StateObjects.learnSubscription);
|
||||||
|
|
||||||
Future<void> _createLearnSubscriptionRequest(String phone) async {
|
Future<void> _createLearnSubscriptionRequest(String phone) async {
|
||||||
print('MY SUMMARIES : PAYMENT');
|
|
||||||
if (await _statusChecker.checkConnection()) {
|
if (await _statusChecker.checkConnection()) {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'plan_id': 1,
|
'plan_id': 1,
|
||||||
|
|
@ -67,23 +53,4 @@ class ArifPayViewModel extends ReactiveViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update payment status
|
|
||||||
Future<void> updatePaymentStatus() async => await runBusyFuture(_updatePaymentStatus(),
|
|
||||||
busyObject: StateObjects.learnSubscription);
|
|
||||||
|
|
||||||
Future<void> _updatePaymentStatus() async {
|
|
||||||
|
|
||||||
Map<String, dynamic> response = {};
|
|
||||||
|
|
||||||
response = await _apiService.getProfileData(_user?.userId);
|
|
||||||
|
|
||||||
if (response['status'] == ResponseStatus.success) {
|
|
||||||
User user = response['data'] as User;
|
|
||||||
await _authenticationService.saveUserData(user);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,38 +6,14 @@ import '../../common/app_colors.dart';
|
||||||
import '../../common/enmus.dart';
|
import '../../common/enmus.dart';
|
||||||
import '../../common/ui_helpers.dart';
|
import '../../common/ui_helpers.dart';
|
||||||
import '../../widgets/custom_circular_progress_indicator.dart';
|
import '../../widgets/custom_circular_progress_indicator.dart';
|
||||||
import '../../widgets/finish_practice_sheet.dart';
|
|
||||||
import '../../widgets/learn_course_tile.dart';
|
import '../../widgets/learn_course_tile.dart';
|
||||||
import '../../widgets/small_app_bar.dart';
|
import '../../widgets/small_app_bar.dart';
|
||||||
import 'learn_course_viewmodel.dart';
|
import 'learn_course_viewmodel.dart';
|
||||||
|
|
||||||
class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
||||||
final int id;
|
final int id;
|
||||||
|
|
||||||
const LearnCourseView({Key? key, required this.id}) : super(key: key);
|
const LearnCourseView({Key? key, required this.id}) : super(key: key);
|
||||||
|
|
||||||
|
|
||||||
Future<void> _onPractice({required BuildContext context,
|
|
||||||
required LearnCourse course,
|
|
||||||
required LearnCourseViewModel viewModel}) async {
|
|
||||||
if (course.access?.completedCount == course.access?.totalCount) {
|
|
||||||
await viewModel.navigateToLearnPractice(
|
|
||||||
id: course.id ?? 0,
|
|
||||||
level: course.name ?? '');
|
|
||||||
} else {
|
|
||||||
await _showSheet(context: context, viewModel: viewModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showSheet({required BuildContext context,
|
|
||||||
required LearnCourseViewModel viewModel}) async =>
|
|
||||||
await showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
backgroundColor: kcTransparent,
|
|
||||||
builder: (_) => _buildSheet(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(LearnCourseViewModel viewModel) async {
|
void onViewModelReady(LearnCourseViewModel viewModel) async {
|
||||||
await viewModel.getLearnCourses(id);
|
await viewModel.getLearnCourses(id);
|
||||||
|
|
@ -49,92 +25,74 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
||||||
LearnCourseViewModel();
|
LearnCourseViewModel();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget builder(BuildContext context,
|
Widget builder(
|
||||||
|
BuildContext context,
|
||||||
LearnCourseViewModel viewModel,
|
LearnCourseViewModel viewModel,
|
||||||
Widget? child,) =>
|
Widget? child,
|
||||||
_buildScaffoldWrapper(context: context,viewModel: viewModel);
|
) =>
|
||||||
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper({required BuildContext context,
|
Widget _buildScaffoldWrapper(LearnCourseViewModel viewModel) => Scaffold(
|
||||||
required LearnCourseViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldContainer(context: context,viewModel: viewModel),
|
body: _buildScaffoldContainer(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldContainer({required BuildContext context,
|
Widget _buildScaffoldContainer(LearnCourseViewModel viewModel) => Container(
|
||||||
required LearnCourseViewModel viewModel}) =>
|
|
||||||
Container(
|
|
||||||
decoration: bgDecoration,
|
decoration: bgDecoration,
|
||||||
child: _buildScaffold(context: context,viewModel: viewModel),
|
child: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold({required BuildContext context,
|
Widget _buildScaffold(LearnCourseViewModel viewModel) =>
|
||||||
required LearnCourseViewModel viewModel}) =>
|
SafeArea(child: _buildBody(viewModel));
|
||||||
SafeArea(child: _buildBody(context: context,viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildBody({required BuildContext context,
|
Widget _buildBody(LearnCourseViewModel viewModel) => Padding(
|
||||||
required LearnCourseViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildColumn(context: context,viewModel: viewModel),
|
child: _buildColumn(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildColumn({required BuildContext context,
|
Widget _buildColumn(LearnCourseViewModel viewModel) => Column(
|
||||||
required LearnCourseViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
children: [
|
children: [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAppBar(viewModel),
|
_buildAppBar(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildCoursesColumnWrapper(context: context,viewModel: viewModel)
|
_buildCoursesColumnWrapper(viewModel)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar(LearnCourseViewModel viewModel) =>
|
Widget _buildAppBar(LearnCourseViewModel viewModel) => SmallAppBar(
|
||||||
SmallAppBar(
|
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildCoursesColumnWrapper({required BuildContext context,
|
Widget _buildCoursesColumnWrapper(LearnCourseViewModel viewModel) =>
|
||||||
required LearnCourseViewModel viewModel}) =>
|
Expanded(child: _buildLevelsColumnScrollView(viewModel));
|
||||||
Expanded(child: _buildLevelsColumnScrollView(context: context,viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildLevelsColumnScrollView({required BuildContext context,
|
Widget _buildLevelsColumnScrollView(LearnCourseViewModel viewModel) =>
|
||||||
required LearnCourseViewModel viewModel}) =>
|
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildListViewBuilder(context: context,viewModel: viewModel),
|
child: _buildListViewBuilder(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildListViewBuilder({required BuildContext context,
|
Widget _buildListViewBuilder(LearnCourseViewModel viewModel) =>
|
||||||
required LearnCourseViewModel viewModel}) =>
|
|
||||||
viewModel.busy(StateObjects.learnCourses)
|
viewModel.busy(StateObjects.learnCourses)
|
||||||
? _buildProgressIndicator()
|
? _buildProgressIndicator()
|
||||||
: _buildListView(context: context,viewModel: viewModel);
|
: _buildListView(viewModel);
|
||||||
|
|
||||||
Widget _buildProgressIndicator() =>
|
Widget _buildProgressIndicator() => const Center(
|
||||||
const Center(
|
|
||||||
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
|
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildListView({required BuildContext context,
|
Widget _buildListView(LearnCourseViewModel viewModel) => ListView.separated(
|
||||||
required LearnCourseViewModel viewModel}) =>
|
|
||||||
ListView.separated(
|
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: viewModel.courses.length,
|
itemCount: viewModel.courses.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) =>
|
itemBuilder: (context, index) => _buildTile(
|
||||||
_buildTile(
|
|
||||||
course: viewModel.courses[index],
|
course: viewModel.courses[index],
|
||||||
|
|
||||||
onPracticeTap: () async =>
|
|
||||||
await _onPractice(
|
|
||||||
context: context,
|
|
||||||
viewModel: viewModel,
|
|
||||||
course: viewModel.courses[index]
|
|
||||||
),
|
|
||||||
onViewTap: () async =>
|
onViewTap: () async =>
|
||||||
await viewModel.navigateToLearnModule(viewModel.courses[index]),
|
await viewModel.navigateToLearnModule(viewModel.courses[index]),
|
||||||
|
onLockTap: () async => await viewModel.navigateToLearnSubscription(),
|
||||||
|
onPracticeTap: () async => await viewModel.navigateToLearnPractice(
|
||||||
|
id: viewModel.courses[index].id ?? 0,
|
||||||
|
level: viewModel.courses[index].name ?? ''),
|
||||||
),
|
),
|
||||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
separatorBuilder: (context, index) => verticalSpaceSmall,
|
||||||
);
|
);
|
||||||
|
|
@ -142,15 +100,13 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
||||||
Widget _buildTile({
|
Widget _buildTile({
|
||||||
required LearnCourse course,
|
required LearnCourse course,
|
||||||
required GestureTapCallback onViewTap,
|
required GestureTapCallback onViewTap,
|
||||||
|
required GestureTapCallback onLockTap,
|
||||||
required GestureTapCallback onPracticeTap,
|
required GestureTapCallback onPracticeTap,
|
||||||
}) =>
|
}) =>
|
||||||
LearnCourseTile(
|
LearnCourseTile(
|
||||||
course: course,
|
course: course,
|
||||||
onViewTap: onViewTap,
|
onViewTap: onViewTap,
|
||||||
|
onLockTap: onLockTap,
|
||||||
onPracticeTap: onPracticeTap,
|
onPracticeTap: onPracticeTap,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
Widget _buildSheet(LearnCourseViewModel viewModel) =>
|
|
||||||
FinishPracticeSheet(onTap: viewModel.pop);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,24 +20,6 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
|
|
||||||
const LearnLessonView({Key? key, required this.module}) : super(key: key);
|
const LearnLessonView({Key? key, required this.module}) : super(key: key);
|
||||||
|
|
||||||
Future<void> _onPractice(
|
|
||||||
{required int index,
|
|
||||||
required LearnLesson lesson,
|
|
||||||
required LearnLessonViewModel viewModel}) async {
|
|
||||||
if (index > 1) {
|
|
||||||
|
|
||||||
print(index);
|
|
||||||
print(viewModel.user?.subscriptionStatus);
|
|
||||||
if (viewModel.user?.subscriptionStatus?.toLowerCase() == 'subscribed') {
|
|
||||||
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
|
||||||
} else {
|
|
||||||
await viewModel.navigateToLearnSubscription();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await viewModel.navigateToLearnPractice(lesson.id ?? 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(LearnLessonViewModel viewModel) async {
|
void onViewModelReady(LearnLessonViewModel viewModel) async {
|
||||||
await viewModel.getLessons(module.id ?? 0);
|
await viewModel.getLessons(module.id ?? 0);
|
||||||
|
|
@ -142,7 +124,7 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
verticalSpaceTiny,
|
verticalSpaceTiny,
|
||||||
_buildSubtitle(),
|
_buildSubtitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildModuleProgress(viewModel),
|
_buildModuleProgress(),
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildMotivationCard(),
|
_buildMotivationCard(),
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
|
|
@ -161,19 +143,10 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
style: style14DG500,
|
style: style14DG500,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildModuleProgress(LearnLessonViewModel viewModel) => ModuleProgress(
|
Widget _buildModuleProgress() => ModuleProgress(
|
||||||
total: (viewModel.getUpdatedLearnModule(module.id ?? 0) ?? module)
|
total: module.access?.totalCount ?? 0,
|
||||||
.access
|
completed: module.access?.completedCount ?? 0,
|
||||||
?.totalCount ??
|
progress: module.access?.progressPercent ?? 0,
|
||||||
0,
|
|
||||||
completed: (viewModel.getUpdatedLearnModule(module.id ?? 0) ?? module)
|
|
||||||
.access
|
|
||||||
?.completedCount ??
|
|
||||||
0,
|
|
||||||
progress: (viewModel.getUpdatedLearnModule(module.id ?? 0) ?? module)
|
|
||||||
.access
|
|
||||||
?.progressPercent ??
|
|
||||||
0,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildMotivationCard() => const MotivationCard();
|
Widget _buildMotivationCard() => const MotivationCard();
|
||||||
|
|
@ -199,16 +172,13 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
||||||
itemBuilder: (context, index) => _buildTile(
|
itemBuilder: (context, index) => _buildTile(
|
||||||
index: index,
|
index: index,
|
||||||
lesson: viewModel.lessons[index],
|
lesson: viewModel.lessons[index],
|
||||||
onPracticeTap: () async => await _onPractice(
|
|
||||||
index: index,
|
|
||||||
viewModel: viewModel,
|
|
||||||
lesson: viewModel.lessons[index],
|
|
||||||
),
|
|
||||||
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(
|
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(
|
||||||
module: module,
|
module: module,
|
||||||
lesson: viewModel.lessons[index],
|
lesson: viewModel.lessons[index],
|
||||||
hasPractice:
|
hasPractice:
|
||||||
index != viewModel.lessons.length - 1 ? true : false),
|
index != viewModel.lessons.length - 1 ? true : false),
|
||||||
|
onPracticeTap: () async => await viewModel
|
||||||
|
.navigateToLearnPractice(viewModel.lessons[index].id ?? 0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,6 @@ import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../models/learn_module.dart';
|
import '../../../models/learn_module.dart';
|
||||||
import '../../../models/user.dart';
|
|
||||||
import '../../../services/authentication_service.dart';
|
|
||||||
import '../../../services/learn_service.dart';
|
import '../../../services/learn_service.dart';
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
import '../../common/helper_functions.dart';
|
import '../../common/helper_functions.dart';
|
||||||
|
|
@ -22,19 +20,8 @@ class LearnLessonViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<ListenableServiceMixin> get listenableServices => [_learnService,_authenticationService];
|
List<ListenableServiceMixin> get listenableServices => [_learnService];
|
||||||
|
|
||||||
|
|
||||||
// Current user
|
|
||||||
User? get _user => _authenticationService.user;
|
|
||||||
|
|
||||||
User? get user => _user;
|
|
||||||
|
|
||||||
// Learn lessons
|
// Learn lessons
|
||||||
|
|
||||||
|
|
@ -49,8 +36,6 @@ class LearnLessonViewModel extends ReactiveViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice(int id) async =>
|
Future<void> navigateToLearnPractice(int id) async =>
|
||||||
await _navigationService.navigateToLearnPracticeView(
|
await _navigationService.navigateToLearnPracticeView(
|
||||||
id: id,
|
id: id,
|
||||||
|
|
@ -60,10 +45,6 @@ class LearnLessonViewModel extends ReactiveViewModel {
|
||||||
subtitle: LocaleKeys.ask_you_few_actions.tr(),
|
subtitle: LocaleKeys.ask_you_few_actions.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
Future<void> navigateToLearnSubscription() async =>
|
|
||||||
await _navigationService.navigateToLearnSubscriptionView();
|
|
||||||
|
|
||||||
Future<void> navigateToLearnLessonDetail(
|
Future<void> navigateToLearnLessonDetail(
|
||||||
{required bool hasPractice,
|
{required bool hasPractice,
|
||||||
required LearnLesson lesson,
|
required LearnLesson lesson,
|
||||||
|
|
@ -84,10 +65,6 @@ class LearnLessonViewModel extends ReactiveViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get module
|
|
||||||
LearnModule? getUpdatedLearnModule(int id) {
|
|
||||||
return _learnService.getLearnModuleById(id);
|
|
||||||
}
|
|
||||||
//Refresh image
|
//Refresh image
|
||||||
Future<void> refreshLessonImages(List<LearnLesson> lessons) async {
|
Future<void> refreshLessonImages(List<LearnLesson> lessons) async {
|
||||||
for (final lesson in lessons) {
|
for (final lesson in lessons) {
|
||||||
|
|
|
||||||
|
|
@ -11,35 +11,14 @@ import '../../common/app_colors.dart';
|
||||||
import '../../common/enmus.dart';
|
import '../../common/enmus.dart';
|
||||||
import '../../common/ui_helpers.dart';
|
import '../../common/ui_helpers.dart';
|
||||||
import '../../widgets/custom_circular_progress_indicator.dart';
|
import '../../widgets/custom_circular_progress_indicator.dart';
|
||||||
import '../../widgets/finish_practice_sheet.dart';
|
|
||||||
import '../../widgets/small_app_bar.dart';
|
import '../../widgets/small_app_bar.dart';
|
||||||
import 'learn_module_viewmodel.dart';
|
import 'learn_module_viewmodel.dart';
|
||||||
|
|
||||||
class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
final LearnCourse course;
|
final LearnCourse course;
|
||||||
|
|
||||||
const LearnModuleView({Key? key, required this.course}) : super(key: key);
|
const LearnModuleView({Key? key, required this.course}) : super(key: key);
|
||||||
|
|
||||||
Future<void> _onPractice(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModule module,
|
|
||||||
required LearnModuleViewModel viewModel}) async {
|
|
||||||
if (module.access?.completedCount == module.access?.totalCount) {
|
|
||||||
await viewModel.navigateToLearnPractice(
|
|
||||||
id: module.id ?? 0, module: module.name ?? '');
|
|
||||||
} else {
|
|
||||||
await _showSheet(context: context, viewModel: viewModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _showSheet(
|
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) async =>
|
|
||||||
await showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
backgroundColor: kcTransparent,
|
|
||||||
builder: (_) => _buildSheet(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(LearnModuleViewModel viewModel) async {
|
void onViewModelReady(LearnModuleViewModel viewModel) async {
|
||||||
await viewModel.getLearnModules(course.id ?? 0);
|
await viewModel.getLearnModules(course.id ?? 0);
|
||||||
|
|
@ -56,46 +35,32 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
LearnModuleViewModel viewModel,
|
LearnModuleViewModel viewModel,
|
||||||
Widget? child,
|
Widget? child,
|
||||||
) =>
|
) =>
|
||||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(
|
Widget _buildScaffoldWrapper(LearnModuleViewModel viewModel) => Scaffold(
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldContainer(context: context, viewModel: viewModel),
|
body: _buildScaffoldContainer(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldContainer(
|
Widget _buildScaffoldContainer(LearnModuleViewModel viewModel) => Container(
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
Container(
|
|
||||||
decoration: bgDecoration,
|
decoration: bgDecoration,
|
||||||
child: _buildScaffold(context: context, viewModel: viewModel),
|
child: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(
|
Widget _buildScaffold(LearnModuleViewModel viewModel) =>
|
||||||
{required BuildContext context,
|
SafeArea(child: _buildBody(viewModel));
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
SafeArea(child: _buildBody(context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildBody(
|
Widget _buildBody(LearnModuleViewModel viewModel) => Padding(
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildColumn(context: context, viewModel: viewModel),
|
child: _buildColumn(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildColumn(
|
Widget _buildColumn(LearnModuleViewModel viewModel) => Column(
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
children: [
|
children: [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAppBar(viewModel),
|
_buildAppBar(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildModulesColumnWrapper(context: context, viewModel: viewModel),
|
_buildModulesColumnWrapper(viewModel),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -104,41 +69,28 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildModulesColumnWrapper(
|
Widget _buildModulesColumnWrapper(LearnModuleViewModel viewModel) =>
|
||||||
{required BuildContext context,
|
Expanded(child: _buildLevelsColumnScrollView(viewModel));
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
Expanded(
|
|
||||||
child: _buildLevelsColumnScrollView(
|
|
||||||
context: context, viewModel: viewModel));
|
|
||||||
|
|
||||||
Widget _buildLevelsColumnScrollView(
|
Widget _buildLevelsColumnScrollView(LearnModuleViewModel viewModel) =>
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildLevelsColumn(context: context, viewModel: viewModel),
|
child: _buildLevelsColumn(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLevelsColumn(
|
Widget _buildLevelsColumn(LearnModuleViewModel viewModel) => Column(
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children:
|
children: _buildLevelsColumnChildren(viewModel),
|
||||||
_buildLevelsColumnChildren(context: context, viewModel: viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildLevelsColumnChildren(
|
List<Widget> _buildLevelsColumnChildren(LearnModuleViewModel viewModel) => [
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
[
|
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
_buildSubtitle(),
|
_buildSubtitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildOverallProgress(viewModel),
|
_buildOverallProgress(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildListViewBuilder(context: context, viewModel: viewModel)
|
_buildListViewBuilder(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
|
|
@ -151,38 +103,30 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
style: style14P400,
|
style: style14P400,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildOverallProgress(LearnModuleViewModel viewModel) => OverallProgress(
|
Widget _buildOverallProgress() => OverallProgress(
|
||||||
indicatorBackgroundColor: kcWhite,
|
indicatorBackgroundColor: kcWhite,
|
||||||
|
progress: course.access?.progressPercent ?? 0,
|
||||||
backgroundColor: kcPrimaryColor.withOpacity(0.1),
|
backgroundColor: kcPrimaryColor.withOpacity(0.1),
|
||||||
progress:
|
|
||||||
(viewModel.getUpdatedLearnCourse(course.id ?? 0) ?? course).access?.progressPercent ?? 0,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildListViewBuilder(
|
Widget _buildListViewBuilder(LearnModuleViewModel viewModel) =>
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
viewModel.busy(StateObjects.learnModules)
|
viewModel.busy(StateObjects.learnModules)
|
||||||
? _buildProgressIndicator()
|
? _buildProgressIndicator()
|
||||||
: _buildListView(context: context, viewModel: viewModel);
|
: _buildListView(viewModel);
|
||||||
|
|
||||||
Widget _buildProgressIndicator() => const Center(
|
Widget _buildProgressIndicator() => const Center(
|
||||||
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
|
child: CustomCircularProgressIndicator(color: kcPrimaryColor),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildListView(
|
Widget _buildListView(LearnModuleViewModel viewModel) => ListView.builder(
|
||||||
{required BuildContext context,
|
|
||||||
required LearnModuleViewModel viewModel}) =>
|
|
||||||
ListView.builder(
|
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: viewModel.modules.length,
|
itemCount: viewModel.modules.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildTile(
|
itemBuilder: (context, index) => _buildTile(
|
||||||
module: viewModel.modules[index],
|
module: viewModel.modules[index],
|
||||||
onPracticeTap: () async => await _onPractice(
|
onPracticeTap: () async => await viewModel.navigateToLearnPractice(
|
||||||
context: context,
|
id: viewModel.modules[index].id ?? 0,
|
||||||
viewModel: viewModel,
|
module: viewModel.modules[index].name ?? ''),
|
||||||
module: viewModel.modules[index],
|
|
||||||
),
|
|
||||||
onModuleTap: () async =>
|
onModuleTap: () async =>
|
||||||
await viewModel.navigateToLearnLesson(viewModel.modules[index]),
|
await viewModel.navigateToLearnLesson(viewModel.modules[index]),
|
||||||
),
|
),
|
||||||
|
|
@ -197,7 +141,4 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
||||||
module: module,
|
module: module,
|
||||||
onModuleTap: onModuleTap,
|
onModuleTap: onModuleTap,
|
||||||
onPracticeTap: onPracticeTap);
|
onPracticeTap: onPracticeTap);
|
||||||
|
|
||||||
Widget _buildSheet(LearnModuleViewModel viewModel) =>
|
|
||||||
FinishPracticeSheet(onTap: viewModel.pop);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import 'package:yimaru_app/models/learn_module.dart';
|
||||||
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../models/learn_course.dart';
|
|
||||||
import '../../../services/learn_service.dart';
|
import '../../../services/learn_service.dart';
|
||||||
import '../../../services/status_checker_service.dart';
|
import '../../../services/status_checker_service.dart';
|
||||||
import '../../common/enmus.dart';
|
import '../../common/enmus.dart';
|
||||||
|
|
@ -62,11 +61,6 @@ class LearnModuleViewModel extends ReactiveViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get course
|
|
||||||
LearnCourse? getUpdatedLearnCourse(int id) {
|
|
||||||
return _learnService.getLearnCourseById(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Refresh image
|
//Refresh image
|
||||||
Future<void> refreshModuleImages(List<LearnModule> modules) async {
|
Future<void> refreshModuleImages(List<LearnModule> modules) async {
|
||||||
for (final module in modules) {
|
for (final module in modules) {
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
// Learn practices
|
// Learn practices
|
||||||
|
|
||||||
|
|
||||||
List<LearnPractice> _practices = [];
|
List<LearnPractice> _practices = [];
|
||||||
|
|
||||||
List<LearnPractice> get practices => _practices;
|
List<LearnPractice> get practices => _practices;
|
||||||
|
|
@ -250,6 +251,7 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
);
|
);
|
||||||
await playVoicePrompt(_questions[index]);
|
await playVoicePrompt(_questions[index]);
|
||||||
} else {
|
} else {
|
||||||
|
await completeLearnPractices();
|
||||||
goTo(3);
|
goTo(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -329,4 +331,5 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
String getPracticeImage(LearnPractice practice) =>
|
String getPracticeImage(LearnPractice practice) =>
|
||||||
getReadableUrl(_refreshedImages[practice.id] ?? '') ?? '';
|
getReadableUrl(_refreshedImages[practice.id] ?? '') ?? '';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,6 @@ class InteractLearnPracticeScreen
|
||||||
Widget _buildSpeakingIndicator(LearnPracticeViewModel viewModel) =>
|
Widget _buildSpeakingIndicator(LearnPracticeViewModel viewModel) =>
|
||||||
WaveWrapper(height: 200, child: _buildSpinnerState(viewModel));
|
WaveWrapper(height: 200, child: _buildSpinnerState(viewModel));
|
||||||
|
|
||||||
|
|
||||||
Widget _buildSpinnerState(LearnPracticeViewModel viewModel) =>
|
Widget _buildSpinnerState(LearnPracticeViewModel viewModel) =>
|
||||||
viewModel.busy(StateObjects.recordLearnPracticeAnswer) ||
|
viewModel.busy(StateObjects.recordLearnPracticeAnswer) ||
|
||||||
viewModel.busy(StateObjects.finishLearnPracticeQuestion)
|
viewModel.busy(StateObjects.finishLearnPracticeQuestion)
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
const LearningGoalFormScreen({super.key});
|
const LearningGoalFormScreen({super.key});
|
||||||
|
|
||||||
IconData getIcon(int index) {
|
IconData getIcon(int icon) {
|
||||||
switch (index) {
|
switch (icon) {
|
||||||
case 0:
|
case 0:
|
||||||
return Iconsax.book;
|
return Iconsax.book;
|
||||||
case 1:
|
case 1:
|
||||||
|
|
@ -25,31 +25,6 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
return Icons.book;
|
return Icons.book;
|
||||||
}
|
}
|
||||||
|
|
||||||
String getTitles(int index) {
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
return 'Learn to Speak English';
|
|
||||||
case 1:
|
|
||||||
return 'Practice Speaking English';
|
|
||||||
case 2:
|
|
||||||
return 'Skill-based Courses';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
String getSubtitle(int index) {
|
|
||||||
switch (index) {
|
|
||||||
case 0:
|
|
||||||
return 'I know some English, but i want to learn to speak it';
|
|
||||||
case 1:
|
|
||||||
return 'I already speak English, but I want more practice.';
|
|
||||||
case 2:
|
|
||||||
return 'I want courses for IELTS, TOEFL, Duolingo, or work';
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void _pop(OnboardingViewModel viewModel) {
|
void _pop(OnboardingViewModel viewModel) {
|
||||||
viewModel.resetLearningGoalFormScreen();
|
viewModel.resetLearningGoalFormScreen();
|
||||||
viewModel.goBack();
|
viewModel.goBack();
|
||||||
|
|
@ -70,20 +45,17 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) =>
|
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
||||||
Scaffold(
|
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) =>
|
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [
|
||||||
[
|
|
||||||
_buildAppBar(viewModel),
|
_buildAppBar(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildExpandedBody(viewModel)
|
_buildExpandedBody(viewModel)
|
||||||
|
|
@ -97,14 +69,12 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
child: _buildBodyWrapper(viewModel),
|
child: _buildBodyWrapper(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) =>
|
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) =>
|
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(viewModel),
|
children: _buildBodyChildren(viewModel),
|
||||||
|
|
@ -113,23 +83,20 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
||||||
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
||||||
|
|
||||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) =>
|
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
||||||
Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
||||||
[
|
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(viewModel),
|
_buildTitle(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildLearningGoals(viewModel)
|
_buildLearningGoals(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) =>
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
LargeAppBar(
|
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onPop: () => _pop(viewModel),
|
onPop: () => _pop(viewModel),
|
||||||
|
|
@ -139,8 +106,7 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
: viewModel.selectedLanguage['code'],
|
: viewModel.selectedLanguage['code'],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle(OnboardingViewModel viewModel) =>
|
Widget _buildTitle(OnboardingViewModel viewModel) => Text.rich(
|
||||||
Text.rich(
|
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text:
|
text:
|
||||||
'${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},',
|
'${LocaleKeys.hello.tr()} ${viewModel.userData['first_name']},',
|
||||||
|
|
@ -153,39 +119,30 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
]),
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLearningGoals(OnboardingViewModel viewModel) =>
|
Widget _buildLearningGoals(OnboardingViewModel viewModel) => ListView.builder(
|
||||||
ListView.builder(
|
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: 3,// viewModel.learningGoals.length,
|
itemCount: viewModel.learningGoals.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) =>
|
itemBuilder: (context, index) => _buildLearningGoal(
|
||||||
_buildLearningGoal(
|
title: viewModel.learningGoals[index].label ?? '',
|
||||||
icon: getIcon(index),
|
|
||||||
title: getTitles(index),
|
|
||||||
subtitle: getSubtitle(index),
|
|
||||||
selected:
|
selected:
|
||||||
viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]),
|
viewModel.isSelectedLearningGoal(viewModel.learningGoals[index]),
|
||||||
onTap: () =>
|
onTap: () =>
|
||||||
viewModel.setSelectedLearningGoal(
|
viewModel.setSelectedLearningGoal(viewModel.learningGoals[index]),
|
||||||
viewModel.learningGoals[index]),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLearningGoal({required String title,
|
Widget _buildLearningGoal(
|
||||||
|
{required String title,
|
||||||
required bool selected,
|
required bool selected,
|
||||||
required IconData icon,
|
|
||||||
required String subtitle,
|
|
||||||
required GestureTapCallback onTap}) =>
|
required GestureTapCallback onTap}) =>
|
||||||
CustomLargeRadioButton(
|
CustomLargeRadioButton(
|
||||||
icon:icon,
|
|
||||||
title: title,
|
title: title,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
subtitle: subtitle,
|
|
||||||
selected: selected,
|
selected: selected,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,20 @@ import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
class CustomLargeRadioButton extends StatelessWidget {
|
class CustomLargeRadioButton extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final bool selected;
|
final bool selected;
|
||||||
final IconData icon;
|
|
||||||
final String subtitle;
|
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback? onTap;
|
||||||
|
|
||||||
const CustomLargeRadioButton(
|
const CustomLargeRadioButton({
|
||||||
{super.key,
|
super.key,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.icon,
|
|
||||||
required this.selected,
|
required this.selected,
|
||||||
required this.subtitle});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => _buildButtonWrapper();
|
Widget build(BuildContext context) => _buildButtonWrapper();
|
||||||
|
|
||||||
Widget _buildButtonWrapper() => Container(
|
Widget _buildButtonWrapper() => Container(
|
||||||
height: 125,
|
height: 75,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: _buildContainerWrapper(),
|
child: _buildContainerWrapper(),
|
||||||
|
|
@ -41,39 +38,24 @@ class CustomLargeRadioButton extends StatelessWidget {
|
||||||
color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75),
|
color: selected ? kcPrimaryColor : kcPrimaryColor.withOpacity(0.75),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: _buildButtonColumnWrapper(),
|
child: _buildButtonRowWrapper(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonColumnWrapper() => Column(
|
Widget _buildButtonRowWrapper() => Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: _buildButtonRowChildren(),
|
children: _buildButtonRowChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildButtonRowChildren() =>
|
List<Widget> _buildButtonRowChildren() =>
|
||||||
[_buildIconSectionWrapper(), _buildTitle(), _buildSubtitle()];
|
[_buildTitleWrapper(), _buildSelectedCheckBox()];
|
||||||
|
|
||||||
Widget _buildIconSectionWrapper() => Row(
|
Widget _buildTitleWrapper() => Expanded(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
child: _buildTitle(),
|
||||||
children: _buildIconSectionChildren(),
|
|
||||||
);
|
|
||||||
|
|
||||||
List<Widget> _buildIconSectionChildren() =>
|
|
||||||
[_buildLeadingIcon(), _buildSelectedCheckBox()];
|
|
||||||
|
|
||||||
Widget _buildLeadingIcon() => Icon(
|
|
||||||
icon,
|
|
||||||
size: 25,
|
|
||||||
color: kcPrimaryColor,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
title,
|
title,
|
||||||
style: style18DG700,
|
maxLines: 1,
|
||||||
);
|
style: style16DG400,
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
|
||||||
subtitle,
|
|
||||||
style: const TextStyle(color: kcMediumGrey),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSelectedCheckBox() => Checkbox(
|
Widget _buildSelectedCheckBox() => Checkbox(
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart';
|
import 'package:yimaru_app/ui/widgets/custom_bottom_sheet.dart';
|
||||||
|
|
||||||
|
|
@ -10,7 +8,6 @@ import 'custom_elevated_button.dart';
|
||||||
|
|
||||||
class FinishPracticeSheet extends StatelessWidget {
|
class FinishPracticeSheet extends StatelessWidget {
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback? onTap;
|
||||||
|
|
||||||
const FinishPracticeSheet({super.key, this.onTap});
|
const FinishPracticeSheet({super.key, this.onTap});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -23,7 +20,6 @@ class FinishPracticeSheet extends StatelessWidget {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildColumn(),
|
child: _buildColumn(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildColumn() => Column(
|
Widget _buildColumn() => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: _buildSheetChildren(),
|
children: _buildSheetChildren(),
|
||||||
|
|
@ -44,7 +40,7 @@ class FinishPracticeSheet extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildMessage() => Text(
|
Widget _buildMessage() => Text(
|
||||||
LocaleKeys.finish_all_practice.tr(),
|
'Finish all the practices in the lessons to take this practice',
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -52,9 +48,9 @@ class FinishPracticeSheet extends StatelessWidget {
|
||||||
Widget _buildContinueButton() => CustomElevatedButton(
|
Widget _buildContinueButton() => CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
text: LocaleKeys.cont.tr(),
|
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,20 +13,26 @@ import 'custom_elevated_button.dart';
|
||||||
class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
||||||
final LearnCourse course;
|
final LearnCourse course;
|
||||||
final GestureTapCallback? onViewTap;
|
final GestureTapCallback? onViewTap;
|
||||||
|
final GestureTapCallback? onLockTap;
|
||||||
final GestureTapCallback? onPracticeTap;
|
final GestureTapCallback? onPracticeTap;
|
||||||
|
|
||||||
const LearnCourseTile({
|
const LearnCourseTile({
|
||||||
super.key,
|
super.key,
|
||||||
this.onViewTap,
|
this.onViewTap,
|
||||||
|
this.onLockTap,
|
||||||
this.onPracticeTap,
|
this.onPracticeTap,
|
||||||
required this.course,
|
required this.course,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnCourseViewModel viewModel) =>
|
Widget build(BuildContext context, LearnCourseViewModel viewModel) =>
|
||||||
_buildExpansionTileCard(viewModel);
|
_buildExpansionTileCardWrapper(viewModel);
|
||||||
|
|
||||||
|
|
||||||
|
Widget _buildExpansionTileCardWrapper(LearnCourseViewModel viewModel) =>
|
||||||
|
GestureDetector(
|
||||||
|
onTap: !(course.access?.isAccessible ?? false) ? onLockTap : null,
|
||||||
|
child: _buildExpansionTileCard(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container(
|
Widget _buildExpansionTileCard(LearnCourseViewModel viewModel) => Container(
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,6 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||||
required this.index,
|
required this.index,
|
||||||
required this.lesson});
|
required this.lesson});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnLessonViewModel viewModel) =>
|
Widget build(BuildContext context, LearnLessonViewModel viewModel) =>
|
||||||
_buildContainer(viewModel);
|
_buildContainer(viewModel);
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,14 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
const LearnModuleTile(
|
const LearnModuleTile(
|
||||||
{super.key, this.onModuleTap, this.onPracticeTap, required this.module});
|
{super.key, this.onModuleTap, this.onPracticeTap, required this.module});
|
||||||
|
|
||||||
|
Future<void> _showSheet(
|
||||||
|
{required BuildContext context,
|
||||||
|
required LearnModuleViewModel viewModel}) async =>
|
||||||
|
await showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
backgroundColor: kcTransparent,
|
||||||
|
builder: (_) => _buildSheet(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnModuleViewModel viewModel) =>
|
Widget build(BuildContext context, LearnModuleViewModel viewModel) =>
|
||||||
|
|
@ -214,7 +221,9 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
text: LocaleKeys.take_practice.tr(),
|
text: LocaleKeys.take_practice.tr(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Widget _buildSheet(LearnModuleViewModel viewModel) => FinishPracticeSheet(
|
||||||
|
onTap: viewModel.pop,
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildContainerShaderState() => !(module.access?.isAccessible ?? false)
|
Widget _buildContainerShaderState() => !(module.access?.isAccessible ?? false)
|
||||||
? _buildContainerShader()
|
? _buildContainerShader()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:yimaru_app/ui/common/translations/locale_keys.g.dart';
|
|
||||||
|
|
||||||
import '../common/app_colors.dart';
|
import '../common/app_colors.dart';
|
||||||
import '../common/ui_helpers.dart';
|
import '../common/ui_helpers.dart';
|
||||||
|
|
@ -50,8 +48,8 @@ class OverallProgressWrapper extends StatelessWidget {
|
||||||
backgroundColor: kcVeryLightGrey,
|
backgroundColor: kcVeryLightGrey,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => const Text(
|
||||||
LocaleKeys.keep_up_the_great_work.tr(),
|
'Keep up the great work! You\'re doing amazing.',
|
||||||
style:style14DG400 ,
|
style: TextStyle(color: kcDarkGrey),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
name: yimaru_app
|
name: yimaru_app
|
||||||
version: 0.1.26+28
|
version: 0.1.25+27
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user