- fix(auth): Fix how user data in fetched from both local and remote
storage. - feat(learn): Complete all learn module UI
This commit is contained in:
parent
1c8b54fe69
commit
d75ed8c7c7
|
|
@ -412,8 +412,13 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i28.LearnPracticeView: (data) {
|
_i28.LearnPracticeView: (data) {
|
||||||
|
final args = data.getArgs<LearnPracticeViewArguments>(nullOk: false);
|
||||||
return _i29.MaterialPageRoute<dynamic>(
|
return _i29.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,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -507,6 +512,45 @@ class FailureViewArguments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LearnPracticeViewArguments {
|
||||||
|
const LearnPracticeViewArguments({
|
||||||
|
this.key,
|
||||||
|
required this.title,
|
||||||
|
required this.subtitle,
|
||||||
|
required this.buttonLabel,
|
||||||
|
});
|
||||||
|
|
||||||
|
final _i29.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 _i30.NavigationService {
|
extension NavigatorStateExtension on _i30.NavigationService {
|
||||||
Future<dynamic> navigateToHomeView([
|
Future<dynamic> navigateToHomeView([
|
||||||
int? routerId,
|
int? routerId,
|
||||||
|
|
@ -881,14 +925,23 @@ extension NavigatorStateExtension on _i30.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToLearnPracticeView([
|
Future<dynamic> navigateToLearnPracticeView({
|
||||||
|
_i29.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,
|
id: routerId,
|
||||||
preventDuplicates: preventDuplicates,
|
preventDuplicates: preventDuplicates,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
|
|
@ -1268,14 +1321,23 @@ extension NavigatorStateExtension on _i30.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithLearnPracticeView([
|
Future<dynamic> replaceWithLearnPracticeView({
|
||||||
|
_i29.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,
|
id: routerId,
|
||||||
preventDuplicates: preventDuplicates,
|
preventDuplicates: preventDuplicates,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,10 @@ 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;
|
||||||
|
|
||||||
|
|
@ -55,7 +53,7 @@ class UserModel {
|
||||||
this.accessToken,
|
this.accessToken,
|
||||||
this.refreshToken,
|
this.refreshToken,
|
||||||
this.profilePicture,
|
this.profilePicture,
|
||||||
this.userInfoLoaded ,
|
this.userInfoLoaded,
|
||||||
this.profileCompleted,
|
this.profileCompleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>{
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ class ApiService {
|
||||||
final _service = locator<DioService>();
|
final _service = locator<DioService>();
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
Future<Map<String, dynamic>> registerWithEmail(Map<String, dynamic> data) async {
|
Future<Map<String, dynamic>> registerWithEmail(
|
||||||
|
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',
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
await _secureService.setString('refreshToken', refresh);
|
await _secureService.setString('refreshToken', refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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']);
|
||||||
|
|
@ -71,8 +70,8 @@ class AuthenticationService with ListenableServiceMixin {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveProfileImage(String image) async {
|
Future<void> saveProfilePicture(String image) async {
|
||||||
await _secureService.setString('profileImage', image);
|
await _secureService.setString('profilePicture', image);
|
||||||
_user = UserModel(
|
_user = UserModel(
|
||||||
email: _user?.email,
|
email: _user?.email,
|
||||||
gender: _user?.gender,
|
gender: _user?.gender,
|
||||||
|
|
@ -87,7 +86,7 @@ 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('profileImage'),
|
profilePicture: await _secureService.getString('profilePicture'),
|
||||||
);
|
);
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
@ -175,8 +174,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;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ 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);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ enum ProficiencyLevels { a1, a2, b1, b2, none }
|
||||||
|
|
||||||
// State object
|
// State object
|
||||||
enum StateObjects {
|
enum StateObjects {
|
||||||
|
homeView,
|
||||||
verifyOtp,
|
verifyOtp,
|
||||||
resendOtp,
|
resendOtp,
|
||||||
profileImage,
|
profileImage,
|
||||||
|
|
|
||||||
|
|
@ -178,6 +178,12 @@ 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,
|
||||||
|
|
@ -190,6 +196,12 @@ 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,
|
||||||
|
|
@ -197,10 +209,19 @@ 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,
|
||||||
|
|
@ -224,6 +245,12 @@ TextStyle style16DG600 = const TextStyle(
|
||||||
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,
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,9 @@ class AccountPrivacyView extends StackedView<AccountPrivacyViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(AccountPrivacyViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(AccountPrivacyViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Account Privacy',
|
showBackButton: true,
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
|
title: 'Account Privacy',
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(AccountPrivacyViewModel viewModel) =>
|
Widget _buildContentWrapper(AccountPrivacyViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ class AssessmentViewModel extends BaseViewModel {
|
||||||
await _navigationService.navigateToLanguageView();
|
await _navigationService.navigateToLanguageView();
|
||||||
|
|
||||||
Future<void> replaceWithHome() async =>
|
Future<void> replaceWithHome() async =>
|
||||||
await _navigationService.clearStackAndShowView(const HomeView());
|
await _navigationService.clearStackAndShow(Routes.homeView);
|
||||||
|
|
||||||
// Remote api call
|
// Remote api call
|
||||||
Future<void> getAssessments() async => await runBusyFuture(_getAssessments());
|
Future<void> getAssessments() async => await runBusyFuture(_getAssessments());
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,9 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(CallSupportViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(CallSupportViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Call Support',
|
showBackButton: true,
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
|
title: 'Call Support',
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedColumn(CallSupportViewModel viewModel) =>
|
Widget _buildExpandedColumn(CallSupportViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,9 @@ class DownloadsView extends StackedView<DownloadsViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppbar(DownloadsViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(DownloadsViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Offline Downloads',
|
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
|
showBackButton: true,
|
||||||
|
title: 'Offline Downloads',
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(DownloadsViewModel viewModel) =>
|
Widget _buildContentWrapper(DownloadsViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,6 @@ 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();
|
||||||
|
|
@ -77,10 +75,6 @@ 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());
|
||||||
|
|
||||||
|
|
@ -96,6 +90,4 @@ class ForgetPasswordView extends StackedView<ForgetPasswordViewModel>
|
||||||
passwordController: passwordController,
|
passwordController: passwordController,
|
||||||
resetCodeController: resetCodeController,
|
resetCodeController: resetCodeController,
|
||||||
confirmPasswordController: confirmPasswordController);
|
confirmPasswordController: confirmPasswordController);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ 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';
|
||||||
|
|
@ -190,7 +191,7 @@ class ForgetPasswordViewModel extends FormViewModel {
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> replaceWithLogin() async =>
|
Future<void> replaceWithLogin() async =>
|
||||||
await _navigationService.clearStackAndShowView(const LoginView());
|
await _navigationService.clearStackAndShow(Routes.loginView);
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,11 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
required this.emailController,
|
required this.emailController,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Widget getPadding(context) {
|
||||||
Widget getPadding(context){
|
double half = screenHeight(context) / 2;
|
||||||
double half = screenHeight(context)/2;
|
return SizedBox(
|
||||||
return SizedBox(height: half + 375 - half,);
|
height: half + 375 - half,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _inAppPop(ForgetPasswordViewModel viewModel) {
|
void _inAppPop(ForgetPasswordViewModel viewModel) {
|
||||||
|
|
@ -34,7 +35,6 @@ 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,34 +48,44 @@ 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( {required BuildContext context,
|
Widget _buildScaffoldWrapper(
|
||||||
required ForgetPasswordViewModel viewModel}) => Scaffold(
|
{required BuildContext context,
|
||||||
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
|
Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldStack( {required BuildContext context,
|
Widget _buildScaffoldStack(
|
||||||
required ForgetPasswordViewModel viewModel}) => Stack(
|
{required BuildContext context,
|
||||||
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
_buildScaffold(context: context,viewModel: viewModel),
|
_buildScaffold(context: context, viewModel: viewModel),
|
||||||
_buildRequestResetCodeState(viewModel),
|
_buildRequestResetCodeState(viewModel),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold( {required BuildContext context,
|
Widget _buildScaffold(
|
||||||
required ForgetPasswordViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(context: context, viewModel: viewModel),
|
children:
|
||||||
|
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren( {required BuildContext context,
|
List<Widget> _buildScaffoldChildren(
|
||||||
|
{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,
|
||||||
|
|
@ -83,34 +93,44 @@ class RequestCodeScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
||||||
onPop: () => _inAppPop(viewModel),
|
onPop: () => _inAppPop(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody( {required BuildContext context,
|
Widget _buildExpandedBody(
|
||||||
|
{required BuildContext context,
|
||||||
required ForgetPasswordViewModel viewModel}) =>
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
Expanded(child: _buildColumnScroller(context: context, viewModel: viewModel));
|
Expanded(
|
||||||
|
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
Widget _buildColumnScroller( {required BuildContext context,
|
Widget _buildColumnScroller(
|
||||||
|
{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( {required BuildContext context,
|
Widget _buildBodyWrapper(
|
||||||
required ForgetPasswordViewModel viewModel}) => Padding(
|
{required BuildContext context,
|
||||||
|
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( {required BuildContext context,
|
Widget _buildBody(
|
||||||
required ForgetPasswordViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
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( {required BuildContext context,
|
List<Widget> _buildBodyChildren(
|
||||||
|
{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,12 +31,10 @@ 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 {
|
||||||
|
|
@ -55,26 +53,30 @@ 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( {required BuildContext context,
|
Widget _buildScaffoldWrapper(
|
||||||
required ForgetPasswordViewModel viewModel}) => Scaffold(
|
{required BuildContext context,
|
||||||
|
required ForgetPasswordViewModel viewModel}) =>
|
||||||
|
Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldStack( {required BuildContext context,
|
Widget _buildScaffoldStack(
|
||||||
required ForgetPasswordViewModel viewModel}) => Stack(
|
{required BuildContext context,
|
||||||
|
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(
|
||||||
|
|
@ -83,15 +85,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),
|
||||||
);
|
);
|
||||||
|
|
@ -102,10 +104,6 @@ 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,6 +1,8 @@
|
||||||
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/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';
|
||||||
|
|
@ -16,17 +18,20 @@ class HomeView extends StackedView<HomeViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onViewModelReady(HomeViewModel viewModel) async {
|
void onViewModelReady(HomeViewModel viewModel) async {
|
||||||
await viewModel.getProfileStatus();
|
await _init(viewModel);
|
||||||
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) => viewModel.isBusy
|
Widget _buildScaffoldWrapper(HomeViewModel viewModel) =>
|
||||||
|
viewModel.busy(StateObjects.homeView)
|
||||||
? const StartupView(label: 'Checking user info')
|
? const StartupView(label: 'Checking user info')
|
||||||
: _buildScaffold(viewModel);
|
: _buildScaffold(viewModel);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ 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();
|
||||||
|
|
@ -63,25 +64,58 @@ class HomeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
Future<void> replaceWithFailure() async =>
|
Future<void> replaceWithFailure() async =>
|
||||||
await _navigationService.clearStackAndShowView(
|
await _navigationService.clearStackAndShow(Routes.failureView,
|
||||||
const FailureView(label: 'Check your internet connection to proceed'),
|
arguments: '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)) {
|
||||||
|
|
@ -89,46 +123,17 @@ 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(
|
await _authenticationService.saveUserData(image: image, data: user);
|
||||||
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,6 +72,7 @@ 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',
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ 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) =>
|
||||||
|
|
@ -122,6 +123,8 @@ 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(),
|
||||||
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -130,11 +133,13 @@ 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,4 +34,12 @@ 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,13 +15,11 @@ 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');
|
||||||
|
|
@ -70,6 +68,7 @@ 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) =>
|
||||||
|
|
@ -173,6 +172,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,6 +67,11 @@ class LearnLessonDetailViewModel extends BaseViewModel {
|
||||||
// Navigation
|
// Navigation
|
||||||
void pop() => _navigationService.back();
|
void pop() => _navigationService.back();
|
||||||
|
|
||||||
Future<void> navigateToLearnPractice() async=>await _navigationService.navigateToLearnPracticeView();
|
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.',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ 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,8 +22,17 @@ 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();
|
||||||
|
|
||||||
void pop() => _navigationService.back();
|
Future<void> navigateToLearnPractice() async =>
|
||||||
|
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,6 +47,7 @@ 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) =>
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ class LearnModuleViewModel extends BaseViewModel {
|
||||||
|
|
||||||
final List<Map<String, dynamic>> _modules = [
|
final List<Map<String, dynamic>> _modules = [
|
||||||
{
|
{
|
||||||
'status': ProgressStatuses.started,
|
'status': ProgressStatuses.completed,
|
||||||
'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.pending,
|
'status': ProgressStatuses.started,
|
||||||
'title': 'Module 2: Everyday Basics',
|
'title': 'Module 2: Everyday Basics',
|
||||||
'subtitle': 'Learn numbers, colors, and common objects.',
|
'subtitle': 'Learn numbers, colors, and common objects.',
|
||||||
},
|
},
|
||||||
|
|
@ -39,4 +39,12 @@ class LearnModuleViewModel extends BaseViewModel {
|
||||||
|
|
||||||
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,8 +1,12 @@
|
||||||
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/listen_speaker_screen.dart';
|
import 'package:yimaru_app/ui/views/learn_practice/screens/finish_learn_practice_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_completion_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/learn_practice/screens/start_practice_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/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';
|
||||||
|
|
||||||
|
|
@ -13,7 +17,16 @@ 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> {
|
||||||
const LearnPracticeView({Key? key}) : super(key: key);
|
final String title;
|
||||||
|
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) =>
|
||||||
|
|
@ -27,13 +40,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.addPostFrameCallback((_) => viewModel.goBack());
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) => viewModel.goBack());
|
||||||
},
|
},
|
||||||
child: _buildScaffoldWrapper(viewModel));
|
child: _buildScaffoldWrapper(viewModel));
|
||||||
|
|
||||||
|
|
@ -42,31 +55,44 @@ class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
||||||
body: _buildScaffoldStack(viewModel),
|
body: _buildScaffoldStack(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffoldStack(LearnPracticeViewModel viewModel) => Stack(children: [
|
Widget _buildScaffoldStack(LearnPracticeViewModel viewModel) =>
|
||||||
|
Stack(children: [
|
||||||
_buildBody(viewModel),
|
_buildBody(viewModel),
|
||||||
//_buildLoginWithEmailState(viewModel),
|
//_buildLoginWithEmailState(viewModel),
|
||||||
//_buildLoginWithGoogleState(viewModel)
|
//_buildLoginWithGoogleState(viewModel)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Widget _buildBody(LearnPracticeViewModel viewModel) =>
|
Widget _buildBody(LearnPracticeViewModel viewModel) =>
|
||||||
IndexedStack(
|
IndexedStack(index: viewModel.currentIndex, children: _buildScreens());
|
||||||
|
|
||||||
index: viewModel.currentIndex, children: _buildScreens());
|
|
||||||
|
|
||||||
List<Widget> _buildScreens() => [
|
List<Widget> _buildScreens() => [
|
||||||
_buildPracticeIntroScreen(),
|
_buildLearnPracticeIntroScreen(),
|
||||||
_buildStartPracticeScreen(),
|
_buildStartLearnPracticeScreen(),
|
||||||
_buildListenSpeakerScreen()
|
_buildListenLearnPracticeSpeakerScreen(),
|
||||||
|
_buildSpeakToLearnPracticeListenerScreen(),
|
||||||
|
_buildFinishLearnPracticeScreen(),
|
||||||
|
_buildLearnPracticeResultScreen(),
|
||||||
|
_buildLearnPracticeCompletionScreen()
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildPracticeIntroScreen() => const PracticeIntroScreen();
|
Widget _buildLearnPracticeIntroScreen() => LearnPracticeIntroScreen(
|
||||||
|
title: title,
|
||||||
|
subtitle: subtitle,
|
||||||
|
buttonLabel: buttonLabel,
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildStartPracticeScreen() => const StartPracticeScreen();
|
Widget _buildStartLearnPracticeScreen() => const StartLearnPracticeScreen();
|
||||||
|
|
||||||
Widget _buildListenSpeakerScreen() => const ListenSpeakerScreen();
|
Widget _buildListenLearnPracticeSpeakerScreen() =>
|
||||||
|
const ListenLearnPracticeSpeakerScreen();
|
||||||
|
|
||||||
|
Widget _buildSpeakToLearnPracticeListenerScreen() =>
|
||||||
|
const SpeakToLearnPracticeListenerScreen();
|
||||||
|
|
||||||
|
Widget _buildFinishLearnPracticeScreen() => const FinishLearnPracticeScreen();
|
||||||
|
|
||||||
|
Widget _buildLearnPracticeResultScreen() => const LearnPracticeResultScreen();
|
||||||
|
|
||||||
|
Widget _buildLearnPracticeCompletionScreen() => const LearnPracticeCompletionScreen();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,24 +11,30 @@ 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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -9,13 +9,20 @@ 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 PracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
const PracticeIntroScreen({super.key});
|
final String title;
|
||||||
|
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) => _buildScaffoldWrapper(viewModel);
|
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||||
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(LearnPracticeViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
|
|
@ -39,6 +46,7 @@ class PracticeIntroScreen 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',
|
||||||
);
|
);
|
||||||
|
|
@ -83,7 +91,9 @@ class PracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
_buildSubtitle()
|
_buildSubtitle()
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildImage() => const SpeakingPartnerImage(radius: 75,);
|
Widget _buildImage() => const SpeakingPartnerImage(
|
||||||
|
radius: 75,
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildPartnerName() => Text.rich(
|
Widget _buildPartnerName() => Text.rich(
|
||||||
TextSpan(text: 'Daniel', style: style14DG600, children: [
|
TextSpan(text: 'Daniel', style: style14DG600, children: [
|
||||||
|
|
@ -95,13 +105,13 @@ class PracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'Let \'s practice what you just learnt!',
|
title,
|
||||||
style: style25DG600,
|
style: style25DG600,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => Text(
|
Widget _buildSubtitle() => Text(
|
||||||
'I’ll ask you a few questions, and you can respond naturally.',
|
subtitle,
|
||||||
style: style14DG400,
|
style: style14DG400,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
@ -116,9 +126,9 @@ class PracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
text: 'Start Practice',
|
text: buttonLabel,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: ()=> viewModel.goTo(1),
|
onTap: () => viewModel.goTo(1),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
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,8 +10,9 @@ 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 ListenSpeakerScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
class ListenLearnPracticeSpeakerScreen
|
||||||
const ListenSpeakerScreen({super.key});
|
extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
|
const ListenLearnPracticeSpeakerScreen({super.key});
|
||||||
|
|
||||||
Future<void> _showSheet(
|
Future<void> _showSheet(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
|
|
@ -86,6 +87,7 @@ class ListenSpeakerScreen 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',
|
||||||
);
|
);
|
||||||
|
|
@ -190,7 +192,7 @@ class ListenSpeakerScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
[
|
[
|
||||||
_buildReplyButtonWrapper(),
|
_buildReplyButtonWrapper(),
|
||||||
_buildMicButtonWrapper(),
|
_buildMicButtonWrapper(viewModel),
|
||||||
_buildCancelButtonWrapper(context: context, viewModel: viewModel)
|
_buildCancelButtonWrapper(context: context, viewModel: viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -199,10 +201,11 @@ class ListenSpeakerScreen 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() => Expanded(child: _buildMicButton());
|
Widget _buildMicButtonWrapper(LearnPracticeViewModel viewModel) =>
|
||||||
|
Expanded(child: _buildMicButton(viewModel));
|
||||||
|
|
||||||
Widget _buildMicButton() => ElevatedButton(
|
Widget _buildMicButton(LearnPracticeViewModel viewModel) => ElevatedButton(
|
||||||
onPressed: () {},
|
onPressed: () => viewModel.goTo(3),
|
||||||
style: const ButtonStyle(
|
style: const ButtonStyle(
|
||||||
shape: WidgetStatePropertyAll(CircleBorder()),
|
shape: WidgetStatePropertyAll(CircleBorder()),
|
||||||
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
||||||
|
|
@ -0,0 +1,232 @@
|
||||||
|
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 StartPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
const StartPracticeScreen({super.key});
|
const StartLearnPracticeScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||||
|
|
@ -47,6 +47,7 @@ class StartPracticeScreen 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',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -122,7 +123,7 @@ class StartPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
[
|
[
|
||||||
_buildActionLabel(),
|
_buildActionLabel(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildButtonsRowWrapper(),
|
_buildButtonsRowWrapper(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -132,15 +133,15 @@ class StartPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonsRowWrapper() => Row(
|
Widget _buildButtonsRowWrapper(LearnPracticeViewModel viewModel) => Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildButtonsRowChildren(),
|
children: _buildButtonsRowChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildButtonsRowChildren() => [
|
List<Widget> _buildButtonsRowChildren(LearnPracticeViewModel viewModel) => [
|
||||||
_buildReplyButtonWrapper(),
|
_buildReplyButtonWrapper(),
|
||||||
_buildMicButtonWrapper(),
|
_buildMicButtonWrapper(viewModel),
|
||||||
_buildEmptySpace()
|
_buildEmptySpace()
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -149,10 +150,11 @@ class StartPracticeScreen 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() => Expanded(child: _buildMicButton());
|
Widget _buildMicButtonWrapper(LearnPracticeViewModel viewModel) =>
|
||||||
|
Expanded(child: _buildMicButton(viewModel));
|
||||||
|
|
||||||
Widget _buildMicButton() => ElevatedButton(
|
Widget _buildMicButton(LearnPracticeViewModel viewModel) => ElevatedButton(
|
||||||
onPressed: () {},
|
onPressed: () => viewModel.goTo(2),
|
||||||
style: const ButtonStyle(
|
style: const ButtonStyle(
|
||||||
shape: WidgetStatePropertyAll(CircleBorder()),
|
shape: WidgetStatePropertyAll(CircleBorder()),
|
||||||
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
padding: WidgetStatePropertyAll(EdgeInsets.all(15)),
|
||||||
|
|
@ -56,10 +56,6 @@ 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());
|
||||||
|
|
||||||
|
|
@ -78,5 +74,4 @@ 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.clearStackAndShowView(const HomeView());
|
await _navigationService.clearStackAndShow(Routes.homeView);
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
|
|
@ -171,7 +171,8 @@ class LoginViewModel extends FormViewModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> signInWithGoogle() async => await runBusyFuture(_signInWithGoogle(),
|
Future<void> signInWithGoogle() async =>
|
||||||
|
await runBusyFuture(_signInWithGoogle(),
|
||||||
busyObject: StateObjects.loginWithGoogle);
|
busyObject: StateObjects.loginWithGoogle);
|
||||||
|
|
||||||
Future<void> _signInWithGoogle() async {
|
Future<void> _signInWithGoogle() async {
|
||||||
|
|
|
||||||
|
|
@ -21,61 +21,77 @@ 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(height: half + 325 - half,);
|
return SizedBox(
|
||||||
|
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({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}) =>
|
||||||
Widget _buildScaffold({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(context: context,viewModel: viewModel),
|
children:
|
||||||
|
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
List<Widget> _buildScaffoldChildren(
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(context: context,viewModel: viewModel)];
|
{required BuildContext context, required LoginViewModel 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({required BuildContext context,required LoginViewModel viewModel}) =>
|
Widget _buildExpandedBody(
|
||||||
Expanded(child: _buildColumnScroller(context: context,viewModel: viewModel));
|
{required BuildContext context, required LoginViewModel viewModel}) =>
|
||||||
|
Expanded(
|
||||||
|
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
Widget _buildColumnScroller({required BuildContext context,required LoginViewModel viewModel}) =>
|
Widget _buildColumnScroller(
|
||||||
|
{required BuildContext context, required LoginViewModel viewModel}) =>
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context,viewModel: viewModel),
|
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper({required BuildContext context,required LoginViewModel viewModel}) => Padding(
|
Widget _buildBodyWrapper(
|
||||||
|
{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({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
Widget _buildBody(
|
||||||
|
{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}) =>
|
||||||
|
[
|
||||||
List<Widget> _buildBodyChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
_buildUpperColumn(viewModel),
|
||||||
[_buildUpperColumn(viewModel),getPadding(context), _buildContinueButton(viewModel)];
|
getPadding(context),
|
||||||
|
_buildContinueButton(viewModel)
|
||||||
|
];
|
||||||
|
|
||||||
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -83,7 +99,6 @@ 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,10 +22,11 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
required this.emailController,
|
required this.emailController,
|
||||||
required this.passwordController});
|
required this.passwordController});
|
||||||
|
|
||||||
|
Widget getPadding(context) {
|
||||||
Widget getPadding(context){
|
double half = screenHeight(context) / 2;
|
||||||
double half = screenHeight(context)/2;
|
return SizedBox(
|
||||||
return SizedBox(height: half + 25 - half,);
|
height: half + 25 - half,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _login(LoginViewModel viewModel) async {
|
Future<void> _login(LoginViewModel viewModel) async {
|
||||||
|
|
@ -42,57 +43,75 @@ 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({required BuildContext context,required LoginViewModel viewModel}) => Scaffold(
|
Widget _buildScaffoldWrapper(
|
||||||
|
{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({required BuildContext context,required LoginViewModel viewModel}) => Stack(children: [
|
Widget _buildScaffoldStack(
|
||||||
_buildScaffold(context: context,viewModel: viewModel),
|
{required BuildContext context, required LoginViewModel viewModel}) =>
|
||||||
|
Stack(children: [
|
||||||
|
_buildScaffold(context: context, viewModel: viewModel),
|
||||||
_buildLoginWithEmailState(viewModel),
|
_buildLoginWithEmailState(viewModel),
|
||||||
_buildLoginWithGoogleState(viewModel)
|
_buildLoginWithGoogleState(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: _buildScaffoldChildren(context: context,viewModel: viewModel),
|
children:
|
||||||
|
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
List<Widget> _buildScaffoldChildren(
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(context: context,viewModel: viewModel)];
|
{required BuildContext context, required LoginViewModel 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({required BuildContext context,required LoginViewModel viewModel}) =>
|
Widget _buildExpandedBody(
|
||||||
Expanded(child: _buildColumnScroller(context: context,viewModel: viewModel));
|
{required BuildContext context, required LoginViewModel viewModel}) =>
|
||||||
|
Expanded(
|
||||||
|
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
Widget _buildColumnScroller({required BuildContext context,required LoginViewModel viewModel}) =>
|
Widget _buildColumnScroller(
|
||||||
|
{required BuildContext context, required LoginViewModel viewModel}) =>
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context,viewModel: viewModel),
|
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper({required BuildContext context,required LoginViewModel viewModel}) => Padding(
|
Widget _buildBodyWrapper(
|
||||||
|
{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({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
Widget _buildBody(
|
||||||
|
{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}) =>
|
||||||
|
[
|
||||||
List<Widget> _buildBodyChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
_buildUpperColumn(viewModel),
|
||||||
[_buildUpperColumn(viewModel),getPadding(context), _buildLowerColumn(viewModel)];
|
getPadding(context),
|
||||||
|
_buildLowerColumn(viewModel)
|
||||||
|
];
|
||||||
|
|
||||||
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -246,7 +265,6 @@ 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,63 +18,76 @@ 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(height: half + 175 - half,);
|
return SizedBox(
|
||||||
|
height: half + 175 - 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(
|
||||||
|
{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}) =>
|
||||||
Widget _buildScaffold({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(context: context,viewModel: viewModel),
|
children:
|
||||||
|
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
List<Widget> _buildScaffoldChildren(
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(context: context,viewModel: viewModel)];
|
{required BuildContext context, required LoginViewModel 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({required BuildContext context,required LoginViewModel viewModel}) =>
|
Widget _buildExpandedBody(
|
||||||
Expanded(child: _buildColumnScroller(context: context,viewModel: viewModel));
|
{required BuildContext context, required LoginViewModel viewModel}) =>
|
||||||
|
Expanded(
|
||||||
|
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
Widget _buildColumnScroller({required BuildContext context,required LoginViewModel viewModel}) =>
|
Widget _buildColumnScroller(
|
||||||
|
{required BuildContext context, required LoginViewModel viewModel}) =>
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(context: context,viewModel: viewModel),
|
child: _buildBodyWrapper(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper({required BuildContext context,required LoginViewModel viewModel}) => Padding(
|
Widget _buildBodyWrapper(
|
||||||
|
{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({required BuildContext context,required LoginViewModel viewModel}) => Column(
|
Widget _buildBody(
|
||||||
|
{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}) =>
|
||||||
|
[
|
||||||
List<Widget> _buildBodyChildren({required BuildContext context,required LoginViewModel viewModel}) =>
|
_buildUpperColumn(viewModel),
|
||||||
[_buildUpperColumn(viewModel),getPadding(context), _buildLowerColumn(viewModel)];
|
getPadding(context),
|
||||||
|
_buildLowerColumn(viewModel)
|
||||||
|
];
|
||||||
|
|
||||||
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
Widget _buildUpperColumn(LoginViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -82,7 +95,6 @@ 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.clearStackAndShowView(const HomeView());
|
await _navigationService.clearStackAndShow(Routes.homeView);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ 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,8 +54,9 @@ class PrivacyPolicyView extends StackedView<PrivacyPolicyViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(PrivacyPolicyViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(PrivacyPolicyViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Privacy Policy',
|
showBackButton: true,
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
|
title: 'Privacy Policy',
|
||||||
);
|
);
|
||||||
|
|
||||||
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.saveProfileImage(image);
|
await _authenticationService.saveProfilePicture(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.saveProfileImage(image);
|
await _authenticationService.saveProfilePicture(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,9 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppbar(ProfileDetailViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(ProfileDetailViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Edit Profile',
|
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
|
showBackButton: true,
|
||||||
|
title: 'Edit Profile',
|
||||||
);
|
);
|
||||||
|
|
||||||
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.saveProfileImage(image);
|
await _authenticationService.saveProfilePicture(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.saveProfileImage(image);
|
await _authenticationService.saveProfilePicture(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ 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) =>
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,6 @@ 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());
|
||||||
|
|
||||||
|
|
@ -114,5 +112,4 @@ class RegisterView extends StackedView<RegisterViewModel> with $RegisterView {
|
||||||
Widget _buildCreatePasswordScreen() => CreatePasswordScreen(
|
Widget _buildCreatePasswordScreen() => CreatePasswordScreen(
|
||||||
passwordController: passwordController,
|
passwordController: passwordController,
|
||||||
confirmPasswordController: confirmPasswordController);
|
confirmPasswordController: confirmPasswordController);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ class RegisterViewModel extends FormViewModel {
|
||||||
|
|
||||||
final _googleAuthService = locator<GoogleAuthService>();
|
final _googleAuthService = locator<GoogleAuthService>();
|
||||||
|
|
||||||
|
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
|
|
@ -284,17 +283,18 @@ class RegisterViewModel extends FormViewModel {
|
||||||
await _navigationService.replaceWithLoginView();
|
await _navigationService.replaceWithLoginView();
|
||||||
|
|
||||||
Future<void> replaceWithHome() async =>
|
Future<void> replaceWithHome() async =>
|
||||||
await _navigationService.clearStackAndShowView(const HomeView());
|
await _navigationService.clearStackAndShow(Routes.homeView);
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
Future<void> registerWithEmail() async =>
|
Future<void> registerWithEmail() async => await runBusyFuture(_register(),
|
||||||
await runBusyFuture(_register(), busyObject: StateObjects.registerWithEmail);
|
busyObject: StateObjects.registerWithEmail);
|
||||||
|
|
||||||
Future<void> _register() async {
|
Future<void> _register() async {
|
||||||
if (await _statusChecker.checkConnection()) {
|
if (await _statusChecker.checkConnection()) {
|
||||||
Map<String, dynamic> response = await _apiService.registerWithEmail(_userData);
|
Map<String, dynamic> response =
|
||||||
|
await _apiService.registerWithEmail(_userData);
|
||||||
|
|
||||||
if (response['status'] == ResponseStatus.success) {
|
if (response['status'] == ResponseStatus.success) {
|
||||||
goTo(page: 3);
|
goTo(page: 3);
|
||||||
|
|
|
||||||
|
|
@ -231,8 +231,6 @@ 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,10 +26,11 @@ class RegistrationOtpScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
required this.emailController,
|
required this.emailController,
|
||||||
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _verifyOtp(RegisterViewModel viewModel) async {
|
Future<void> _verifyOtp(RegisterViewModel viewModel) async {
|
||||||
|
|
@ -45,13 +46,14 @@ 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( {required BuildContext context,
|
Widget _buildScaffoldWrapper(
|
||||||
required RegisterViewModel viewModel}) => Scaffold(
|
{required BuildContext context,
|
||||||
|
required RegisterViewModel viewModel}) =>
|
||||||
|
Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
body: _buildScaffoldStack(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
@ -66,49 +68,66 @@ class RegistrationOtpScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold( {required BuildContext context,
|
Widget _buildScaffold(
|
||||||
required RegisterViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
required RegisterViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(context: context, viewModel: viewModel),
|
children:
|
||||||
|
_buildScaffoldChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren( {required BuildContext context,
|
List<Widget> _buildScaffoldChildren(
|
||||||
|
{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( {required BuildContext context,
|
Widget _buildExpandedBody(
|
||||||
|
{required BuildContext context,
|
||||||
required RegisterViewModel viewModel}) =>
|
required RegisterViewModel viewModel}) =>
|
||||||
Expanded(child: _buildColumnScroller(context: context, viewModel: viewModel));
|
Expanded(
|
||||||
|
child: _buildColumnScroller(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
Widget _buildColumnScroller( {required BuildContext context,
|
Widget _buildColumnScroller(
|
||||||
|
{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( {required BuildContext context,
|
Widget _buildBodyWrapper(
|
||||||
required RegisterViewModel viewModel}) => Padding(
|
{required BuildContext context,
|
||||||
|
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( {required BuildContext context,
|
Widget _buildBody(
|
||||||
required RegisterViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
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( {required BuildContext context,
|
List<Widget> _buildBodyChildren(
|
||||||
|
{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,8 +70,7 @@ class StartupView extends StackedView<StartupViewModel> {
|
||||||
_buildIndicatorWrapper(),
|
_buildIndicatorWrapper(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildLoadingText() =>
|
Widget _buildLoadingText() => Text('$label ...', style: style16W600);
|
||||||
Text('$label ...', style: const TextStyle(color: kcWhite, fontSize: 16));
|
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
Widget _buildIndicatorWrapper() => SizedBox(
|
||||||
width: 16,
|
width: 16,
|
||||||
|
|
@ -83,7 +82,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: 100),
|
padding: const EdgeInsets.only(top: 120),
|
||||||
child: _buildIcon(),
|
child: _buildIcon(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ 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,8 +49,9 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(TelegramSupportViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(TelegramSupportViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Telegram Support',
|
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
|
showBackButton: true,
|
||||||
|
title: 'Telegram Support',
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedColumn(TelegramSupportViewModel viewModel) =>
|
Widget _buildExpandedColumn(TelegramSupportViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,9 @@ class TermsAndConditionsView extends StackedView<TermsAndConditionsViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppbar(TermsAndConditionsViewModel viewModel) => SmallAppBar(
|
Widget _buildAppbar(TermsAndConditionsViewModel viewModel) => SmallAppBar(
|
||||||
title: 'Terms and Conditions',
|
|
||||||
onTap: viewModel.pop,
|
onTap: viewModel.pop,
|
||||||
|
showBackButton: true,
|
||||||
|
title: 'Terms and Conditions',
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContentWrapper(TermsAndConditionsViewModel viewModel) =>
|
Widget _buildContentWrapper(TermsAndConditionsViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,10 @@ class FirstWelcomeScreen extends ViewModelWidget<WelcomeViewModel> {
|
||||||
height: 50,
|
height: 50,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => 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(
|
||||||
|
|
@ -85,8 +81,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,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ class CancelLearnPracticeSheet extends StatelessWidget {
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildContinueButton(),
|
_buildContinueButton(),
|
||||||
_buildEndButton(),
|
_buildEndButton(),
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildImage() => const SpeakingPartnerImage(
|
Widget _buildImage() => const SpeakingPartnerImage(
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,6 @@ class CustomCircularProgressIndicator extends StatelessWidget {
|
||||||
|
|
||||||
Widget _buildIndicator() => CircularProgressIndicator(
|
Widget _buildIndicator() => CircularProgressIndicator(
|
||||||
color: color,
|
color: color,
|
||||||
strokeWidth: 6,
|
strokeWidth: 5,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,22 +29,25 @@ class CustomColumnButton extends StatelessWidget {
|
||||||
children: _buildColumnChildren(),
|
children: _buildColumnChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren() => [
|
List<Widget> _buildColumnChildren() => [_buildIconWrapper(), _buildLabel()];
|
||||||
_buildIconWrapper(),
|
|
||||||
_buildLabel()
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildIconWrapper() => Container(
|
Widget _buildIconWrapper() => Container(
|
||||||
padding:const EdgeInsets.all(5),
|
padding: const EdgeInsets.all(5),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: color.withOpacity(0.1),
|
color: color.withOpacity(0.1),
|
||||||
border: Border.all(color: color.withOpacity(0.75))
|
border: Border.all(color: color.withOpacity(0.75))),
|
||||||
),
|
|
||||||
child: _buildIcon(),
|
child: _buildIcon(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLabel()=> Text(label,style: style14LG400.copyWith(color: color),);
|
Widget _buildLabel() => Text(
|
||||||
|
label,
|
||||||
|
style: style14LG400.copyWith(color: color),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildIcon()=> Icon(icon,size: 14,color: color,);
|
Widget _buildIcon() => Icon(
|
||||||
|
icon,
|
||||||
|
size: 14,
|
||||||
|
color: color,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,10 +57,7 @@ class CustomListTile extends StatelessWidget {
|
||||||
|
|
||||||
Widget _buildTrailingText() => Text(
|
Widget _buildTrailingText() => Text(
|
||||||
language ?? '',
|
language ?? '',
|
||||||
style: const TextStyle(
|
style: style12DG400,
|
||||||
fontSize: 12,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTrailingIcon() => const Icon(
|
Widget _buildTrailingIcon() => const Icon(
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,12 @@ class LearnLessonTile extends StatelessWidget {
|
||||||
final String thumbnail;
|
final String thumbnail;
|
||||||
final ProgressStatuses status;
|
final ProgressStatuses status;
|
||||||
final GestureTapCallback? onLessonTap;
|
final GestureTapCallback? onLessonTap;
|
||||||
|
final GestureTapCallback? onPracticeTap;
|
||||||
|
|
||||||
const LearnLessonTile({
|
const LearnLessonTile({
|
||||||
super.key,
|
super.key,
|
||||||
this.onLessonTap,
|
this.onLessonTap,
|
||||||
|
this.onPracticeTap,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.status,
|
required this.status,
|
||||||
required this.thumbnail,
|
required this.thumbnail,
|
||||||
|
|
@ -181,11 +183,12 @@ class LearnLessonTile extends StatelessWidget {
|
||||||
_buildLessonButton(),
|
_buildLessonButton(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildPracticeButton() => const CustomElevatedButton(
|
Widget _buildPracticeButton() => CustomElevatedButton(
|
||||||
height: 15,
|
height: 15,
|
||||||
width: 135,
|
width: 135,
|
||||||
text: 'Practice',
|
text: 'Practice',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
|
onTap: onPracticeTap,
|
||||||
trailingIcon: Icons.mic,
|
trailingIcon: Icons.mic,
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
|
|
|
||||||
|
|
@ -218,8 +218,9 @@ class LearnModuleTile extends ViewModelWidget<LearnModuleViewModel> {
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
onTap: () async =>
|
onTap: () async => status == ProgressStatuses.completed
|
||||||
await _showSheet(context: context, viewModel: viewModel),
|
? await viewModel.navigateToLearnPractice()
|
||||||
|
: await _showSheet(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSheet(LearnModuleViewModel viewModel) => FinishPracticeSheet(
|
Widget _buildSheet(LearnModuleViewModel viewModel) => FinishPracticeSheet(
|
||||||
|
|
|
||||||
54
lib/ui/widgets/learn_practice_tip_section.dart
Normal file
54
lib/ui/widgets/learn_practice_tip_section.dart
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
import 'package:yimaru_app/ui/widgets/custom_list_tile.dart';
|
||||||
|
|
||||||
|
class LearnPracticeTipSection extends StatelessWidget {
|
||||||
|
const LearnPracticeTipSection({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => _buildContainer();
|
||||||
|
|
||||||
|
Widget _buildContainer() => Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
color: kcBlue.withOpacity(0.1),
|
||||||
|
),
|
||||||
|
child: _buildColumn(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildColumn() => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: _buildColumnChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildColumnChildren() =>
|
||||||
|
[_buildTitleWrapper(), verticalSpaceTiny, _buildContent()];
|
||||||
|
|
||||||
|
Widget _buildTitleWrapper() =>
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
_buildLeading(),horizontalSpaceSmall,_buildTitle()
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
Widget _buildLeading() => const Icon(
|
||||||
|
Icons.lightbulb_outline_rounded,
|
||||||
|
color: kcBlue,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildTitle() => Text(
|
||||||
|
'Quick Tip',
|
||||||
|
style: style16B600,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
Widget _buildContent() => Text(
|
||||||
|
"You can always do better!\nSpeak in full sentences instead of short phrases.\nMaintain a steady pace, not too fast, not too slow.\nUse varied vocabulary to make your answers richer.\nPause naturally instead of using fillers like “um” or “uh”.",
|
||||||
|
style: style14B400,
|
||||||
|
textAlign: TextAlign.start,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -123,14 +123,14 @@ class LearnSubLevelTile extends ViewModelWidget<LearnLevelViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPracticeButton(LearnLevelViewModel viewModel) =>
|
Widget _buildPracticeButton(LearnLevelViewModel viewModel) =>
|
||||||
const CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 15,
|
height: 15,
|
||||||
text: 'Practice',
|
text: 'Practice',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
|
onTap: () async => await viewModel.navigateToLearnPractice()
|
||||||
// onTap: () async => await viewModel.navigateToLearnLevel(),
|
// onTap: () async => await viewModel.navigateToLearnLevel(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
71
lib/ui/widgets/practice_response_card.dart
Normal file
71
lib/ui/widgets/practice_response_card.dart
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
|
||||||
|
class PracticeResponseCard extends StatelessWidget {
|
||||||
|
final String title;
|
||||||
|
final String subtitle;
|
||||||
|
|
||||||
|
const PracticeResponseCard(
|
||||||
|
{super.key, required this.title, required this.subtitle});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => _buildContainer();
|
||||||
|
|
||||||
|
Widget _buildContainer() => Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kcWhite,
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 5),
|
||||||
|
child: _buildRow(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildRow() => Row(
|
||||||
|
children: [
|
||||||
|
_buildPlayButton(),
|
||||||
|
_buildColumnWrapper()
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildPlayButton() => ElevatedButton(
|
||||||
|
onPressed: () {},
|
||||||
|
style: const ButtonStyle(
|
||||||
|
shape: WidgetStatePropertyAll(CircleBorder()),
|
||||||
|
padding: WidgetStatePropertyAll(EdgeInsets.all(5)),
|
||||||
|
shadowColor: WidgetStatePropertyAll(kcPrimaryColor),
|
||||||
|
backgroundColor: WidgetStatePropertyAll(kcPrimaryColor),
|
||||||
|
),
|
||||||
|
child: _buildPlayIcon(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildPlayIcon() => const Icon(
|
||||||
|
Icons.play_arrow_rounded,
|
||||||
|
size: 25,
|
||||||
|
color: kcWhite,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildColumnWrapper() => Expanded(child: _buildColumn());
|
||||||
|
|
||||||
|
Widget _buildColumn() => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: _buildColumnChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildColumnChildren() => [_buildTitle(), _buildSubtitle()];
|
||||||
|
|
||||||
|
Widget _buildTitle() => Text(
|
||||||
|
title,
|
||||||
|
maxLines: 1,
|
||||||
|
softWrap: false,
|
||||||
|
style: style12RP600,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildSubtitle() => Text(
|
||||||
|
subtitle,
|
||||||
|
maxLines: 1,
|
||||||
|
softWrap: false,
|
||||||
|
style: style12RP600,
|
||||||
|
);
|
||||||
|
}
|
||||||
47
lib/ui/widgets/practice_result_card.dart
Normal file
47
lib/ui/widgets/practice_result_card.dart
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
import 'package:yimaru_app/ui/widgets/practice_response_card.dart';
|
||||||
|
|
||||||
|
class PracticeResultCard extends StatelessWidget {
|
||||||
|
final int index;
|
||||||
|
final Map<String, dynamic> data;
|
||||||
|
const PracticeResultCard(
|
||||||
|
{super.key, required this.index, required this.data});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => _buildColumnWrapper();
|
||||||
|
|
||||||
|
Widget _buildColumnWrapper() => SizedBox(height: 100,width: double.maxFinite,child: _buildColumn(),);
|
||||||
|
|
||||||
|
Widget _buildColumn() => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: _buildColumnChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildColumnChildren() => [_buildQuestion(),verticalSpaceSmall, _buildRow()];
|
||||||
|
|
||||||
|
Widget _buildQuestion() => Text(
|
||||||
|
'$index. ${data['question']}',
|
||||||
|
style: style14DG400,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildRow() => Row(
|
||||||
|
children: _buildRowChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildRowChildren() =>
|
||||||
|
[_buildSampleResponseWrapper(),horizontalSpaceSmall, _buildActualResponseWrapper()];
|
||||||
|
|
||||||
|
Widget _buildSampleResponseWrapper() =>
|
||||||
|
Expanded(child: _buildSampleResponse());
|
||||||
|
|
||||||
|
Widget _buildSampleResponse() =>
|
||||||
|
const PracticeResponseCard(title: 'Sample Answer', subtitle: '0:54');
|
||||||
|
|
||||||
|
Widget _buildActualResponseWrapper() =>
|
||||||
|
Expanded(child: _buildActualResponse());
|
||||||
|
|
||||||
|
Widget _buildActualResponse() =>
|
||||||
|
const PracticeResponseCard(title: 'Sample Answer', subtitle: '0:54');
|
||||||
|
}
|
||||||
50
lib/ui/widgets/practice_results_wrapper.dart
Normal file
50
lib/ui/widgets/practice_results_wrapper.dart
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
import 'package:yimaru_app/ui/widgets/practice_result_card.dart';
|
||||||
|
|
||||||
|
import '../common/app_colors.dart';
|
||||||
|
|
||||||
|
class PracticeResultsWrapper extends StatelessWidget {
|
||||||
|
final List<Map<String, dynamic>> data;
|
||||||
|
|
||||||
|
const PracticeResultsWrapper({super.key, required this.data});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => _buildContainer();
|
||||||
|
|
||||||
|
Widget _buildContainer() => Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
color: kcPrimaryColor.withOpacity(0.1),
|
||||||
|
),
|
||||||
|
child: _buildColumn(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildColumn() => Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: _buildColumnChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildColumnChildren() =>
|
||||||
|
[_buildTitle(), verticalSpaceSmall, _buildResults()];
|
||||||
|
|
||||||
|
Widget _buildTitle() => Text(
|
||||||
|
'Conversation Review',
|
||||||
|
style: style16DG600,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildResults() => ListView.separated(
|
||||||
|
shrinkWrap: true,
|
||||||
|
itemCount: data.length,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, index) => _buildResult(index),
|
||||||
|
separatorBuilder: (context, index) => verticalSpaceSmall,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildResult(int index) =>
|
||||||
|
PracticeResultCard(index: index + 1, data: data[index]);
|
||||||
|
}
|
||||||
|
|
@ -4,9 +4,11 @@ import 'package:yimaru_app/ui/widgets/custom_back_button.dart';
|
||||||
|
|
||||||
class SmallAppBar extends StatelessWidget {
|
class SmallAppBar extends StatelessWidget {
|
||||||
final String? title;
|
final String? title;
|
||||||
|
final bool showBackButton;
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback? onTap;
|
||||||
|
|
||||||
const SmallAppBar({super.key, this.onTap, this.title});
|
const SmallAppBar(
|
||||||
|
{super.key, this.onTap, this.title, required this.showBackButton});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => _buildAppBar();
|
Widget build(BuildContext context) => _buildAppBar();
|
||||||
|
|
@ -16,8 +18,10 @@ class SmallAppBar extends StatelessWidget {
|
||||||
children: _buildAppBarChildren(),
|
children: _buildAppBarChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildAppBarChildren() =>
|
List<Widget> _buildAppBarChildren() => [
|
||||||
[_buildBackButtonWrapper(), if (title != null) _buildTitleWrapper()];
|
if (showBackButton) _buildBackButtonWrapper(),
|
||||||
|
if (title != null) _buildTitleWrapper()
|
||||||
|
];
|
||||||
|
|
||||||
Widget _buildBackButtonWrapper() => Align(
|
Widget _buildBackButtonWrapper() => Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,17 @@ import '../common/app_colors.dart';
|
||||||
|
|
||||||
class SpeakingPartnerImage extends StatelessWidget {
|
class SpeakingPartnerImage extends StatelessWidget {
|
||||||
final double radius;
|
final double radius;
|
||||||
const SpeakingPartnerImage({super.key,required this.radius});
|
const SpeakingPartnerImage({super.key, required this.radius});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => _buildProfileImage();
|
Widget build(BuildContext context) => _buildProfileImage();
|
||||||
|
|
||||||
|
|
||||||
Widget _buildProfileImage() => CircleAvatar(
|
Widget _buildProfileImage() => CircleAvatar(
|
||||||
radius: radius,
|
radius: radius,
|
||||||
backgroundColor: kcViolet,
|
backgroundColor: kcViolet,
|
||||||
backgroundImage: _buildImageBuilder(),
|
backgroundImage: _buildImageBuilder(),
|
||||||
);
|
);
|
||||||
|
|
||||||
AssetImage? _buildImageBuilder() => const AssetImage('assets/images/profile.png');
|
AssetImage? _buildImageBuilder() =>
|
||||||
|
const AssetImage('assets/images/profile.png');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user