fix: Apply UAT comments
This commit is contained in:
parent
92db2453c5
commit
e917209d10
BIN
assets/images/pattern.png
Normal file
BIN
assets/images/pattern.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -510,8 +510,8 @@ class StackedRouter extends _i1.RouterBase {
|
|||
_i22.LearnLessonDetailView: (data) {
|
||||
final args = data.getArgs<LearnLessonDetailViewArguments>(nullOk: false);
|
||||
return _i37.MaterialPageRoute<dynamic>(
|
||||
builder: (context) =>
|
||||
_i22.LearnLessonDetailView(key: args.key, lesson: args.lesson),
|
||||
builder: (context) => _i22.LearnLessonDetailView(
|
||||
key: args.key, lesson: args.lesson, hasPractice: args.hasPractice),
|
||||
settings: data,
|
||||
);
|
||||
},
|
||||
|
|
@ -519,7 +519,13 @@ class StackedRouter extends _i1.RouterBase {
|
|||
final args = data.getArgs<LearnPracticeViewArguments>(nullOk: false);
|
||||
return _i37.MaterialPageRoute<dynamic>(
|
||||
builder: (context) => _i23.LearnPracticeView(
|
||||
key: args.key, id: args.id, practice: args.practice),
|
||||
key: args.key,
|
||||
level: args.level,
|
||||
id: args.id,
|
||||
label: args.label,
|
||||
title: args.title,
|
||||
practice: args.practice,
|
||||
subtitle: args.subtitle),
|
||||
settings: data,
|
||||
);
|
||||
},
|
||||
|
|
@ -1098,56 +1104,85 @@ class LearnLessonDetailViewArguments {
|
|||
const LearnLessonDetailViewArguments({
|
||||
this.key,
|
||||
required this.lesson,
|
||||
required this.hasPractice,
|
||||
});
|
||||
|
||||
final _i37.Key? key;
|
||||
|
||||
final _i40.LearnLesson lesson;
|
||||
|
||||
final bool hasPractice;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '{"key": "$key", "lesson": "$lesson"}';
|
||||
return '{"key": "$key", "lesson": "$lesson", "hasPractice": "$hasPractice"}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant LearnLessonDetailViewArguments other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other.key == key && other.lesson == lesson;
|
||||
return other.key == key &&
|
||||
other.lesson == lesson &&
|
||||
other.hasPractice == hasPractice;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return key.hashCode ^ lesson.hashCode;
|
||||
return key.hashCode ^ lesson.hashCode ^ hasPractice.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
class LearnPracticeViewArguments {
|
||||
const LearnPracticeViewArguments({
|
||||
this.key,
|
||||
this.level,
|
||||
required this.id,
|
||||
required this.label,
|
||||
required this.title,
|
||||
required this.practice,
|
||||
required this.subtitle,
|
||||
});
|
||||
|
||||
final _i37.Key? key;
|
||||
|
||||
final String? level;
|
||||
|
||||
final int id;
|
||||
|
||||
final String label;
|
||||
|
||||
final String title;
|
||||
|
||||
final _i41.LearnPractices practice;
|
||||
|
||||
final String subtitle;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '{"key": "$key", "id": "$id", "practice": "$practice"}';
|
||||
return '{"key": "$key", "level": "$level", "id": "$id", "label": "$label", "title": "$title", "practice": "$practice", "subtitle": "$subtitle"}';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(covariant LearnPracticeViewArguments other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other.key == key && other.id == id && other.practice == practice;
|
||||
return other.key == key &&
|
||||
other.level == level &&
|
||||
other.id == id &&
|
||||
other.label == label &&
|
||||
other.title == title &&
|
||||
other.practice == practice &&
|
||||
other.subtitle == subtitle;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
return key.hashCode ^ id.hashCode ^ practice.hashCode;
|
||||
return key.hashCode ^
|
||||
level.hashCode ^
|
||||
id.hashCode ^
|
||||
label.hashCode ^
|
||||
title.hashCode ^
|
||||
practice.hashCode ^
|
||||
subtitle.hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1817,6 +1852,7 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
Future<dynamic> navigateToLearnLessonDetailView({
|
||||
_i37.Key? key,
|
||||
required _i40.LearnLesson lesson,
|
||||
required bool hasPractice,
|
||||
int? routerId,
|
||||
bool preventDuplicates = true,
|
||||
Map<String, String>? parameters,
|
||||
|
|
@ -1824,7 +1860,8 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
transition,
|
||||
}) async {
|
||||
return navigateTo<dynamic>(Routes.learnLessonDetailView,
|
||||
arguments: LearnLessonDetailViewArguments(key: key, lesson: lesson),
|
||||
arguments: LearnLessonDetailViewArguments(
|
||||
key: key, lesson: lesson, hasPractice: hasPractice),
|
||||
id: routerId,
|
||||
preventDuplicates: preventDuplicates,
|
||||
parameters: parameters,
|
||||
|
|
@ -1833,8 +1870,12 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
|
||||
Future<dynamic> navigateToLearnPracticeView({
|
||||
_i37.Key? key,
|
||||
String? level,
|
||||
required int id,
|
||||
required String label,
|
||||
required String title,
|
||||
required _i41.LearnPractices practice,
|
||||
required String subtitle,
|
||||
int? routerId,
|
||||
bool preventDuplicates = true,
|
||||
Map<String, String>? parameters,
|
||||
|
|
@ -1842,8 +1883,14 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
transition,
|
||||
}) async {
|
||||
return navigateTo<dynamic>(Routes.learnPracticeView,
|
||||
arguments:
|
||||
LearnPracticeViewArguments(key: key, id: id, practice: practice),
|
||||
arguments: LearnPracticeViewArguments(
|
||||
key: key,
|
||||
level: level,
|
||||
id: id,
|
||||
label: label,
|
||||
title: title,
|
||||
practice: practice,
|
||||
subtitle: subtitle),
|
||||
id: routerId,
|
||||
preventDuplicates: preventDuplicates,
|
||||
parameters: parameters,
|
||||
|
|
@ -2395,6 +2442,7 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
Future<dynamic> replaceWithLearnLessonDetailView({
|
||||
_i37.Key? key,
|
||||
required _i40.LearnLesson lesson,
|
||||
required bool hasPractice,
|
||||
int? routerId,
|
||||
bool preventDuplicates = true,
|
||||
Map<String, String>? parameters,
|
||||
|
|
@ -2402,7 +2450,8 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
transition,
|
||||
}) async {
|
||||
return replaceWith<dynamic>(Routes.learnLessonDetailView,
|
||||
arguments: LearnLessonDetailViewArguments(key: key, lesson: lesson),
|
||||
arguments: LearnLessonDetailViewArguments(
|
||||
key: key, lesson: lesson, hasPractice: hasPractice),
|
||||
id: routerId,
|
||||
preventDuplicates: preventDuplicates,
|
||||
parameters: parameters,
|
||||
|
|
@ -2411,8 +2460,12 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
|
||||
Future<dynamic> replaceWithLearnPracticeView({
|
||||
_i37.Key? key,
|
||||
String? level,
|
||||
required int id,
|
||||
required String label,
|
||||
required String title,
|
||||
required _i41.LearnPractices practice,
|
||||
required String subtitle,
|
||||
int? routerId,
|
||||
bool preventDuplicates = true,
|
||||
Map<String, String>? parameters,
|
||||
|
|
@ -2420,8 +2473,14 @@ extension NavigatorStateExtension on _i46.NavigationService {
|
|||
transition,
|
||||
}) async {
|
||||
return replaceWith<dynamic>(Routes.learnPracticeView,
|
||||
arguments:
|
||||
LearnPracticeViewArguments(key: key, id: id, practice: practice),
|
||||
arguments: LearnPracticeViewArguments(
|
||||
key: key,
|
||||
level: level,
|
||||
id: id,
|
||||
label: label,
|
||||
title: title,
|
||||
practice: practice,
|
||||
subtitle: subtitle),
|
||||
id: routerId,
|
||||
preventDuplicates: preventDuplicates,
|
||||
parameters: parameters,
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ class DioService {
|
|||
|
||||
return true;
|
||||
} catch (e) {
|
||||
print('REFRESH EXCEPTION: ${e.toString()}');
|
||||
await _authenticationService.logout();
|
||||
await _navigationService.replaceWithLoginView();
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,4 @@ import 'package:flutter_phone_direct_caller/flutter_phone_direct_caller.dart';
|
|||
class PhoneCallerService {
|
||||
Future<void> call(String phone) async =>
|
||||
await FlutterPhoneDirectCaller.callNumber(phone);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
const String ksHomeBottomSheetTitle = 'Build Great Apps!';
|
||||
|
||||
const String ksSuggestion =
|
||||
|
|
|
|||
|
|
@ -238,6 +238,12 @@ TextStyle style25P600 = const TextStyle(
|
|||
fontWeight: FontWeight.w600,
|
||||
);
|
||||
|
||||
TextStyle style40P900 = const TextStyle(
|
||||
fontSize: 40,
|
||||
color: kcPrimaryColor,
|
||||
fontWeight: FontWeight.w900,
|
||||
);
|
||||
|
||||
TextStyle style25DG600 = const TextStyle(
|
||||
fontSize: 25,
|
||||
color: kcDarkGrey,
|
||||
|
|
@ -309,16 +315,14 @@ TextStyle style14LG400 = const TextStyle(
|
|||
TextStyle style14MG400 = const TextStyle(
|
||||
color: kcMediumGrey,
|
||||
);
|
||||
TextStyle style14DG400 = const TextStyle(color: kcDarkGrey);
|
||||
|
||||
TextStyle style14DG500 =
|
||||
const TextStyle(color: kcDarkGrey, fontWeight: FontWeight.w500);
|
||||
|
||||
TextStyle style18MG500 = const TextStyle(
|
||||
fontSize: 18, color: kcMediumGrey, fontWeight: FontWeight.w500);
|
||||
|
||||
TextStyle style14DG400 = const TextStyle(
|
||||
color: kcDarkGrey,
|
||||
);
|
||||
|
||||
TextStyle style14DG600 = const TextStyle(
|
||||
color: kcDarkGrey,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
|
|
|||
|
|
@ -53,62 +53,61 @@ class AssessmentQuestionsScreen extends ViewModelWidget<AssessmentViewModel> {
|
|||
controller: viewModel.pageController,
|
||||
itemCount: viewModel.assessmentQuestions.length,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (cotext, index) =>
|
||||
_buildBodyScroller( viewModel),
|
||||
itemBuilder: (cotext, index) => _buildBodyScroller(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildBodyScroller(
|
||||
AssessmentViewModel viewModel) =>
|
||||
Widget _buildBodyScroller(AssessmentViewModel viewModel) =>
|
||||
SingleChildScrollView(
|
||||
child: _buildBody( viewModel),
|
||||
child: _buildBody(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildBody(
|
||||
AssessmentViewModel viewModel) =>
|
||||
Column(
|
||||
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _buildBodyChildren( viewModel),
|
||||
children: _buildBodyChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildBodyChildren(
|
||||
AssessmentViewModel viewModel) =>[
|
||||
|
||||
List<Widget> _buildBodyChildren(AssessmentViewModel viewModel) => [
|
||||
verticalSpaceMedium,
|
||||
_buildTitleState( viewModel),
|
||||
_buildTitleState(viewModel),
|
||||
verticalSpaceMedium,
|
||||
_buildAnswersState( viewModel),
|
||||
_buildContinueButtonWrapper( viewModel)
|
||||
_buildAnswersState(viewModel),
|
||||
_buildContinueButtonWrapper(viewModel)
|
||||
];
|
||||
Widget _buildTitleState( AssessmentViewModel viewModel)=> viewModel.currentQuestionIndex ==
|
||||
viewModel.assessmentQuestions.length ?Container(): _buildTitle(viewModel);
|
||||
Widget _buildTitle(
|
||||
AssessmentViewModel viewModel) =>
|
||||
Text(
|
||||
Widget _buildTitleState(AssessmentViewModel viewModel) =>
|
||||
viewModel.currentQuestionIndex == viewModel.assessmentQuestions.length
|
||||
? Container()
|
||||
: _buildTitle(viewModel);
|
||||
Widget _buildTitle(AssessmentViewModel viewModel) => Text(
|
||||
'Q${viewModel.currentQuestionIndex + 1}. ${viewModel.assessmentQuestions[viewModel.currentQuestionIndex].questionText} ',
|
||||
style: style16DG600,
|
||||
);
|
||||
|
||||
Widget _buildAnswersState( AssessmentViewModel viewModel)=> viewModel.currentQuestionIndex ==
|
||||
viewModel.assessmentQuestions.length ?Container(): _buildAnswers(viewModel);
|
||||
Widget _buildAnswersState(AssessmentViewModel viewModel) =>
|
||||
viewModel.currentQuestionIndex == viewModel.assessmentQuestions.length
|
||||
? Container()
|
||||
: _buildAnswers(viewModel);
|
||||
|
||||
Widget _buildAnswers(
|
||||
AssessmentViewModel viewModel) =>
|
||||
ListView.builder(
|
||||
Widget _buildAnswers(AssessmentViewModel viewModel) => ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: viewModel.assessmentQuestions[viewModel.currentQuestionIndex].options?.length,
|
||||
itemCount: viewModel.assessmentQuestions[viewModel.currentQuestionIndex]
|
||||
.options?.length,
|
||||
itemBuilder: (context, inner) => _buildAnswer(
|
||||
onTap: () => viewModel.setSelectedAnswer(
|
||||
question: viewModel.currentQuestionIndex + 1,
|
||||
option: viewModel.assessmentQuestions[viewModel.currentQuestionIndex].options?[inner]),
|
||||
title:
|
||||
viewModel.assessmentQuestions[viewModel.currentQuestionIndex].options?[inner].optionText ??
|
||||
option: viewModel
|
||||
.assessmentQuestions[viewModel.currentQuestionIndex]
|
||||
.options?[inner]),
|
||||
title: viewModel.assessmentQuestions[viewModel.currentQuestionIndex]
|
||||
.options?[inner].optionText ??
|
||||
'',
|
||||
selected: viewModel.isSelectedAnswer(
|
||||
question: viewModel.currentQuestionIndex + 1,
|
||||
answer: viewModel
|
||||
.assessmentQuestions[viewModel.currentQuestionIndex ].options?[inner].optionText ??
|
||||
.assessmentQuestions[viewModel.currentQuestionIndex]
|
||||
.options?[inner]
|
||||
.optionText ??
|
||||
''),
|
||||
),
|
||||
);
|
||||
|
|
@ -123,15 +122,12 @@ class AssessmentQuestionsScreen extends ViewModelWidget<AssessmentViewModel> {
|
|||
selected: selected,
|
||||
);
|
||||
|
||||
Widget _buildContinueButtonWrapper(
|
||||
AssessmentViewModel viewModel) =>
|
||||
Padding(
|
||||
Widget _buildContinueButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 50),
|
||||
child: _buildContinueButton( viewModel),
|
||||
child: _buildContinueButton(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildContinueButton(
|
||||
AssessmentViewModel viewModel) =>
|
||||
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||
CustomElevatedButton(
|
||||
height: 55,
|
||||
borderRadius: 12,
|
||||
|
|
@ -140,13 +136,13 @@ class AssessmentQuestionsScreen extends ViewModelWidget<AssessmentViewModel> {
|
|||
viewModel.assessmentQuestions.length - 1
|
||||
? 'Finish Level'
|
||||
: 'Continue',
|
||||
backgroundColor:
|
||||
viewModel.selectedAnswers.containsKey('${viewModel.currentQuestionIndex + 1}')
|
||||
backgroundColor: viewModel.selectedAnswers
|
||||
.containsKey('${viewModel.currentQuestionIndex + 1}')
|
||||
? kcPrimaryColor
|
||||
: kcPrimaryColor.withOpacity(0.1),
|
||||
onTap: viewModel.selectedAnswers.containsKey('${viewModel.currentQuestionIndex + 1}')
|
||||
onTap: viewModel.selectedAnswers
|
||||
.containsKey('${viewModel.currentQuestionIndex + 1}')
|
||||
? () => viewModel.nextQuestion()
|
||||
: null,
|
||||
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:yimaru_app/ui/common/app_constants.dart';
|
||||
|
||||
import '../../common/app_colors.dart';
|
||||
import '../../common/ui_helpers.dart';
|
||||
|
|
@ -83,9 +84,7 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
|||
verticalSpaceMedium,
|
||||
_buildTitle(),
|
||||
verticalSpaceMedium,
|
||||
_buildSubtitle('+2519012345678'),
|
||||
verticalSpaceSmall,
|
||||
_buildSubtitle('+2519012345678'),
|
||||
_buildSubtitle(kPhoneSupport),
|
||||
];
|
||||
|
||||
Widget _buildIcon() =>
|
||||
|
|
@ -109,12 +108,13 @@ class CallSupportView extends StackedView<CallSupportViewModel> {
|
|||
);
|
||||
|
||||
Widget _buildContinueButton(CallSupportViewModel viewModel) =>
|
||||
const CustomElevatedButton(
|
||||
CustomElevatedButton(
|
||||
height: 55,
|
||||
borderRadius: 12,
|
||||
text: 'Tap to Call',
|
||||
leadingIcon: Icons.call,
|
||||
foregroundColor: kcWhite,
|
||||
backgroundColor: kcPrimaryColor,
|
||||
onTap: () async => await viewModel.callSupport(),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,18 @@ import 'package:stacked/stacked.dart';
|
|||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import '../../../app/app.locator.dart';
|
||||
import '../../../services/phone_caller_service.dart';
|
||||
import '../../common/app_constants.dart';
|
||||
|
||||
class CallSupportViewModel extends BaseViewModel {
|
||||
// Dependency injection
|
||||
final _navigationService = locator<NavigationService>();
|
||||
|
||||
final _phoneCallerService = locator<PhoneCallerService>();
|
||||
|
||||
// Call support
|
||||
Future<void> callSupport() => _phoneCallerService.call(kPhoneSupport);
|
||||
|
||||
// Navigation
|
||||
void pop() => _navigationService.back();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,14 +40,6 @@ class ForgetPasswordViewModel extends FormViewModel {
|
|||
|
||||
bool get length => _length;
|
||||
|
||||
bool _number = false;
|
||||
|
||||
bool get number => _number;
|
||||
|
||||
bool _specialChar = false;
|
||||
|
||||
bool get specialChar => _specialChar;
|
||||
|
||||
bool _focusPassword = false;
|
||||
|
||||
bool get focusPassword => _focusPassword;
|
||||
|
|
@ -105,11 +97,9 @@ class ForgetPasswordViewModel extends FormViewModel {
|
|||
int completed = 0;
|
||||
|
||||
if (_length) completed++;
|
||||
if (_number) completed++;
|
||||
if (_specialChar) completed++;
|
||||
if (_passwordMatch) completed++;
|
||||
|
||||
return completed / 4; // returns 0.0 → 1.0
|
||||
return completed / 2; // returns 0.0 → 1.0
|
||||
}
|
||||
|
||||
void validatePassword(
|
||||
|
|
@ -120,17 +110,7 @@ class ForgetPasswordViewModel extends FormViewModel {
|
|||
_length = false;
|
||||
}
|
||||
|
||||
if (RegExp(r'\d').hasMatch(password)) {
|
||||
_number = true;
|
||||
} else {
|
||||
_number = false;
|
||||
}
|
||||
|
||||
if (RegExp(r'[!@#$%^&*(),.?":{}|<>]').hasMatch(password)) {
|
||||
_specialChar = true;
|
||||
} else {
|
||||
_specialChar = false;
|
||||
}
|
||||
|
||||
if (password == confirmPassword) {
|
||||
_passwordMatch = true;
|
||||
|
|
@ -156,8 +136,6 @@ class ForgetPasswordViewModel extends FormViewModel {
|
|||
// Reset reset password screen
|
||||
void resetResetPasswordScreen() {
|
||||
_length = false;
|
||||
_number = false;
|
||||
_specialChar = false;
|
||||
_passwordMatch = false;
|
||||
_focusPassword = false;
|
||||
_focusResetCode = false;
|
||||
|
|
|
|||
|
|
@ -140,8 +140,6 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
|||
_buildLinearProgressIndicator(viewModel),
|
||||
verticalSpaceSmall,
|
||||
_buildCharLengthValidator(viewModel),
|
||||
_buildNumberValidator(viewModel),
|
||||
_buildSymbolValidator(viewModel),
|
||||
_buildPasswordMatchValidator(viewModel),
|
||||
verticalSpaceSmall,
|
||||
_buildSignUpButton(viewModel),
|
||||
|
|
@ -256,16 +254,6 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
|||
backgroundColor: viewModel.length ? kcPrimaryColor : kcLightGrey,
|
||||
label: '8 characters minimum');
|
||||
|
||||
Widget _buildNumberValidator(ForgetPasswordViewModel viewModel) =>
|
||||
ValidatorListTile(
|
||||
backgroundColor: viewModel.number ? kcPrimaryColor : kcLightGrey,
|
||||
label: 'a number');
|
||||
|
||||
Widget _buildSymbolValidator(ForgetPasswordViewModel viewModel) =>
|
||||
ValidatorListTile(
|
||||
backgroundColor: viewModel.specialChar ? kcPrimaryColor : kcLightGrey,
|
||||
label: 'one symbol minimum');
|
||||
|
||||
Widget _buildPasswordMatchValidator(ForgetPasswordViewModel viewModel) =>
|
||||
ValidatorListTile(
|
||||
backgroundColor:
|
||||
|
|
@ -281,20 +269,14 @@ class ResetPasswordScreen extends ViewModelWidget<ForgetPasswordViewModel> {
|
|||
onTap: passwordController.text.isNotEmpty &&
|
||||
confirmPasswordController.text.isNotEmpty &&
|
||||
resetCodeController.text.isNotEmpty &&
|
||||
viewModel.number &&
|
||||
viewModel.length &&
|
||||
viewModel.specialChar &&
|
||||
viewModel.specialChar &&
|
||||
viewModel.passwordMatch
|
||||
? () async => await _reset(viewModel)
|
||||
: null,
|
||||
backgroundColor: passwordController.text.isNotEmpty &&
|
||||
confirmPasswordController.text.isNotEmpty &&
|
||||
resetCodeController.text.isNotEmpty &&
|
||||
viewModel.number &&
|
||||
viewModel.length &&
|
||||
viewModel.specialChar &&
|
||||
viewModel.specialChar &&
|
||||
viewModel.passwordMatch
|
||||
? kcPrimaryColor
|
||||
: kcPrimaryColor.withOpacity(0.1),
|
||||
|
|
|
|||
|
|
@ -84,8 +84,9 @@ class LearnCourseView extends StackedView<LearnCourseViewModel> {
|
|||
course: viewModel.learnCourses[index],
|
||||
onViewTap: () async => await viewModel
|
||||
.navigateToLearnModule(viewModel.learnCourses[index]),
|
||||
onPracticeTap: () async => await viewModel
|
||||
.navigateToLearnPractice(viewModel.learnCourses[index].id ?? 0),
|
||||
onPracticeTap: () async => await viewModel.navigateToLearnPractice(
|
||||
id: viewModel.learnCourses[index].id ?? 0,
|
||||
level: viewModel.learnCourses[index].name ?? ''),
|
||||
),
|
||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -27,8 +27,16 @@ class LearnCourseViewModel extends BaseViewModel {
|
|||
Future<void> navigateToLearnModule(LearnCourse course) async =>
|
||||
_navigationService.navigateToLearnModuleView(course: course);
|
||||
|
||||
Future<void> navigateToLearnPractice(int id) async => await _navigationService
|
||||
.navigateToLearnPracticeView(id: id, practice: LearnPractices.course);
|
||||
Future<void> navigateToLearnPractice(
|
||||
{required int id, required String level}) async =>
|
||||
await _navigationService.navigateToLearnPracticeView(
|
||||
id: id,
|
||||
level: level,
|
||||
label: 'Begin Level Practice',
|
||||
practice: LearnPractices.course,
|
||||
title: 'Let’s Practice Course $level',
|
||||
subtitle: 'Let’s quickly review what you’ve learned in this level!',
|
||||
);
|
||||
|
||||
// Remote api call
|
||||
|
||||
|
|
|
|||
|
|
@ -115,9 +115,9 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
|||
_buildSubtitle(),
|
||||
verticalSpaceSmall,
|
||||
_buildModuleProgress(),
|
||||
verticalSpaceMedium,
|
||||
verticalSpaceLarge,
|
||||
_buildMotivationCard(),
|
||||
verticalSpaceMedium,
|
||||
verticalSpaceLarge,
|
||||
_buildHeader(),
|
||||
verticalSpaceMedium,
|
||||
_buildListViewBuilder(viewModel),
|
||||
|
|
@ -156,20 +156,25 @@ class LearnLessonView extends StackedView<LearnLessonViewModel> {
|
|||
itemCount: viewModel.lessons.length,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => _buildTile(
|
||||
index: index,
|
||||
lesson: viewModel.lessons[index],
|
||||
onLessonTap: () async => await viewModel
|
||||
.navigateToLearnLessonDetail(viewModel.lessons[index]),
|
||||
onLessonTap: () async => await viewModel.navigateToLearnLessonDetail(
|
||||
lesson: viewModel.lessons[index],
|
||||
hasPractice:
|
||||
index != viewModel.lessons.length - 1 ? true : false),
|
||||
onPracticeTap: () async => await viewModel
|
||||
.navigateToLearnPractice(viewModel.lessons[index].id ?? 0),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildTile({
|
||||
required int index,
|
||||
required LearnLesson lesson,
|
||||
required GestureTapCallback? onLessonTap,
|
||||
required GestureTapCallback? onPracticeTap,
|
||||
}) =>
|
||||
LearnLessonTile(
|
||||
index: index,
|
||||
lesson: lesson,
|
||||
onLessonTap: onLessonTap,
|
||||
onPracticeTap: onPracticeTap,
|
||||
|
|
|
|||
|
|
@ -24,11 +24,20 @@ class LearnLessonViewModel extends BaseViewModel {
|
|||
// Navigation
|
||||
void pop() => _navigationService.back();
|
||||
|
||||
Future<void> navigateToLearnPractice(int id) async => await _navigationService
|
||||
.navigateToLearnPracticeView(id: id, practice: LearnPractices.lesson);
|
||||
Future<void> navigateToLearnPractice(int id) async =>
|
||||
await _navigationService.navigateToLearnPracticeView(
|
||||
id: id,
|
||||
label: 'Start Practice',
|
||||
practice: LearnPractices.lesson,
|
||||
title: 'Let\'s practice what you just learnt!',
|
||||
subtitle:
|
||||
'I’ll ask you a few questions, and you can respond naturally.',
|
||||
);
|
||||
|
||||
Future<void> navigateToLearnLessonDetail(LearnLesson lesson) async =>
|
||||
await _navigationService.navigateToLearnLessonDetailView(lesson: lesson);
|
||||
Future<void> navigateToLearnLessonDetail(
|
||||
{required bool hasPractice, required LearnLesson lesson}) async =>
|
||||
await _navigationService.navigateToLearnLessonDetailView(
|
||||
lesson: lesson, hasPractice: hasPractice);
|
||||
|
||||
// Remote api call
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@ import '../../widgets/small_app_bar.dart';
|
|||
import 'learn_lesson_detail_viewmodel.dart';
|
||||
|
||||
class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
||||
final bool hasPractice;
|
||||
final LearnLesson lesson;
|
||||
|
||||
const LearnLessonDetailView({Key? key, required this.lesson})
|
||||
const LearnLessonDetailView(
|
||||
{Key? key, required this.lesson, required this.hasPractice})
|
||||
: super(key: key);
|
||||
|
||||
Future<void> _navigate(LearnLessonDetailViewModel viewModel) async {
|
||||
|
|
@ -86,7 +88,7 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
|||
List<Widget> _buildBodyColumnChildren(LearnLessonDetailViewModel viewModel) =>
|
||||
[
|
||||
_buildLevelsColumnWrapper(viewModel),
|
||||
_buildContinueButtonWrapper(viewModel)
|
||||
if (hasPractice) _buildPracticeButtonWrapper(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildLevelsColumnWrapper(LearnLessonDetailViewModel viewModel) =>
|
||||
|
|
@ -157,21 +159,21 @@ class LearnLessonDetailView extends StackedView<LearnLessonDetailViewModel> {
|
|||
style: style14DG400,
|
||||
);
|
||||
|
||||
Widget _buildContinueButtonWrapper(LearnLessonDetailViewModel viewModel) =>
|
||||
Widget _buildPracticeButtonWrapper(LearnLessonDetailViewModel viewModel) =>
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15,
|
||||
right: 15,
|
||||
bottom: 50,
|
||||
),
|
||||
child: _buildContinueButton(viewModel),
|
||||
child: _buildPracticeButton(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildContinueButton(LearnLessonDetailViewModel viewModel) =>
|
||||
Widget _buildPracticeButton(LearnLessonDetailViewModel viewModel) =>
|
||||
CustomElevatedButton(
|
||||
height: 55,
|
||||
borderRadius: 12,
|
||||
text: 'Practices',
|
||||
text: 'Take Practice',
|
||||
foregroundColor: kcWhite,
|
||||
backgroundColor: kcPrimaryColor,
|
||||
onTap: () async => await _navigate(viewModel),
|
||||
|
|
|
|||
|
|
@ -67,6 +67,13 @@ class LearnLessonDetailViewModel extends BaseViewModel {
|
|||
// Navigation
|
||||
void pop() => _navigationService.back();
|
||||
|
||||
Future<void> navigateToLearnPractice(int id) async => await _navigationService
|
||||
.navigateToLearnPracticeView(id: id, practice: LearnPractices.lesson);
|
||||
Future<void> navigateToLearnPractice(int id) async =>
|
||||
await _navigationService.navigateToLearnPracticeView(
|
||||
id: id,
|
||||
label: 'Start Practice',
|
||||
practice: LearnPractices.lesson,
|
||||
title: 'Let\'s practice what you just learnt!',
|
||||
subtitle:
|
||||
'I’ll ask you a few questions, and you can respond naturally.',
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,8 +116,9 @@ class LearnModuleView extends StackedView<LearnModuleViewModel> {
|
|||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) => _buildTile(
|
||||
module: viewModel.modules[index],
|
||||
onPracticeTap: () async => await viewModel
|
||||
.navigateToLearnPractice(viewModel.modules[index].id ?? 0),
|
||||
onPracticeTap: () async => await viewModel.navigateToLearnPractice(
|
||||
id: viewModel.modules[index].id ?? 0,
|
||||
module: viewModel.modules[index].name ?? ''),
|
||||
onModuleTap: () async =>
|
||||
await viewModel.navigateToLearnLesson(viewModel.modules[index]),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -27,8 +27,15 @@ class LearnModuleViewModel extends BaseViewModel {
|
|||
Future<void> navigateToLearnLesson(LearnModule module) async =>
|
||||
await _navigationService.navigateToLearnLessonView(module: module);
|
||||
|
||||
Future<void> navigateToLearnPractice(int id) async => await _navigationService
|
||||
.navigateToLearnPracticeView(id: id, practice: LearnPractices.module);
|
||||
Future<void> navigateToLearnPractice(
|
||||
{required int id, required String module}) async =>
|
||||
await _navigationService.navigateToLearnPracticeView(
|
||||
id: id,
|
||||
label: 'Begin Module Practice',
|
||||
practice: LearnPractices.module,
|
||||
title: 'Let’s Practice $module',
|
||||
subtitle: 'Let’s quickly review what you’ve learned in this module! ',
|
||||
);
|
||||
|
||||
// Remote api call
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,21 @@ import 'learn_practice_viewmodel.dart';
|
|||
|
||||
class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
||||
final int id;
|
||||
final String label;
|
||||
final String title;
|
||||
final String? level;
|
||||
final String subtitle;
|
||||
final LearnPractices practice;
|
||||
|
||||
const LearnPracticeView({Key? key, required this.id, required this.practice})
|
||||
: super(key: key);
|
||||
const LearnPracticeView({
|
||||
Key? key,
|
||||
this.level,
|
||||
required this.id,
|
||||
required this.label,
|
||||
required this.title,
|
||||
required this.practice,
|
||||
required this.subtitle,
|
||||
}) : super(key: key);
|
||||
|
||||
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
|
||||
await viewModel.stopRecording();
|
||||
|
|
@ -108,10 +119,17 @@ class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
|||
_buildLearnPracticeQuestionsScreen(),
|
||||
_buildFinishLearnPracticeScreen(),
|
||||
_buildLearnPracticeResultScreen(),
|
||||
if (practice == LearnPractices.course)
|
||||
_buildLearnPracticeCompletionScreen()
|
||||
];
|
||||
|
||||
Widget _buildLearnPracticeIntroScreen() => const LearnPracticeIntroScreen();
|
||||
Widget _buildLearnPracticeIntroScreen() => LearnPracticeIntroScreen(
|
||||
level: level,
|
||||
title: title,
|
||||
label: label,
|
||||
practice: practice,
|
||||
subtitle: subtitle,
|
||||
);
|
||||
|
||||
Widget _buildLearnPracticeElementsScreen() =>
|
||||
const LearnPracticeDescriptionScreen();
|
||||
|
|
@ -121,8 +139,9 @@ class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
|||
|
||||
Widget _buildFinishLearnPracticeScreen() => const FinishLearnPracticeScreen();
|
||||
|
||||
Widget _buildLearnPracticeResultScreen() => const LearnPracticeResultScreen();
|
||||
Widget _buildLearnPracticeResultScreen() =>
|
||||
LearnPracticeResultScreen(practice: practice);
|
||||
|
||||
Widget _buildLearnPracticeCompletionScreen() =>
|
||||
const LearnPracticeCompletionScreen();
|
||||
LearnPracticeCompletionScreen(level: level ?? '');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
|||
await stopRecording();
|
||||
_answers.add({
|
||||
'busy_object': question.id.toString(),
|
||||
'sample_text_answer': question.audioCorrectAnswerText,
|
||||
'question_text': question.questionText,
|
||||
'sample_voice_answer': question.sampleAnswerVoicePrompt,
|
||||
'recorded_voice_answer': await _voiceRecorderService.getRecordedAudio(),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import '../../../widgets/custom_elevated_button.dart';
|
|||
|
||||
class LearnPracticeCompletionScreen
|
||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
||||
const LearnPracticeCompletionScreen({super.key});
|
||||
final String level;
|
||||
const LearnPracticeCompletionScreen({super.key, required this.level});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||
|
|
@ -54,7 +55,7 @@ class LearnPracticeCompletionScreen
|
|||
);
|
||||
|
||||
Widget _buildTitle() => Text(
|
||||
'Yay, you’ve completed A1 ',
|
||||
'Yay, you’ve completed $level ',
|
||||
style: style25DG600,
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import 'package:stacked/stacked.dart';
|
|||
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart';
|
||||
|
||||
import '../../../common/app_colors.dart';
|
||||
import '../../../common/enmus.dart';
|
||||
import '../../../common/ui_helpers.dart';
|
||||
import '../../../widgets/cancel_learn_practice_sheet.dart';
|
||||
import '../../../widgets/custom_elevated_button.dart';
|
||||
|
|
@ -10,7 +11,19 @@ import '../../../widgets/small_app_bar.dart';
|
|||
import '../../../widgets/speaking_partner_image.dart';
|
||||
|
||||
class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||
const LearnPracticeIntroScreen({super.key});
|
||||
final String title;
|
||||
final String label;
|
||||
final String? level;
|
||||
final String subtitle;
|
||||
final LearnPractices practice;
|
||||
|
||||
const LearnPracticeIntroScreen(
|
||||
{super.key,
|
||||
this.level,
|
||||
required this.label,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.practice});
|
||||
|
||||
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
|
||||
await viewModel.stopRecording();
|
||||
|
|
@ -114,21 +127,44 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
List<Widget> _buildPracticeColumnChildren(LearnPracticeViewModel viewModel) =>
|
||||
[
|
||||
verticalSpaceMassive,
|
||||
_buildImage(),
|
||||
_buildImageState(),
|
||||
verticalSpaceMedium,
|
||||
_buildPartnerName(),
|
||||
_buildPartnerNameState(),
|
||||
verticalSpaceMedium,
|
||||
_buildTitle(),
|
||||
verticalSpaceMedium,
|
||||
_buildSubtitle()
|
||||
];
|
||||
|
||||
Widget _buildImage() => const SpeakingPartnerImage(
|
||||
Widget _buildImageState() =>
|
||||
level != null ? _buildCourseSpeakingPartnerImage() : _buildImage(75);
|
||||
|
||||
Widget _buildCourseSpeakingPartnerImage() => CircleAvatar(
|
||||
radius: 75,
|
||||
backgroundColor: kcPrimaryColorLight,
|
||||
child: _buildCourseSpeakingPartnerText(),
|
||||
);
|
||||
|
||||
Widget _buildCourseSpeakingPartnerText() => Text(
|
||||
level?.toUpperCase() ?? '',
|
||||
style: style40P900,
|
||||
);
|
||||
|
||||
Widget _buildImage(double radius) => SpeakingPartnerImage(radius: radius);
|
||||
|
||||
Widget _buildPartnerNameState() =>
|
||||
level != null ? _buildCourseSpeakingPartner() : _buildPartnerName();
|
||||
|
||||
Widget _buildCourseSpeakingPartner() => Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: _buildCourseSpeakingPartnerChildren(),
|
||||
);
|
||||
|
||||
List<Widget> _buildCourseSpeakingPartnerChildren() =>
|
||||
[_buildImage(15), horizontalSpaceTiny, _buildPartnerName()];
|
||||
|
||||
Widget _buildPartnerName() => Text.rich(
|
||||
TextSpan(text: 'Dawit', style: style14DG600, children: [
|
||||
TextSpan(text: 'Daniel', style: style14DG600, children: [
|
||||
TextSpan(
|
||||
text: ' - Your Speaking Partner',
|
||||
style: style14MG400,
|
||||
|
|
@ -137,13 +173,13 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
);
|
||||
|
||||
Widget _buildTitle() => Text(
|
||||
'Let\'s practice what you just learnt!',
|
||||
title,
|
||||
style: style25DG600,
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
|
||||
Widget _buildSubtitle() => Text(
|
||||
'I’ll ask you a few questions, and you can respond naturally.',
|
||||
subtitle,
|
||||
maxLines: 1,
|
||||
style: style14DG400,
|
||||
textAlign: TextAlign.center,
|
||||
|
|
@ -158,8 +194,8 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
Widget _buildContinueButton(LearnPracticeViewModel viewModel) =>
|
||||
CustomElevatedButton(
|
||||
height: 55,
|
||||
text: label,
|
||||
borderRadius: 12,
|
||||
text: 'Practice',
|
||||
foregroundColor: kcWhite,
|
||||
onTap: () => viewModel.goTo(1),
|
||||
backgroundColor: kcPrimaryColor,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||
import 'package:yimaru_app/ui/views/learn_practice/learn_practice_viewmodel.dart';
|
||||
import 'package:yimaru_app/ui/widgets/learn_practice_tip_section.dart';
|
||||
import 'package:yimaru_app/ui/widgets/learn_practice_results_wrapper.dart';
|
||||
|
|
@ -12,9 +13,19 @@ import '../../../widgets/small_app_bar.dart';
|
|||
|
||||
class LearnPracticeResultScreen
|
||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
||||
const LearnPracticeResultScreen({super.key});
|
||||
final LearnPractices practice;
|
||||
|
||||
void _navigate(LearnPracticeViewModel viewModel) async =>
|
||||
const LearnPracticeResultScreen({super.key, required this.practice});
|
||||
|
||||
Future<void> _navigate(LearnPracticeViewModel viewModel) async {
|
||||
if (practice == LearnPractices.course) {
|
||||
viewModel.goTo(5);
|
||||
} else {
|
||||
viewModel.pop();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _retry(LearnPracticeViewModel viewModel) async =>
|
||||
await viewModel.reset();
|
||||
|
||||
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
|
||||
|
|
@ -145,8 +156,8 @@ class LearnPracticeResultScreen
|
|||
text: 'Continue',
|
||||
borderRadius: 12,
|
||||
foregroundColor: kcWhite,
|
||||
onTap: () => viewModel.goTo(5),
|
||||
backgroundColor: kcPrimaryColor,
|
||||
onTap: () async => await _navigate(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildPracticeAgainButton(LearnPracticeViewModel viewModel) =>
|
||||
|
|
@ -157,6 +168,6 @@ class LearnPracticeResultScreen
|
|||
backgroundColor: kcWhite,
|
||||
borderColor: kcPrimaryColor,
|
||||
foregroundColor: kcPrimaryColor,
|
||||
onTap: () => _navigate(viewModel),
|
||||
onTap: () async => await _retry(viewModel),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ class ProfileViewModel extends ReactiveViewModel {
|
|||
|
||||
final _googleAuthService = locator<GoogleAuthService>();
|
||||
|
||||
final _phoneCallerService = locator<PhoneCallerService>();
|
||||
|
||||
final _urlLauncherService = locator<UrlLauncherService>();
|
||||
|
||||
final _imagePickerService = locator<ImagePickerService>();
|
||||
|
||||
final _authenticationService = locator<AuthenticationService>();
|
||||
|
|
@ -68,13 +64,6 @@ class ProfileViewModel extends ReactiveViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
// Launch telegram
|
||||
Future<void> launchTelegram() =>
|
||||
_urlLauncherService.launchUri(kTelegramSupport);
|
||||
|
||||
// Call support
|
||||
Future<void> callSupport() => _phoneCallerService.call(kPhoneSupport);
|
||||
|
||||
// Dialog
|
||||
Future<bool?> showAbortDialog() async {
|
||||
DialogResponse? response = await _dialogService.showDialog(
|
||||
|
|
|
|||
|
|
@ -66,13 +66,14 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
content: _buildImagePicker(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
void _checkRegion(ProfileDetailViewModel viewModel){
|
||||
bool region = viewModel.checkRegion(region:viewModel.user?.region ?? 'Addis Ababa',country:viewModel.user?.country ?? 'Ethiopia' );
|
||||
if(region){
|
||||
void _checkRegion(ProfileDetailViewModel viewModel) {
|
||||
bool region = viewModel.checkRegion(
|
||||
region: viewModel.user?.region ?? 'Addis Ababa',
|
||||
country: viewModel.user?.country ?? 'Ethiopia');
|
||||
if (region) {
|
||||
viewModel.setSelectedRegion(viewModel.user?.region ?? 'Addis Ababa');
|
||||
}else{
|
||||
} else {
|
||||
regionController.text = viewModel.user?.region ?? '';
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -549,10 +550,12 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
_buildRegionFormState(viewModel),
|
||||
if (viewModel.hasRegionValidationMessage &&
|
||||
!viewModel.dropdownRegion &&
|
||||
viewModel.focusRegion) verticalSpaceTiny,
|
||||
viewModel.focusRegion)
|
||||
verticalSpaceTiny,
|
||||
if (viewModel.hasRegionValidationMessage &&
|
||||
!viewModel.dropdownRegion &&
|
||||
viewModel.focusRegion) _buildRegionValidatorWrapper(viewModel),
|
||||
viewModel.focusRegion)
|
||||
_buildRegionValidatorWrapper(viewModel),
|
||||
];
|
||||
|
||||
Widget _buildRegionFormFieldLabel() => CustomFormLabel(
|
||||
|
|
@ -574,7 +577,8 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
onChanged: (value) =>
|
||||
viewModel.setSelectedRegion(value ?? 'Addis Ababa'));
|
||||
|
||||
Widget _buildRegionFormField(ProfileDetailViewModel viewModel) => TextFormField(
|
||||
Widget _buildRegionFormField(ProfileDetailViewModel viewModel) =>
|
||||
TextFormField(
|
||||
controller: regionController,
|
||||
onTap: viewModel.setRegionFocus,
|
||||
decoration: inputDecoration(
|
||||
|
|
@ -593,7 +597,6 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
style: style12R700,
|
||||
);
|
||||
|
||||
|
||||
Widget _buildOccupationDropdownWrapper(ProfileDetailViewModel viewModel) =>
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
@ -608,7 +611,6 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
_buildOccupationDropdownLabel(),
|
||||
verticalSpaceSmall,
|
||||
_buildOccupationDropdown(viewModel)
|
||||
|
||||
];
|
||||
|
||||
Widget _buildOccupationDropdownLabel() => CustomFormLabel(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ const String RegionValueKey = 'region';
|
|||
const String PhoneNumberValueKey = 'phoneNumber';
|
||||
const String LastNameValueKey = 'lastName';
|
||||
const String FirstNameValueKey = 'firstName';
|
||||
const String OccupationValueKey = 'occupation';
|
||||
|
||||
final Map<String, TextEditingController>
|
||||
_ProfileDetailViewTextEditingControllers = {};
|
||||
|
|
@ -32,7 +31,6 @@ final Map<String, String? Function(String?)?>
|
|||
PhoneNumberValueKey: FormValidator.validatePhoneNumberForm,
|
||||
LastNameValueKey: FormValidator.validateForm,
|
||||
FirstNameValueKey: FormValidator.validateForm,
|
||||
OccupationValueKey: FormValidator.validateForm,
|
||||
};
|
||||
|
||||
mixin $ProfileDetailView {
|
||||
|
|
@ -46,15 +44,12 @@ mixin $ProfileDetailView {
|
|||
_getFormTextEditingController(LastNameValueKey);
|
||||
TextEditingController get firstNameController =>
|
||||
_getFormTextEditingController(FirstNameValueKey);
|
||||
TextEditingController get occupationController =>
|
||||
_getFormTextEditingController(OccupationValueKey);
|
||||
|
||||
FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey);
|
||||
FocusNode get regionFocusNode => _getFormFocusNode(RegionValueKey);
|
||||
FocusNode get phoneNumberFocusNode => _getFormFocusNode(PhoneNumberValueKey);
|
||||
FocusNode get lastNameFocusNode => _getFormFocusNode(LastNameValueKey);
|
||||
FocusNode get firstNameFocusNode => _getFormFocusNode(FirstNameValueKey);
|
||||
FocusNode get occupationFocusNode => _getFormFocusNode(OccupationValueKey);
|
||||
|
||||
TextEditingController _getFormTextEditingController(
|
||||
String key, {
|
||||
|
|
@ -85,7 +80,6 @@ mixin $ProfileDetailView {
|
|||
phoneNumberController.addListener(() => _updateFormData(model));
|
||||
lastNameController.addListener(() => _updateFormData(model));
|
||||
firstNameController.addListener(() => _updateFormData(model));
|
||||
occupationController.addListener(() => _updateFormData(model));
|
||||
|
||||
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
||||
}
|
||||
|
|
@ -102,7 +96,6 @@ mixin $ProfileDetailView {
|
|||
phoneNumberController.addListener(() => _updateFormData(model));
|
||||
lastNameController.addListener(() => _updateFormData(model));
|
||||
firstNameController.addListener(() => _updateFormData(model));
|
||||
occupationController.addListener(() => _updateFormData(model));
|
||||
|
||||
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
||||
}
|
||||
|
|
@ -117,7 +110,6 @@ mixin $ProfileDetailView {
|
|||
PhoneNumberValueKey: phoneNumberController.text,
|
||||
LastNameValueKey: lastNameController.text,
|
||||
FirstNameValueKey: firstNameController.text,
|
||||
OccupationValueKey: occupationController.text,
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
@ -165,8 +157,6 @@ extension ValueProperties on FormStateHelper {
|
|||
this.formValueMap[PhoneNumberValueKey] as String?;
|
||||
String? get lastNameValue => this.formValueMap[LastNameValueKey] as String?;
|
||||
String? get firstNameValue => this.formValueMap[FirstNameValueKey] as String?;
|
||||
String? get occupationValue =>
|
||||
this.formValueMap[OccupationValueKey] as String?;
|
||||
|
||||
set emailValue(String? value) {
|
||||
this.setData(
|
||||
|
|
@ -226,18 +216,6 @@ extension ValueProperties on FormStateHelper {
|
|||
}
|
||||
}
|
||||
|
||||
set occupationValue(String? value) {
|
||||
this.setData(
|
||||
this.formValueMap..addAll({OccupationValueKey: value}),
|
||||
);
|
||||
|
||||
if (_ProfileDetailViewTextEditingControllers.containsKey(
|
||||
OccupationValueKey)) {
|
||||
_ProfileDetailViewTextEditingControllers[OccupationValueKey]?.text =
|
||||
value ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
bool get hasEmail =>
|
||||
this.formValueMap.containsKey(EmailValueKey) &&
|
||||
(emailValue?.isNotEmpty ?? false);
|
||||
|
|
@ -253,9 +231,6 @@ extension ValueProperties on FormStateHelper {
|
|||
bool get hasFirstName =>
|
||||
this.formValueMap.containsKey(FirstNameValueKey) &&
|
||||
(firstNameValue?.isNotEmpty ?? false);
|
||||
bool get hasOccupation =>
|
||||
this.formValueMap.containsKey(OccupationValueKey) &&
|
||||
(occupationValue?.isNotEmpty ?? false);
|
||||
|
||||
bool get hasEmailValidationMessage =>
|
||||
this.fieldsValidationMessages[EmailValueKey]?.isNotEmpty ?? false;
|
||||
|
|
@ -267,8 +242,6 @@ extension ValueProperties on FormStateHelper {
|
|||
this.fieldsValidationMessages[LastNameValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasFirstNameValidationMessage =>
|
||||
this.fieldsValidationMessages[FirstNameValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasOccupationValidationMessage =>
|
||||
this.fieldsValidationMessages[OccupationValueKey]?.isNotEmpty ?? false;
|
||||
|
||||
String? get emailValidationMessage =>
|
||||
this.fieldsValidationMessages[EmailValueKey];
|
||||
|
|
@ -280,8 +253,6 @@ extension ValueProperties on FormStateHelper {
|
|||
this.fieldsValidationMessages[LastNameValueKey];
|
||||
String? get firstNameValidationMessage =>
|
||||
this.fieldsValidationMessages[FirstNameValueKey];
|
||||
String? get occupationValidationMessage =>
|
||||
this.fieldsValidationMessages[OccupationValueKey];
|
||||
}
|
||||
|
||||
extension Methods on FormStateHelper {
|
||||
|
|
@ -295,8 +266,6 @@ extension Methods on FormStateHelper {
|
|||
this.fieldsValidationMessages[LastNameValueKey] = validationMessage;
|
||||
void setFirstNameValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[FirstNameValueKey] = validationMessage;
|
||||
void setOccupationValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[OccupationValueKey] = validationMessage;
|
||||
|
||||
/// Clears text input fields on the Form
|
||||
void clearForm() {
|
||||
|
|
@ -305,7 +274,6 @@ extension Methods on FormStateHelper {
|
|||
phoneNumberValue = '';
|
||||
lastNameValue = '';
|
||||
firstNameValue = '';
|
||||
occupationValue = '';
|
||||
}
|
||||
|
||||
/// Validates text input fields on the Form
|
||||
|
|
@ -316,7 +284,6 @@ extension Methods on FormStateHelper {
|
|||
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
||||
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
||||
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -341,5 +308,4 @@ void updateValidationData(FormStateHelper model) =>
|
|||
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
||||
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
||||
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,13 +57,11 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
|
||||
bool get focusEmail => _focusEmail;
|
||||
|
||||
|
||||
// Occupation
|
||||
String _selectedOccupation = 'Students (High school & University)';
|
||||
|
||||
String get selectedOccupation => _selectedOccupation;
|
||||
|
||||
|
||||
// Country
|
||||
String _selectedCountry = 'Ethiopia';
|
||||
|
||||
|
|
@ -117,8 +115,6 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
rebuildUi();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Occupation
|
||||
List<String> getOccupations() => [
|
||||
'Students (High school & University)',
|
||||
|
|
@ -321,8 +317,8 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
'Tigray',
|
||||
];
|
||||
|
||||
bool checkRegion({required String region,required String country}){
|
||||
if(country == 'Ethiopia'){
|
||||
bool checkRegion({required String region, required String country}) {
|
||||
if (country == 'Ethiopia') {
|
||||
return getRegions().contains(region);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ class RegisterViewModel extends ReactiveViewModel
|
|||
_length = false;
|
||||
}
|
||||
|
||||
|
||||
if (password == confirmPassword) {
|
||||
_passwordMatch = true;
|
||||
} else {
|
||||
|
|
@ -237,6 +236,7 @@ class RegisterViewModel extends ReactiveViewModel
|
|||
}
|
||||
|
||||
void goBack() {
|
||||
print('HERE');
|
||||
if (_currentPage == 1) {
|
||||
_currentPage = 0;
|
||||
rebuildUi();
|
||||
|
|
|
|||
|
|
@ -213,7 +213,6 @@ class CreatePasswordScreen extends ViewModelWidget<RegisterViewModel> {
|
|||
backgroundColor: viewModel.length ? kcPrimaryColor : kcLightGrey,
|
||||
label: '8 characters minimum');
|
||||
|
||||
|
||||
Widget _buildPasswordMatchValidator(RegisterViewModel viewModel) =>
|
||||
ValidatorListTile(
|
||||
backgroundColor:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:yimaru_app/ui/common/app_constants.dart';
|
||||
import 'package:yimaru_app/ui/widgets/circular_icon.dart';
|
||||
|
||||
import '../../common/app_colors.dart';
|
||||
|
|
@ -91,20 +92,16 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
|
|||
Widget _buildIcon() =>
|
||||
const CircularIcon(icon: Icons.telegram, size: 50, color: kcSkyBlue);
|
||||
|
||||
Widget _buildTitle() => const Text(
|
||||
Widget _buildTitle() => Text(
|
||||
'Join Yimaru Academy on Telegram',
|
||||
style: style25DG600,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 25,
|
||||
color: kcDarkGrey,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildSubtitle() => const Text(
|
||||
Widget _buildSubtitle() => Text(
|
||||
'Connect with our support team instantly on Telegram for quick assistance and community updates',
|
||||
style: style14MG400,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(color: kcMediumGrey),
|
||||
);
|
||||
|
||||
Widget _buildLowerColumn(TelegramSupportViewModel viewModel) => Column(
|
||||
|
|
@ -123,30 +120,23 @@ class TelegramSupportView extends StackedView<TelegramSupportViewModel> {
|
|||
];
|
||||
|
||||
Widget _buildContinueButton(TelegramSupportViewModel viewModel) =>
|
||||
const CustomElevatedButton(
|
||||
CustomElevatedButton(
|
||||
height: 55,
|
||||
borderRadius: 12,
|
||||
leadingIcon: Icons.telegram,
|
||||
text: 'Open in Telegram',
|
||||
foregroundColor: kcWhite,
|
||||
leadingIcon: Icons.telegram,
|
||||
backgroundColor: kcPrimaryColor,
|
||||
onTap: () async => await viewModel.launchTelegram(),
|
||||
);
|
||||
|
||||
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
||||
|
||||
Widget _buildSearchText() => const Text.rich(
|
||||
Widget _buildSearchText() => Text.rich(
|
||||
TextSpan(text: 'Search for', style: style14DG500, children: [
|
||||
TextSpan(
|
||||
text: 'Search for',
|
||||
style: TextStyle(
|
||||
color: kcDarkGrey,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: ' @YimaruSupport',
|
||||
style: TextStyle(
|
||||
color: kcPrimaryColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
style: style14P600,
|
||||
text: ' $kTelegramSupport',
|
||||
)
|
||||
]),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,8 +2,19 @@ import 'package:stacked/stacked.dart';
|
|||
import 'package:stacked_services/stacked_services.dart';
|
||||
|
||||
import '../../../app/app.locator.dart';
|
||||
import '../../../services/url_launcher_service.dart';
|
||||
import '../../common/app_constants.dart';
|
||||
|
||||
class TelegramSupportViewModel extends BaseViewModel {
|
||||
// Dependency injection
|
||||
final _navigationService = locator<NavigationService>();
|
||||
|
||||
final _urlLauncherService = locator<UrlLauncherService>();
|
||||
|
||||
// Launch telegram
|
||||
Future<void> launchTelegram() =>
|
||||
_urlLauncherService.launchUri(kTelegramSupport);
|
||||
|
||||
// Navigation
|
||||
void pop() => _navigationService.back();
|
||||
}
|
||||
|
|
|
|||
44
lib/ui/widgets/app_bar_pattern.dart
Normal file
44
lib/ui/widgets/app_bar_pattern.dart
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||
|
||||
class AppBarPattern extends StatelessWidget {
|
||||
const AppBarPattern({
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _buildDecorationImageWrapper();
|
||||
|
||||
Widget _buildDecorationImageWrapper() => ClipRRect(
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24),
|
||||
bottomRight: Radius.circular(24),
|
||||
),
|
||||
child: _buildDecorationImage(),
|
||||
);
|
||||
|
||||
Widget _buildDecorationImage() => SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: double.maxFinite,
|
||||
child: _buildPatternWrapper(),
|
||||
);
|
||||
|
||||
Widget _buildPatternWrapper() => SizedBox(
|
||||
width: double.maxFinite,
|
||||
height: double.maxFinite,
|
||||
child: _buildPatternMask(),
|
||||
);
|
||||
|
||||
Widget _buildPatternMask() => ShaderMask(
|
||||
shaderCallback: (Rect bounds) => const LinearGradient(
|
||||
colors: [kcWhite, kcWhite],
|
||||
).createShader(bounds),
|
||||
blendMode: BlendMode.modulate,
|
||||
child: _buildPattern(),
|
||||
);
|
||||
|
||||
Widget _buildPattern() => Image.asset(
|
||||
'assets/images/pattern.png',
|
||||
fit: BoxFit.cover,
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||
import 'package:yimaru_app/ui/widgets/app_bar_pattern.dart';
|
||||
import 'package:yimaru_app/ui/widgets/language_button.dart';
|
||||
|
||||
class LargeAppBar extends StatelessWidget {
|
||||
|
|
@ -18,12 +19,11 @@ class LargeAppBar extends StatelessWidget {
|
|||
required this.showLanguageSelection});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _buildAppBarWrapper();
|
||||
Widget build(BuildContext context) => _buildStackWrapper();
|
||||
|
||||
Widget _buildAppBarWrapper() => Container(
|
||||
Widget _buildStackWrapper() => Container(
|
||||
height: 125,
|
||||
width: double.maxFinite,
|
||||
alignment: Alignment.bottomCenter,
|
||||
decoration: const BoxDecoration(
|
||||
color: kcPrimaryColor,
|
||||
borderRadius: BorderRadius.only(
|
||||
|
|
@ -31,6 +31,18 @@ class LargeAppBar extends StatelessWidget {
|
|||
bottomRight: Radius.circular(24),
|
||||
),
|
||||
),
|
||||
child: _buildStack(),
|
||||
);
|
||||
|
||||
Widget _buildStack() => Stack(
|
||||
children: [ _buildPattern(),_buildAppBarWrapper()],
|
||||
);
|
||||
|
||||
Widget _buildAppBarWrapper() => Container(
|
||||
color: kcTransparent,
|
||||
width: double.maxFinite,
|
||||
height: double.maxFinite,
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: const EdgeInsets.only(bottom: 25, right: 15),
|
||||
child: _buildAppBarItems(),
|
||||
);
|
||||
|
|
@ -74,4 +86,6 @@ class LargeAppBar extends StatelessWidget {
|
|||
Icons.close,
|
||||
color: kcWhite,
|
||||
);
|
||||
|
||||
Widget _buildPattern() => const AppBarPattern();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
|||
height: 15,
|
||||
borderRadius: 12,
|
||||
onTap: onViewTap,
|
||||
text: 'View Courses',
|
||||
text: 'View Course',
|
||||
foregroundColor: kcWhite,
|
||||
backgroundColor: kcPrimaryColor,
|
||||
);
|
||||
|
|
@ -158,7 +158,7 @@ class LearnCourseTile extends ViewModelWidget<LearnCourseViewModel> {
|
|||
height: 15,
|
||||
borderRadius: 12,
|
||||
onTap: onPracticeTap,
|
||||
text: 'Take Practices',
|
||||
text: 'Take Practice',
|
||||
backgroundColor: kcWhite,
|
||||
borderColor: kcPrimaryColor,
|
||||
foregroundColor: kcPrimaryColor,
|
||||
|
|
|
|||
|
|
@ -12,12 +12,16 @@ import 'custom_elevated_button.dart';
|
|||
import 'custom_linear_progress_indicator.dart';
|
||||
|
||||
class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
||||
final int index;
|
||||
final LearnLesson lesson;
|
||||
final GestureTapCallback? onLessonTap;
|
||||
final GestureTapCallback? onPracticeTap;
|
||||
|
||||
const LearnLessonTile(
|
||||
{super.key, this.onLessonTap, this.onPracticeTap, required this.lesson});
|
||||
const LearnLessonTile({super.key,
|
||||
this.onLessonTap,
|
||||
this.onPracticeTap,
|
||||
required this.index,
|
||||
required this.lesson});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, LearnLessonViewModel viewModel) =>
|
||||
|
|
@ -52,8 +56,8 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
|||
expandedAlignment: Alignment.centerLeft,
|
||||
backgroundColor: kcPrimaryColor.withOpacity(0.1),
|
||||
controlAffinity: ListTileControlAffinity.trailing,
|
||||
tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 0),
|
||||
expandedCrossAxisAlignment: CrossAxisAlignment.start,
|
||||
tilePadding: const EdgeInsets.fromLTRB(15, 15, 15, 15),
|
||||
collapsedBackgroundColor: kcPrimaryColor.withOpacity(0.1),
|
||||
childrenPadding: const EdgeInsets.fromLTRB(15, 0, 15, 15),
|
||||
// enabled: (lesson.access?.isAccessible ?? false),
|
||||
|
|
@ -130,10 +134,11 @@ class LearnLessonTile extends ViewModelWidget<LearnLessonViewModel> {
|
|||
|
||||
Widget _buildActionButtons(LearnLessonViewModel viewModel) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: __buildActionButtonChildren(viewModel),
|
||||
children: _buildActionButtonChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> __buildActionButtonChildren(LearnLessonViewModel viewModel) => [
|
||||
List<Widget> _buildActionButtonChildren(LearnLessonViewModel viewModel) => [
|
||||
if (index != viewModel.lessons.length - 1)
|
||||
_buildPracticeButtonWrapper(viewModel),
|
||||
horizontalSpaceSmall,
|
||||
_buildLessonButtonWrapper(viewModel)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class LearnPracticeResultCard extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
_buildColumnWrapper(viewModel);
|
||||
|
||||
Widget _buildColumnWrapper(LearnPracticeViewModel viewModel) => SizedBox(
|
||||
height: 100,
|
||||
height: 125,
|
||||
width: double.maxFinite,
|
||||
child: _buildColumn(viewModel),
|
||||
);
|
||||
|
|
@ -30,7 +30,8 @@ class LearnPracticeResultCard extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
[_buildQuestion(viewModel), verticalSpaceSmall, _buildRow()];
|
||||
|
||||
Widget _buildQuestion(LearnPracticeViewModel viewModel) => Text(
|
||||
answer['sample_text_answer'],
|
||||
answer['question_text'],
|
||||
maxLines: 2,
|
||||
style: style14DG400,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ class MiniThumbnail extends StatelessWidget {
|
|||
Widget build(BuildContext context) => _buildWrapper();
|
||||
|
||||
Widget _buildWrapper() => SizedBox(
|
||||
width: 75,
|
||||
height: double.maxFinite,
|
||||
width: 80,
|
||||
child: _buildLeadingClipper(),
|
||||
);
|
||||
|
||||
|
|
@ -40,15 +39,17 @@ class MiniThumbnail extends StatelessWidget {
|
|||
: _buildNetworkImage();
|
||||
|
||||
Widget _buildNetworkImage() => CachedNetworkImage(
|
||||
fit: BoxFit.cover,
|
||||
imageUrl: thumbnail,
|
||||
fit: BoxFit.fill,
|
||||
width: double.maxFinite,
|
||||
height: double.maxFinite,
|
||||
);
|
||||
|
||||
Widget _buildLocalImage() => Image.asset(
|
||||
thumbnail,
|
||||
fit: BoxFit.fill,
|
||||
fit: BoxFit.cover,
|
||||
width: double.maxFinite,
|
||||
height: double.maxFinite,
|
||||
);
|
||||
|
||||
Widget _buildPlayButtonWrapper() => Align(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name: yimaru_app
|
||||
version: 0.1.13+15
|
||||
version: 0.1.14+16
|
||||
publish_to: 'none'
|
||||
description: A new Flutter project.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user