fix(onboarding): Remove birthday and fix other fields
This commit is contained in:
parent
36360ea7ca
commit
74ffabd917
|
|
@ -14,12 +14,10 @@ class VoiceRecorderService with ListenableServiceMixin {
|
|||
|
||||
WaveformRecorderController get waveController => _waveController;
|
||||
|
||||
|
||||
bool _isRecording = false;
|
||||
|
||||
bool get isRecording => _isRecording;
|
||||
|
||||
|
||||
// Start voice recording
|
||||
Future<void> startRecording() async {
|
||||
await _waveController.startRecording();
|
||||
|
|
@ -41,5 +39,4 @@ class VoiceRecorderService with ListenableServiceMixin {
|
|||
if (file == null) return null;
|
||||
return file.path;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
|||
required LearnPracticeViewModel viewModel}) =>
|
||||
PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (value, data)
|
||||
async=>await _showSheet(context: context, viewModel: viewModel),
|
||||
onPopInvokedWithResult: (value, data) async =>
|
||||
await _showSheet(context: context, viewModel: viewModel),
|
||||
child: _buildScaffoldWrapper(viewModel));
|
||||
|
||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||
|
|
|
|||
|
|
@ -126,7 +126,6 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
|||
Future<void> _startRecording() async =>
|
||||
await _voiceRecorderService.startRecording();
|
||||
|
||||
|
||||
// Play practice audio
|
||||
void _listenToAudio() {
|
||||
_audioPlayerService.durationStream.listen((dur) {
|
||||
|
|
@ -151,32 +150,26 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
|||
await _audioPlayerService.playUrl(question.voicePrompt ?? '');
|
||||
}
|
||||
|
||||
Future<void> playResult({required Map<String,dynamic> answer,required Voice voice})async{
|
||||
setBusyObject(
|
||||
playing: voice,
|
||||
object: answer['busy_object']);
|
||||
Future<void> playResult(
|
||||
{required Map<String, dynamic> answer, required Voice voice}) async {
|
||||
setBusyObject(playing: voice, object: answer['busy_object']);
|
||||
await playAudio(voice: voice, answer: answer);
|
||||
}
|
||||
|
||||
Future<void> playAudio({required Map<String,dynamic> answer,required Voice voice}) async =>
|
||||
Future<void> playAudio(
|
||||
{required Map<String, dynamic> answer, required Voice voice}) async =>
|
||||
await runBusyFuture(_playAudio(voice: voice, answer: answer),
|
||||
busyObject: answer['busy_object']);
|
||||
|
||||
Future<void> _playAudio({required Map<String,dynamic> answer,required Voice voice}) async {
|
||||
|
||||
|
||||
Future<void> _playAudio(
|
||||
{required Map<String, dynamic> answer, required Voice voice}) async {
|
||||
if (voice == Voice.recorded) {
|
||||
await _audioPlayerService
|
||||
.playLocal(answer['recorded_voice_answer']);
|
||||
await _audioPlayerService.playLocal(answer['recorded_voice_answer']);
|
||||
} else {
|
||||
await _audioPlayerService.playUrl(answer['sample_voice_answer']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Future<void> pauseAudio() async {
|
||||
await _audioPlayerService.pause();
|
||||
}
|
||||
|
|
@ -188,8 +181,6 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
|||
rebuildUi();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Dialogue
|
||||
Future<bool?> showAbortDialog() async {
|
||||
DialogResponse? response = await _dialogService.showDialog(
|
||||
|
|
@ -219,7 +210,8 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
|||
}
|
||||
}
|
||||
|
||||
Future<void> nextQuestion({required int index,required LearnQuestion question}) async {
|
||||
Future<void> nextQuestion(
|
||||
{required int index, required LearnQuestion question}) async {
|
||||
await stopRecording();
|
||||
_answers.add({
|
||||
'busy_object': question.id.toString(),
|
||||
|
|
@ -266,6 +258,5 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
|||
|
||||
Future<void> _getLearnPracticeQuestions(int id) async {
|
||||
_questions = await _apiService.getLearnQuestions(id);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ class InteractLearnPracticeScreen
|
|||
void _start(LearnPracticeViewModel viewModel) =>
|
||||
viewModel.playVoicePrompt(question);
|
||||
|
||||
|
||||
Future<void> _stop(LearnPracticeViewModel viewModel) async =>
|
||||
await viewModel.nextQuestion(index: index, question: question);
|
||||
|
||||
|
|
@ -101,8 +100,10 @@ class InteractLearnPracticeScreen
|
|||
_buildLowerButtonsSectionWrapper(context: context, viewModel: viewModel)
|
||||
];
|
||||
|
||||
Widget _buildAppBarWrapper( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Column(
|
||||
Widget _buildAppBarWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Column(
|
||||
children: [
|
||||
verticalSpaceMedium,
|
||||
_buildAppBar(context: context, viewModel: viewModel),
|
||||
|
|
@ -110,10 +111,13 @@ class InteractLearnPracticeScreen
|
|||
],
|
||||
);
|
||||
|
||||
Widget _buildAppBar( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
||||
Widget _buildAppBar(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
SmallAppBar(
|
||||
showBackButton: true,
|
||||
onTap: () async => await _showSheet(context: context,viewModel: viewModel),
|
||||
onTap: () async =>
|
||||
await _showSheet(context: context, viewModel: viewModel),
|
||||
title: 'Practice Speaking ($index/${viewModel.questions.length})');
|
||||
|
||||
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
viewModel.pop();
|
||||
viewModel.pop();
|
||||
viewModel.stopRecording();
|
||||
|
||||
}
|
||||
|
||||
Future<void> _showSheet(
|
||||
|
|
@ -34,24 +33,32 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||
|
||||
Widget _buildScaffoldWrapper( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Scaffold(
|
||||
Widget _buildScaffoldWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Scaffold(
|
||||
backgroundColor: kcBackgroundColor,
|
||||
body: _buildScaffold(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildScaffold( {required BuildContext context,
|
||||
Widget _buildScaffold(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
SafeArea(child: _buildColumnWrapper(context: context,viewModel: viewModel));
|
||||
SafeArea(
|
||||
child: _buildColumnWrapper(context: context, viewModel: viewModel));
|
||||
|
||||
Widget _buildColumnWrapper( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Padding(
|
||||
Widget _buildColumnWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: _buildColumn(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildColumn( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Column(
|
||||
Widget _buildColumn(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Column(
|
||||
children: [
|
||||
verticalSpaceMedium,
|
||||
_buildAppBar(context: context, viewModel: viewModel),
|
||||
|
|
@ -60,12 +67,14 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
],
|
||||
);
|
||||
|
||||
Widget _buildAppBar( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
||||
Widget _buildAppBar(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
SmallAppBar(
|
||||
showBackButton: true,
|
||||
title: 'Practice Speaking',
|
||||
onTap: () async => await _showSheet(context: context,viewModel: viewModel),
|
||||
|
||||
onTap: () async =>
|
||||
await _showSheet(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||
|
|
|
|||
|
|
@ -52,14 +52,19 @@ class LearnPracticeQuestionsScreen
|
|||
|
||||
Widget _buildStartLearnPracticeScreen({
|
||||
required int index,
|
||||
required LearnQuestion question,}
|
||||
) => StartLearnPracticeScreen(
|
||||
required LearnQuestion question,
|
||||
}) =>
|
||||
StartLearnPracticeScreen(
|
||||
index: index,
|
||||
question: question,
|
||||
);
|
||||
|
||||
Widget _buildInteractLearnPracticeScreen({
|
||||
required int index,
|
||||
required LearnQuestion question,}) =>
|
||||
InteractLearnPracticeScreen(index: index,question: question,);
|
||||
required LearnQuestion question,
|
||||
}) =>
|
||||
InteractLearnPracticeScreen(
|
||||
index: index,
|
||||
question: question,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,10 +12,8 @@ import '../../../widgets/small_app_bar.dart';
|
|||
|
||||
class LearnPracticeResultScreen
|
||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
||||
|
||||
const LearnPracticeResultScreen({super.key});
|
||||
|
||||
|
||||
void _navigate(LearnPracticeViewModel viewModel) {
|
||||
viewModel.questionSetController.jumpToPage(0);
|
||||
viewModel.goTo(0);
|
||||
|
|
@ -25,7 +23,6 @@ class LearnPracticeResultScreen
|
|||
viewModel.pop();
|
||||
viewModel.pop();
|
||||
viewModel.stopRecording();
|
||||
|
||||
}
|
||||
|
||||
Future<void> _showSheet(
|
||||
|
|
@ -42,40 +39,55 @@ class LearnPracticeResultScreen
|
|||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||
|
||||
Widget _buildScaffoldWrapper({required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Scaffold(
|
||||
Widget _buildScaffoldWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Scaffold(
|
||||
backgroundColor: kcBackgroundColor,
|
||||
body: _buildScaffold(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildScaffold({required BuildContext context,
|
||||
Widget _buildScaffold(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
SafeArea(child: _buildBodyColumnWrapper(context: context,viewModel: viewModel));
|
||||
SafeArea(
|
||||
child:
|
||||
_buildBodyColumnWrapper(context: context, viewModel: viewModel));
|
||||
|
||||
Widget _buildBodyColumnWrapper({required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Padding(
|
||||
Widget _buildBodyColumnWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: _buildBodyColumn(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildBodyColumn({required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Column(
|
||||
children: _buildBodyColumnChildren(context: context,viewModel: viewModel),
|
||||
Widget _buildBodyColumn(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Column(
|
||||
children:
|
||||
_buildBodyColumnChildren(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildBodyColumnChildren({required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => [
|
||||
List<Widget> _buildBodyColumnChildren(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
[
|
||||
verticalSpaceMedium,
|
||||
_buildAppBar(context: context, viewModel: viewModel),
|
||||
verticalSpaceMedium,
|
||||
_buildBodyWrapper(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildAppBar({required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
||||
Widget _buildAppBar(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
SmallAppBar(
|
||||
title: 'Result',
|
||||
showBackButton: true,
|
||||
onTap: () async => await _showSheet(context: context,viewModel: viewModel),
|
||||
onTap: () async =>
|
||||
await _showSheet(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||
|
|
@ -148,6 +160,5 @@ class LearnPracticeResultScreen
|
|||
borderColor: kcPrimaryColor,
|
||||
foregroundColor: kcPrimaryColor,
|
||||
onTap: () => _navigate(viewModel),
|
||||
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
final int index;
|
||||
final LearnQuestion question;
|
||||
|
||||
const StartLearnPracticeScreen({super.key,required this.index,required this.question});
|
||||
const StartLearnPracticeScreen(
|
||||
{super.key, required this.index, required this.question});
|
||||
|
||||
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
|
||||
viewModel.pop();
|
||||
|
|
@ -39,37 +40,51 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||
|
||||
Widget _buildScaffoldWrapper( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Scaffold(
|
||||
Widget _buildScaffoldWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Scaffold(
|
||||
backgroundColor: kcBackgroundColor,
|
||||
body: _buildScaffold(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildScaffold( {required BuildContext context,
|
||||
Widget _buildScaffold(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
SafeArea(child: _buildBodyColumnWrapper(context: context,viewModel: viewModel));
|
||||
SafeArea(
|
||||
child:
|
||||
_buildBodyColumnWrapper(context: context, viewModel: viewModel));
|
||||
|
||||
Widget _buildBodyColumnWrapper( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Padding(
|
||||
Widget _buildBodyColumnWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: _buildBodyColumn(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
Widget _buildBodyColumn( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Column(
|
||||
Widget _buildBodyColumn(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: _buildBodyColumnChildren(context: context,viewModel: viewModel),
|
||||
children:
|
||||
_buildBodyColumnChildren(context: context, viewModel: viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildBodyColumnChildren( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => [
|
||||
List<Widget> _buildBodyColumnChildren(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
[
|
||||
_buildAppBarWrapper(context: context, viewModel: viewModel),
|
||||
_buildStartButtonWrapper(viewModel),
|
||||
_buildLowerButtonsSectionWrapper(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildAppBarWrapper( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => Column(
|
||||
Widget _buildAppBarWrapper(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
Column(
|
||||
children: [
|
||||
verticalSpaceMedium,
|
||||
_buildAppBar(context: context, viewModel: viewModel),
|
||||
|
|
@ -77,10 +92,13 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
],
|
||||
);
|
||||
|
||||
Widget _buildAppBar( {required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
||||
Widget _buildAppBar(
|
||||
{required BuildContext context,
|
||||
required LearnPracticeViewModel viewModel}) =>
|
||||
SmallAppBar(
|
||||
showBackButton: true,
|
||||
onTap: () async => await _showSheet(context: context,viewModel: viewModel),
|
||||
onTap: () async =>
|
||||
await _showSheet(context: context, viewModel: viewModel),
|
||||
title: 'Practice Speaking ($index/${viewModel.questions.length})');
|
||||
|
||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'package:stacked/stacked.dart';
|
|||
import 'package:stacked/stacked_annotations.dart';
|
||||
|
||||
import 'package:yimaru_app/ui/views/onboarding/screens/age_group_form_screen.dart';
|
||||
import 'package:yimaru_app/ui/views/onboarding/screens/birthday_form_screen.dart';
|
||||
import 'package:yimaru_app/ui/views/onboarding/screens/challenge_form_screen.dart';
|
||||
import 'package:yimaru_app/ui/views/onboarding/screens/country_region_form_screen.dart';
|
||||
import 'package:yimaru_app/ui/views/onboarding/screens/educational_background_form_screen.dart';
|
||||
|
|
@ -22,6 +21,7 @@ import 'onboarding_view.form.dart';
|
|||
FormTextField(name: 'topic', validator: FormValidator.validateForm),
|
||||
FormTextField(
|
||||
name: 'fullName', validator: FormValidator.validateFullNameForm),
|
||||
FormTextField(name: 'region', validator: FormValidator.validateForm),
|
||||
FormTextField(name: 'challenge', validator: FormValidator.validateForm),
|
||||
FormTextField(name: 'occupation', validator: FormValidator.validateForm),
|
||||
FormTextField(name: 'languageGoal', validator: FormValidator.validateForm),
|
||||
|
|
@ -50,25 +50,23 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
|||
} else if (viewModel.currentPage == 1) {
|
||||
viewModel.resetGenderFormScreen();
|
||||
} else if (viewModel.currentPage == 2) {
|
||||
viewModel.resetBirthdayFormScreen();
|
||||
} else if (viewModel.currentPage == 3) {
|
||||
viewModel.resetAgeGroupFormScreen();
|
||||
} else if (viewModel.currentPage == 4) {
|
||||
} else if (viewModel.currentPage == 3) {
|
||||
viewModel.resetEducationalBackgroundFormScreen();
|
||||
} else if (viewModel.currentPage == 5) {
|
||||
} else if (viewModel.currentPage == 4) {
|
||||
occupationController.clear();
|
||||
viewModel.resetOccupationFormScreen();
|
||||
} else if (viewModel.currentPage == 6) {
|
||||
} else if (viewModel.currentPage == 5) {
|
||||
viewModel.resetCountryRegionFormScreen();
|
||||
} else if (viewModel.currentPage == 7) {
|
||||
} else if (viewModel.currentPage == 6) {
|
||||
viewModel.resetLearningGoalFormScreen();
|
||||
} else if (viewModel.currentPage == 8) {
|
||||
} else if (viewModel.currentPage == 7) {
|
||||
languageGoalController.clear();
|
||||
viewModel.resetLanguageGoalFormScreen();
|
||||
} else if (viewModel.currentPage == 9) {
|
||||
} else if (viewModel.currentPage == 8) {
|
||||
challengeController.clear();
|
||||
viewModel.resetChallengeFormScreen();
|
||||
} else if (viewModel.currentPage == 10) {
|
||||
} else if (viewModel.currentPage == 9) {
|
||||
topicController.clear();
|
||||
viewModel.resetTopicFormScreen();
|
||||
}
|
||||
|
|
@ -117,7 +115,6 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
|||
List<Widget> _buildScreens() => [
|
||||
_buildFullNameForm(),
|
||||
_buildGenderForm(),
|
||||
_buildBirthdayForm(),
|
||||
_buildAgeGroupForm(),
|
||||
_buildEducationalBackgroundForm(),
|
||||
_buildOccupationForm(),
|
||||
|
|
@ -133,8 +130,6 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
|||
|
||||
Widget _buildGenderForm() => const GenderFormScreen();
|
||||
|
||||
Widget _buildBirthdayForm() => const BirthdayFormScreen();
|
||||
|
||||
Widget _buildAgeGroupForm() => const AgeGroupFormScreen();
|
||||
|
||||
Widget _buildEducationalBackgroundForm() =>
|
||||
|
|
@ -143,7 +138,9 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
|||
Widget _buildOccupationForm() =>
|
||||
OccupationFormScreen(occupationController: occupationController);
|
||||
|
||||
Widget _buildCountryRegionForm() => const CountryRegionFormScreen();
|
||||
Widget _buildCountryRegionForm() => CountryRegionFormScreen(
|
||||
regionController: regionController,
|
||||
);
|
||||
|
||||
Widget _buildLearningGoalForm() => const LearningGoalFormScreen();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const bool _autoTextFieldValidation = true;
|
|||
|
||||
const String TopicValueKey = 'topic';
|
||||
const String FullNameValueKey = 'fullName';
|
||||
const String RegionValueKey = 'region';
|
||||
const String ChallengeValueKey = 'challenge';
|
||||
const String OccupationValueKey = 'occupation';
|
||||
const String LanguageGoalValueKey = 'languageGoal';
|
||||
|
|
@ -27,6 +28,7 @@ final Map<String, FocusNode> _OnboardingViewFocusNodes = {};
|
|||
final Map<String, String? Function(String?)?> _OnboardingViewTextValidations = {
|
||||
TopicValueKey: FormValidator.validateForm,
|
||||
FullNameValueKey: FormValidator.validateFullNameForm,
|
||||
RegionValueKey: FormValidator.validateForm,
|
||||
ChallengeValueKey: FormValidator.validateForm,
|
||||
OccupationValueKey: FormValidator.validateForm,
|
||||
LanguageGoalValueKey: FormValidator.validateForm,
|
||||
|
|
@ -37,6 +39,8 @@ mixin $OnboardingView {
|
|||
_getFormTextEditingController(TopicValueKey);
|
||||
TextEditingController get fullNameController =>
|
||||
_getFormTextEditingController(FullNameValueKey);
|
||||
TextEditingController get regionController =>
|
||||
_getFormTextEditingController(RegionValueKey);
|
||||
TextEditingController get challengeController =>
|
||||
_getFormTextEditingController(ChallengeValueKey);
|
||||
TextEditingController get occupationController =>
|
||||
|
|
@ -46,6 +50,7 @@ mixin $OnboardingView {
|
|||
|
||||
FocusNode get topicFocusNode => _getFormFocusNode(TopicValueKey);
|
||||
FocusNode get fullNameFocusNode => _getFormFocusNode(FullNameValueKey);
|
||||
FocusNode get regionFocusNode => _getFormFocusNode(RegionValueKey);
|
||||
FocusNode get challengeFocusNode => _getFormFocusNode(ChallengeValueKey);
|
||||
FocusNode get occupationFocusNode => _getFormFocusNode(OccupationValueKey);
|
||||
FocusNode get languageGoalFocusNode =>
|
||||
|
|
@ -77,6 +82,7 @@ mixin $OnboardingView {
|
|||
void syncFormWithViewModel(FormStateHelper model) {
|
||||
topicController.addListener(() => _updateFormData(model));
|
||||
fullNameController.addListener(() => _updateFormData(model));
|
||||
regionController.addListener(() => _updateFormData(model));
|
||||
challengeController.addListener(() => _updateFormData(model));
|
||||
occupationController.addListener(() => _updateFormData(model));
|
||||
languageGoalController.addListener(() => _updateFormData(model));
|
||||
|
|
@ -93,6 +99,7 @@ mixin $OnboardingView {
|
|||
void listenToFormUpdated(FormViewModel model) {
|
||||
topicController.addListener(() => _updateFormData(model));
|
||||
fullNameController.addListener(() => _updateFormData(model));
|
||||
regionController.addListener(() => _updateFormData(model));
|
||||
challengeController.addListener(() => _updateFormData(model));
|
||||
occupationController.addListener(() => _updateFormData(model));
|
||||
languageGoalController.addListener(() => _updateFormData(model));
|
||||
|
|
@ -107,6 +114,7 @@ mixin $OnboardingView {
|
|||
..addAll({
|
||||
TopicValueKey: topicController.text,
|
||||
FullNameValueKey: fullNameController.text,
|
||||
RegionValueKey: regionController.text,
|
||||
ChallengeValueKey: challengeController.text,
|
||||
OccupationValueKey: occupationController.text,
|
||||
LanguageGoalValueKey: languageGoalController.text,
|
||||
|
|
@ -153,6 +161,7 @@ extension ValueProperties on FormStateHelper {
|
|||
|
||||
String? get topicValue => this.formValueMap[TopicValueKey] as String?;
|
||||
String? get fullNameValue => this.formValueMap[FullNameValueKey] as String?;
|
||||
String? get regionValue => this.formValueMap[RegionValueKey] as String?;
|
||||
String? get challengeValue => this.formValueMap[ChallengeValueKey] as String?;
|
||||
String? get occupationValue =>
|
||||
this.formValueMap[OccupationValueKey] as String?;
|
||||
|
|
@ -180,6 +189,16 @@ extension ValueProperties on FormStateHelper {
|
|||
}
|
||||
}
|
||||
|
||||
set regionValue(String? value) {
|
||||
this.setData(
|
||||
this.formValueMap..addAll({RegionValueKey: value}),
|
||||
);
|
||||
|
||||
if (_OnboardingViewTextEditingControllers.containsKey(RegionValueKey)) {
|
||||
_OnboardingViewTextEditingControllers[RegionValueKey]?.text = value ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
set challengeValue(String? value) {
|
||||
this.setData(
|
||||
this.formValueMap..addAll({ChallengeValueKey: value}),
|
||||
|
|
@ -220,6 +239,9 @@ extension ValueProperties on FormStateHelper {
|
|||
bool get hasFullName =>
|
||||
this.formValueMap.containsKey(FullNameValueKey) &&
|
||||
(fullNameValue?.isNotEmpty ?? false);
|
||||
bool get hasRegion =>
|
||||
this.formValueMap.containsKey(RegionValueKey) &&
|
||||
(regionValue?.isNotEmpty ?? false);
|
||||
bool get hasChallenge =>
|
||||
this.formValueMap.containsKey(ChallengeValueKey) &&
|
||||
(challengeValue?.isNotEmpty ?? false);
|
||||
|
|
@ -234,6 +256,8 @@ extension ValueProperties on FormStateHelper {
|
|||
this.fieldsValidationMessages[TopicValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasFullNameValidationMessage =>
|
||||
this.fieldsValidationMessages[FullNameValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasRegionValidationMessage =>
|
||||
this.fieldsValidationMessages[RegionValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasChallengeValidationMessage =>
|
||||
this.fieldsValidationMessages[ChallengeValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasOccupationValidationMessage =>
|
||||
|
|
@ -245,6 +269,8 @@ extension ValueProperties on FormStateHelper {
|
|||
this.fieldsValidationMessages[TopicValueKey];
|
||||
String? get fullNameValidationMessage =>
|
||||
this.fieldsValidationMessages[FullNameValueKey];
|
||||
String? get regionValidationMessage =>
|
||||
this.fieldsValidationMessages[RegionValueKey];
|
||||
String? get challengeValidationMessage =>
|
||||
this.fieldsValidationMessages[ChallengeValueKey];
|
||||
String? get occupationValidationMessage =>
|
||||
|
|
@ -258,6 +284,8 @@ extension Methods on FormStateHelper {
|
|||
this.fieldsValidationMessages[TopicValueKey] = validationMessage;
|
||||
void setFullNameValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[FullNameValueKey] = validationMessage;
|
||||
void setRegionValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[RegionValueKey] = validationMessage;
|
||||
void setChallengeValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[ChallengeValueKey] = validationMessage;
|
||||
void setOccupationValidationMessage(String? validationMessage) =>
|
||||
|
|
@ -269,6 +297,7 @@ extension Methods on FormStateHelper {
|
|||
void clearForm() {
|
||||
topicValue = '';
|
||||
fullNameValue = '';
|
||||
regionValue = '';
|
||||
challengeValue = '';
|
||||
occupationValue = '';
|
||||
languageGoalValue = '';
|
||||
|
|
@ -279,6 +308,7 @@ extension Methods on FormStateHelper {
|
|||
this.setValidationMessages({
|
||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
||||
|
|
@ -303,6 +333,7 @@ void updateValidationData(FormStateHelper model) =>
|
|||
model.setValidationMessages({
|
||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
||||
|
|
|
|||
|
|
@ -63,11 +63,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
|||
|
||||
String? get selectedGender => _selectedGender;
|
||||
|
||||
// Birthday
|
||||
String? _selectedBirthday;
|
||||
|
||||
String? get selectedBirthday => _selectedBirthday;
|
||||
|
||||
// Age group
|
||||
final List<Map<String, dynamic>> _ageGroups = [
|
||||
{
|
||||
|
|
@ -105,10 +100,10 @@ class OnboardingViewModel extends ReactiveViewModel
|
|||
|
||||
String get selectedCountry => _selectedCountry;
|
||||
|
||||
// Country
|
||||
String _selectedRegion = 'Addis Ababa';
|
||||
// Region
|
||||
bool _focusRegion = false;
|
||||
|
||||
String get selectedRegion => _selectedRegion;
|
||||
bool get focusRegion => _focusRegion;
|
||||
|
||||
// Learning goal
|
||||
String? _selectedLearningGoal;
|
||||
|
|
@ -247,12 +242,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
|||
|
||||
bool isSelectedGender(String value) => _selectedGender == value;
|
||||
|
||||
// Birthday
|
||||
void setBirthday(String value) {
|
||||
_selectedBirthday = value;
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
// Age group
|
||||
void setSelectedAgeGroup(Map<String, dynamic> value) {
|
||||
_selectedAgeGroup = value;
|
||||
|
|
@ -270,44 +259,168 @@ class OnboardingViewModel extends ReactiveViewModel
|
|||
}
|
||||
|
||||
// Country
|
||||
List<String> getCountries() => ['Ethiopia', 'Other'];
|
||||
List<String> getCountries() => [
|
||||
"Afghanistan",
|
||||
"Albania",
|
||||
"Algeria",
|
||||
"Andorra",
|
||||
"Angola",
|
||||
"Argentina",
|
||||
"Armenia",
|
||||
"Australia",
|
||||
"Austria",
|
||||
"Azerbaijan",
|
||||
"Bahrain",
|
||||
"Bangladesh",
|
||||
"Belarus",
|
||||
"Belgium",
|
||||
"Belize",
|
||||
"Benin",
|
||||
"Bhutan",
|
||||
"Bolivia",
|
||||
"Bosnia and Herzegovina",
|
||||
"Botswana",
|
||||
"Brazil",
|
||||
"Brunei",
|
||||
"Bulgaria",
|
||||
"Burkina Faso",
|
||||
"Burundi",
|
||||
"Cambodia",
|
||||
"Cameroon",
|
||||
"Canada",
|
||||
"Chad",
|
||||
"Chile",
|
||||
"China",
|
||||
"Colombia",
|
||||
"Comoros",
|
||||
"Congo",
|
||||
"Costa Rica",
|
||||
"Croatia",
|
||||
"Cuba",
|
||||
"Cyprus",
|
||||
"Czech Republic",
|
||||
"Denmark",
|
||||
"Djibouti",
|
||||
"Dominican Republic",
|
||||
"Ecuador",
|
||||
"Egypt",
|
||||
"El Salvador",
|
||||
"Eritrea",
|
||||
"Estonia",
|
||||
"Eswatini",
|
||||
"Ethiopia",
|
||||
"Finland",
|
||||
"France",
|
||||
"Gabon",
|
||||
"Gambia",
|
||||
"Georgia",
|
||||
"Germany",
|
||||
"Ghana",
|
||||
"Greece",
|
||||
"Guatemala",
|
||||
"Guinea",
|
||||
"Haiti",
|
||||
"Honduras",
|
||||
"Hungary",
|
||||
"Iceland",
|
||||
"India",
|
||||
"Indonesia",
|
||||
"Iran",
|
||||
"Iraq",
|
||||
"Ireland",
|
||||
"Israel",
|
||||
"Italy",
|
||||
"Jamaica",
|
||||
"Japan",
|
||||
"Jordan",
|
||||
"Kazakhstan",
|
||||
"Kenya",
|
||||
"Kuwait",
|
||||
"Kyrgyzstan",
|
||||
"Laos",
|
||||
"Latvia",
|
||||
"Lebanon",
|
||||
"Liberia",
|
||||
"Libya",
|
||||
"Lithuania",
|
||||
"Luxembourg",
|
||||
"Madagascar",
|
||||
"Malawi",
|
||||
"Malaysia",
|
||||
"Maldives",
|
||||
"Mali",
|
||||
"Malta",
|
||||
"Mexico",
|
||||
"Moldova",
|
||||
"Monaco",
|
||||
"Mongolia",
|
||||
"Morocco",
|
||||
"Mozambique",
|
||||
"Myanmar",
|
||||
"Namibia",
|
||||
"Nepal",
|
||||
"Netherlands",
|
||||
"New Zealand",
|
||||
"Nicaragua",
|
||||
"Niger",
|
||||
"Nigeria",
|
||||
"North Korea",
|
||||
"Norway",
|
||||
"Oman",
|
||||
"Pakistan",
|
||||
"Panama",
|
||||
"Paraguay",
|
||||
"Peru",
|
||||
"Philippines",
|
||||
"Poland",
|
||||
"Portugal",
|
||||
"Qatar",
|
||||
"Romania",
|
||||
"Russia",
|
||||
"Rwanda",
|
||||
"Saudi Arabia",
|
||||
"Senegal",
|
||||
"Serbia",
|
||||
"Singapore",
|
||||
"Slovakia",
|
||||
"Slovenia",
|
||||
"Somalia",
|
||||
"South Africa",
|
||||
"South Korea",
|
||||
"Spain",
|
||||
"Sri Lanka",
|
||||
"Sudan",
|
||||
"Sweden",
|
||||
"Switzerland",
|
||||
"Syria",
|
||||
"Taiwan",
|
||||
"Tajikistan",
|
||||
"Tanzania",
|
||||
"Thailand",
|
||||
"Tunisia",
|
||||
"Turkey",
|
||||
"Uganda",
|
||||
"Ukraine",
|
||||
"United Arab Emirates",
|
||||
"United Kingdom",
|
||||
"United States",
|
||||
"Uruguay",
|
||||
"Uzbekistan",
|
||||
"Venezuela",
|
||||
"Vietnam",
|
||||
"Yemen",
|
||||
"Zambia",
|
||||
"Zimbabwe"
|
||||
];
|
||||
|
||||
void setSelectedCountry(String value) {
|
||||
_selectedCountry = value;
|
||||
if (selectedCountry != 'Ethiopia') {
|
||||
_selectedRegion = 'Other';
|
||||
} else {
|
||||
_selectedRegion = 'Addis Ababa';
|
||||
}
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
// Region
|
||||
List<String> getRegions(String country) {
|
||||
if (country == 'Ethiopia') {
|
||||
return [
|
||||
'Afar',
|
||||
'SNNPR',
|
||||
'Amhara',
|
||||
'Harari',
|
||||
'Oromia',
|
||||
'Sidama',
|
||||
'Somali',
|
||||
'Tigray',
|
||||
'Gambela',
|
||||
'Dire Dawa',
|
||||
'Addis Ababa',
|
||||
'Central Ethiopia',
|
||||
'Benishangul-Gumuz',
|
||||
'South West Ethiopia',
|
||||
];
|
||||
} else {
|
||||
return ['Other'];
|
||||
}
|
||||
}
|
||||
|
||||
void setSelectedRegion(String value) {
|
||||
_selectedRegion = value;
|
||||
void setRegionFocus() {
|
||||
_focusRegion = true;
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
|
|
@ -414,12 +527,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
|||
rebuildUi();
|
||||
}
|
||||
|
||||
// Reset birthday form screen
|
||||
void resetBirthdayFormScreen() {
|
||||
_selectedBirthday = null;
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
// Reset age group form screen
|
||||
void resetAgeGroupFormScreen() {
|
||||
_selectedAgeGroup = null;
|
||||
|
|
@ -441,7 +548,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
|||
// Reset country region form screen
|
||||
void resetCountryRegionFormScreen() {
|
||||
_selectedCountry = 'Ethiopia';
|
||||
_selectedRegion = 'Addis Ababa';
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,122 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:stacked/stacked.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_elevated_button.dart';
|
||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||
|
||||
import '../../../widgets/birthday_selector.dart';
|
||||
|
||||
class BirthdayFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||
const BirthdayFormScreen({super.key});
|
||||
|
||||
void _pop(OnboardingViewModel viewModel) {
|
||||
viewModel.resetBirthdayFormScreen();
|
||||
|
||||
viewModel.goBack();
|
||||
}
|
||||
|
||||
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
|
||||
Map<String, dynamic> data = {'birth_day': viewModel.selectedBirthday};
|
||||
viewModel.addUserData(data);
|
||||
viewModel.next();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||
_buildScaffoldWrapper(viewModel);
|
||||
|
||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
||||
backgroundColor: kcBackgroundColor,
|
||||
body: _buildScaffold(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _buildScaffoldChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [
|
||||
_buildAppBar(viewModel),
|
||||
verticalSpaceMedium,
|
||||
_buildExpandedBody(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
||||
Expanded(child: _buildBodyWrapper(viewModel));
|
||||
|
||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: _buildBody(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: _buildBodyChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
||||
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
||||
|
||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _buildUpperColumnChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
||||
verticalSpaceMedium,
|
||||
_buildTitle(),
|
||||
verticalSpaceSmall,
|
||||
_buildSubtitle(),
|
||||
verticalSpaceMedium,
|
||||
_buildBirthdayFormField(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||
showBackButton: true,
|
||||
showLanguageSelection: true,
|
||||
onPop: () => _pop(viewModel),
|
||||
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||
);
|
||||
|
||||
Widget _buildTitle() => Text(
|
||||
'Pick your birthday?',
|
||||
style: style25DG600,
|
||||
);
|
||||
|
||||
Widget _buildSubtitle() => Text(
|
||||
'We’ll personalize your learning experience based on your birthday.',
|
||||
style: style14MG400,
|
||||
);
|
||||
|
||||
Widget _buildBirthdayFormField(OnboardingViewModel viewModel) =>
|
||||
BirthdaySelector(
|
||||
birthday: viewModel.selectedBirthday,
|
||||
onSelected: (value) =>
|
||||
viewModel.setBirthday(DateFormat('yyyy-MM-dd').format(value)),
|
||||
);
|
||||
|
||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
||||
padding: const EdgeInsets.only(bottom: 50),
|
||||
child: _buildContinueButton(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
||||
CustomElevatedButton(
|
||||
height: 55,
|
||||
text: 'Continue',
|
||||
borderRadius: 12,
|
||||
foregroundColor: kcWhite,
|
||||
backgroundColor: viewModel.selectedBirthday != null
|
||||
? kcPrimaryColor
|
||||
: kcPrimaryColor.withOpacity(0.1),
|
||||
onTap:
|
||||
viewModel.selectedBirthday != null ? () => _next(viewModel) : null,
|
||||
);
|
||||
}
|
||||
|
|
@ -6,9 +6,11 @@ import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
|||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||
import 'package:yimaru_app/ui/widgets/custom_dropdown.dart';
|
||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||
import '../onboarding_view.form.dart';
|
||||
|
||||
class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||
const CountryRegionFormScreen({super.key});
|
||||
final TextEditingController regionController;
|
||||
const CountryRegionFormScreen({super.key, required this.regionController});
|
||||
|
||||
void _pop(OnboardingViewModel viewModel) {
|
||||
viewModel.resetCountryRegionFormScreen();
|
||||
|
|
@ -19,8 +21,8 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
|||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
|
||||
Map<String, dynamic> data = {
|
||||
'region': regionController.text,
|
||||
'country': viewModel.selectedCountry,
|
||||
'region': viewModel.selectedRegion
|
||||
};
|
||||
viewModel.addUserData(data);
|
||||
|
||||
|
|
@ -83,8 +85,11 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
|||
verticalSpaceMedium,
|
||||
_buildCountryDropDown(viewModel),
|
||||
verticalSpaceMedium,
|
||||
_buildRegionDropDown(viewModel),
|
||||
verticalSpaceMedium,
|
||||
_buildRegionFormField(viewModel),
|
||||
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||
verticalSpaceTiny,
|
||||
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||
_buildRegionValidatorWrapper(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||
|
|
@ -112,16 +117,23 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
|||
items: (value, props) => viewModel.getCountries(),
|
||||
onChanged: (value) =>
|
||||
viewModel.setSelectedCountry(value ?? 'Ethiopia'));
|
||||
Widget _buildRegionFormField(OnboardingViewModel viewModel) => TextFormField(
|
||||
controller: regionController,
|
||||
onTap: viewModel.setRegionFocus,
|
||||
decoration: inputDecoration(
|
||||
hint: 'Enter Your City',
|
||||
focus: viewModel.focusRegion,
|
||||
filled: regionController.text.isNotEmpty),
|
||||
);
|
||||
|
||||
Widget _buildRegionDropDown(OnboardingViewModel viewModel) =>
|
||||
CustomDropdownPicker(
|
||||
hint: 'Select region',
|
||||
icon: _buildSearchIcon(),
|
||||
selectedItem: viewModel.selectedRegion,
|
||||
items: (value, props) =>
|
||||
viewModel.getRegions(viewModel.selectedCountry),
|
||||
onChanged: (value) =>
|
||||
viewModel.setSelectedRegion(value ?? 'Addis Ababa'),
|
||||
Widget _buildRegionValidatorWrapper(OnboardingViewModel viewModel) =>
|
||||
viewModel.hasRegionValidationMessage
|
||||
? _buildRegionValidator(viewModel)
|
||||
: Container();
|
||||
|
||||
Widget _buildRegionValidator(OnboardingViewModel viewModel) => Text(
|
||||
viewModel.regionValidationMessage!,
|
||||
style: style12R700,
|
||||
);
|
||||
|
||||
Icon _buildSearchIcon() => const Icon(
|
||||
|
|
@ -140,7 +152,9 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
|||
text: 'Continue',
|
||||
borderRadius: 12,
|
||||
foregroundColor: kcWhite,
|
||||
onTap: () => _next(viewModel),
|
||||
backgroundColor: kcPrimaryColor,
|
||||
onTap: regionController.text.isNotEmpty ? () => _next(viewModel) : null,
|
||||
backgroundColor: regionController.text.isNotEmpty
|
||||
? kcPrimaryColor
|
||||
: kcPrimaryColor.withOpacity(0.1),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||
|
|
@ -25,6 +26,7 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
|||
Map<String, dynamic> data = {
|
||||
'profile_completed': true,
|
||||
'preferred_language': 'en',
|
||||
'birth_day': DateFormat('yyyy-MM-dd').format(DateTime.now()),
|
||||
'favoutite_topic': viewModel.selectedTopic ?? topicController.text,
|
||||
};
|
||||
viewModel.addUserData(data);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import 'package:flutter/services.dart';
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
import 'package:stacked/stacked_annotations.dart';
|
||||
import 'package:yimaru_app/ui/widgets/birthday_selector.dart';
|
||||
import 'package:yimaru_app/ui/widgets/custom_form_label.dart';
|
||||
import 'package:yimaru_app/ui/widgets/small_app_bar.dart';
|
||||
|
||||
|
|
@ -22,6 +21,7 @@ import 'profile_detail_view.form.dart';
|
|||
|
||||
@FormView(fields: [
|
||||
FormTextField(name: 'email', validator: FormValidator.validateForm),
|
||||
FormTextField(name: 'region', validator: FormValidator.validateForm),
|
||||
FormTextField(
|
||||
name: 'phoneNumber', validator: FormValidator.validatePhoneNumberForm),
|
||||
FormTextField(name: 'lastName', validator: FormValidator.validateForm),
|
||||
|
|
@ -34,13 +34,13 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
|
||||
Future<void> _update(ProfileDetailViewModel viewModel) async {
|
||||
Map<String, dynamic> data = {
|
||||
'region': viewModel.selectedRegion,
|
||||
'region':regionController.text,
|
||||
'gender': viewModel.selectedGender,
|
||||
'last_name': lastNameController.text,
|
||||
'country': viewModel.selectedCountry,
|
||||
'first_name': firstNameController.text,
|
||||
'occupation': occupationController.text,
|
||||
'birth_day': viewModel.selectedBirthday,
|
||||
'birth_day': DateFormat('d MMM, yyyy').format(DateTime.now()),
|
||||
};
|
||||
|
||||
viewModel.addUserData(data);
|
||||
|
|
@ -68,15 +68,14 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
void _onModelReady(ProfileDetailViewModel viewModel) {
|
||||
phoneNumberController.text = '251900000000';
|
||||
emailController.text = viewModel.user?.email ?? '';
|
||||
regionController.text = viewModel.user?.region ?? '';
|
||||
lastNameController.text = viewModel.user?.lastName ?? '';
|
||||
firstNameController.text = viewModel.user?.firstName ?? '';
|
||||
occupationController.text = viewModel.user?.occupation ?? '';
|
||||
viewModel.clearUserData();
|
||||
viewModel.setGender(viewModel.user?.gender ?? '');
|
||||
viewModel.setSelectedCountry(viewModel.user?.country ?? 'Ethiopia');
|
||||
viewModel.setSelectedRegion(viewModel.user?.region ?? 'Addis Ababa');
|
||||
viewModel.setBirthday(viewModel.user?.birthday ??
|
||||
DateFormat('d MMM, yyyy').format(DateTime.now()));
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
@ -185,14 +184,17 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
verticalSpaceMedium,
|
||||
_buildGenderFormFieldWrapper(viewModel),
|
||||
verticalSpaceSmall,
|
||||
_buildBirthdayColumn(viewModel),
|
||||
verticalSpaceSmall,
|
||||
_buildPhoneNumberFormFieldSection(viewModel),
|
||||
verticalSpaceTiny,
|
||||
_buildEmailFormFieldSection(viewModel),
|
||||
verticalSpaceMedium,
|
||||
_buildCountryRegionSection(viewModel),
|
||||
_buildCountryDropdownLabel(),
|
||||
verticalSpaceSmall,
|
||||
_buildCountryDropdown(viewModel),
|
||||
verticalSpaceMedium,
|
||||
_buildRegionFormFieldWrapper(viewModel),
|
||||
verticalSpaceMedium,
|
||||
|
||||
_buildOccupationDropdownWrapper(viewModel),
|
||||
verticalSpaceLarge,
|
||||
_buildLowerColumn(viewModel)
|
||||
|
|
@ -415,30 +417,6 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
),
|
||||
);
|
||||
|
||||
Widget _buildBirthdayColumn(ProfileDetailViewModel viewModel) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _buildBirthdayChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildBirthdayChildren(ProfileDetailViewModel viewModel) => [
|
||||
_buildBirthdayLabel(),
|
||||
verticalSpaceSmall,
|
||||
_buildBirthdayFormField(viewModel),
|
||||
];
|
||||
|
||||
Widget _buildBirthdayLabel() => CustomFormLabel(
|
||||
label: 'Birthday',
|
||||
style: style16DG600,
|
||||
);
|
||||
|
||||
Widget _buildBirthdayFormField(ProfileDetailViewModel viewModel) =>
|
||||
BirthdaySelector(
|
||||
birthday: viewModel.selectedBirthday,
|
||||
onSelected: (value) =>
|
||||
viewModel.setBirthday(DateFormat('d MMM, yyyy').format(value)),
|
||||
);
|
||||
|
||||
Widget _buildPhoneNumberFormFieldSection(ProfileDetailViewModel viewModel) =>
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
|
@ -533,39 +511,6 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
style: validationStyle,
|
||||
);
|
||||
|
||||
Widget _buildCountryRegionSection(ProfileDetailViewModel viewModel) => Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: _buildCountryRegionChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildCountryRegionChildren(ProfileDetailViewModel viewModel) =>
|
||||
[
|
||||
_buildCountryDropdownColumnWrapper(viewModel),
|
||||
const SizedBox(width: 20),
|
||||
_buildRegionDropdownColumnWrapper(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildCountryDropdownColumnWrapper(ProfileDetailViewModel viewModel) =>
|
||||
Expanded(
|
||||
child: _buildCountryDropdownColumn(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildCountryDropdownColumn(ProfileDetailViewModel viewModel) =>
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: _buildCountryDropdownChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildCountryDropdownChildren(
|
||||
ProfileDetailViewModel viewModel) =>
|
||||
[
|
||||
_buildCountryDropdownLabel(),
|
||||
verticalSpaceSmall,
|
||||
_buildCountryDropdown(viewModel)
|
||||
];
|
||||
|
||||
Widget _buildCountryDropdownLabel() => CustomFormLabel(
|
||||
label: 'Country',
|
||||
style: style16DG600,
|
||||
|
|
@ -579,38 +524,48 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
|||
onChanged: (value) => viewModel.setSelectedCountry(value ?? 'Ethiopia'),
|
||||
);
|
||||
|
||||
Widget _buildRegionDropdownColumnWrapper(ProfileDetailViewModel viewModel) =>
|
||||
Expanded(
|
||||
child: _buildRegionDropdownColumn(viewModel),
|
||||
);
|
||||
|
||||
Widget _buildRegionDropdownColumn(ProfileDetailViewModel viewModel) => Column(
|
||||
Widget _buildRegionFormFieldWrapper(ProfileDetailViewModel viewModel) =>
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: _buildRegionDropdownChildren(viewModel),
|
||||
children: _buildRegionFormFieldChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildRegionDropdownChildren(ProfileDetailViewModel viewModel) =>
|
||||
List<Widget> _buildRegionFormFieldChildren(
|
||||
ProfileDetailViewModel viewModel) =>
|
||||
[
|
||||
_buildRegionDropdownLabel(),
|
||||
verticalSpaceSmall,
|
||||
_buildRegionDropdown(viewModel)
|
||||
_buildRegionFormFieldLabel(),verticalSpaceSmall,
|
||||
_buildRegionFormField(viewModel),
|
||||
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||
verticalSpaceTiny,
|
||||
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||
_buildRegionValidatorWrapper(viewModel),
|
||||
];
|
||||
|
||||
Widget _buildRegionDropdownLabel() => CustomFormLabel(
|
||||
Widget _buildRegionFormFieldLabel() => CustomFormLabel(
|
||||
label: 'Region',
|
||||
style: style16DG600,
|
||||
);
|
||||
|
||||
Widget _buildRegionDropdown(ProfileDetailViewModel viewModel) =>
|
||||
CustomDropdownPicker(
|
||||
hint: 'Select region',
|
||||
selectedItem: viewModel.selectedRegion,
|
||||
items: (value, props) =>
|
||||
viewModel.getRegions(viewModel.selectedCountry),
|
||||
onChanged: (value) =>
|
||||
viewModel.setSelectedRegion(value ?? 'Addis Ababa'),
|
||||
Widget _buildRegionFormField(ProfileDetailViewModel viewModel) =>
|
||||
TextFormField(
|
||||
controller: regionController,
|
||||
onTap: viewModel.setRegionFocus,
|
||||
decoration: inputDecoration(
|
||||
hint: 'Enter Your City',
|
||||
focus: viewModel.focusRegion,
|
||||
filled: regionController.text.isNotEmpty),
|
||||
);
|
||||
|
||||
Widget _buildRegionValidatorWrapper(ProfileDetailViewModel viewModel) =>
|
||||
viewModel.hasRegionValidationMessage
|
||||
? _buildRegionValidator(viewModel)
|
||||
: Container();
|
||||
|
||||
Widget _buildRegionValidator(ProfileDetailViewModel viewModel) => Text(
|
||||
viewModel.regionValidationMessage!,
|
||||
style: style12R700,
|
||||
);
|
||||
|
||||
Widget _buildOccupationDropdownWrapper(ProfileDetailViewModel viewModel) =>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import 'package:yimaru_app/ui/common/validators/form_validator.dart';
|
|||
const bool _autoTextFieldValidation = true;
|
||||
|
||||
const String EmailValueKey = 'email';
|
||||
const String RegionValueKey = 'region';
|
||||
const String PhoneNumberValueKey = 'phoneNumber';
|
||||
const String LastNameValueKey = 'lastName';
|
||||
const String FirstNameValueKey = 'firstName';
|
||||
|
|
@ -27,6 +28,7 @@ final Map<String, FocusNode> _ProfileDetailViewFocusNodes = {};
|
|||
final Map<String, String? Function(String?)?>
|
||||
_ProfileDetailViewTextValidations = {
|
||||
EmailValueKey: FormValidator.validateForm,
|
||||
RegionValueKey: FormValidator.validateForm,
|
||||
PhoneNumberValueKey: FormValidator.validatePhoneNumberForm,
|
||||
LastNameValueKey: FormValidator.validateForm,
|
||||
FirstNameValueKey: FormValidator.validateForm,
|
||||
|
|
@ -36,6 +38,8 @@ final Map<String, String? Function(String?)?>
|
|||
mixin $ProfileDetailView {
|
||||
TextEditingController get emailController =>
|
||||
_getFormTextEditingController(EmailValueKey);
|
||||
TextEditingController get regionController =>
|
||||
_getFormTextEditingController(RegionValueKey);
|
||||
TextEditingController get phoneNumberController =>
|
||||
_getFormTextEditingController(PhoneNumberValueKey);
|
||||
TextEditingController get lastNameController =>
|
||||
|
|
@ -46,6 +50,7 @@ mixin $ProfileDetailView {
|
|||
_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);
|
||||
|
|
@ -76,6 +81,7 @@ mixin $ProfileDetailView {
|
|||
/// with the latest textController values
|
||||
void syncFormWithViewModel(FormStateHelper model) {
|
||||
emailController.addListener(() => _updateFormData(model));
|
||||
regionController.addListener(() => _updateFormData(model));
|
||||
phoneNumberController.addListener(() => _updateFormData(model));
|
||||
lastNameController.addListener(() => _updateFormData(model));
|
||||
firstNameController.addListener(() => _updateFormData(model));
|
||||
|
|
@ -92,6 +98,7 @@ mixin $ProfileDetailView {
|
|||
)
|
||||
void listenToFormUpdated(FormViewModel model) {
|
||||
emailController.addListener(() => _updateFormData(model));
|
||||
regionController.addListener(() => _updateFormData(model));
|
||||
phoneNumberController.addListener(() => _updateFormData(model));
|
||||
lastNameController.addListener(() => _updateFormData(model));
|
||||
firstNameController.addListener(() => _updateFormData(model));
|
||||
|
|
@ -106,6 +113,7 @@ mixin $ProfileDetailView {
|
|||
model.formValueMap
|
||||
..addAll({
|
||||
EmailValueKey: emailController.text,
|
||||
RegionValueKey: regionController.text,
|
||||
PhoneNumberValueKey: phoneNumberController.text,
|
||||
LastNameValueKey: lastNameController.text,
|
||||
FirstNameValueKey: firstNameController.text,
|
||||
|
|
@ -152,6 +160,7 @@ extension ValueProperties on FormStateHelper {
|
|||
}
|
||||
|
||||
String? get emailValue => this.formValueMap[EmailValueKey] as String?;
|
||||
String? get regionValue => this.formValueMap[RegionValueKey] as String?;
|
||||
String? get phoneNumberValue =>
|
||||
this.formValueMap[PhoneNumberValueKey] as String?;
|
||||
String? get lastNameValue => this.formValueMap[LastNameValueKey] as String?;
|
||||
|
|
@ -170,6 +179,17 @@ extension ValueProperties on FormStateHelper {
|
|||
}
|
||||
}
|
||||
|
||||
set regionValue(String? value) {
|
||||
this.setData(
|
||||
this.formValueMap..addAll({RegionValueKey: value}),
|
||||
);
|
||||
|
||||
if (_ProfileDetailViewTextEditingControllers.containsKey(RegionValueKey)) {
|
||||
_ProfileDetailViewTextEditingControllers[RegionValueKey]?.text =
|
||||
value ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
set phoneNumberValue(String? value) {
|
||||
this.setData(
|
||||
this.formValueMap..addAll({PhoneNumberValueKey: value}),
|
||||
|
|
@ -221,6 +241,9 @@ extension ValueProperties on FormStateHelper {
|
|||
bool get hasEmail =>
|
||||
this.formValueMap.containsKey(EmailValueKey) &&
|
||||
(emailValue?.isNotEmpty ?? false);
|
||||
bool get hasRegion =>
|
||||
this.formValueMap.containsKey(RegionValueKey) &&
|
||||
(regionValue?.isNotEmpty ?? false);
|
||||
bool get hasPhoneNumber =>
|
||||
this.formValueMap.containsKey(PhoneNumberValueKey) &&
|
||||
(phoneNumberValue?.isNotEmpty ?? false);
|
||||
|
|
@ -236,6 +259,8 @@ extension ValueProperties on FormStateHelper {
|
|||
|
||||
bool get hasEmailValidationMessage =>
|
||||
this.fieldsValidationMessages[EmailValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasRegionValidationMessage =>
|
||||
this.fieldsValidationMessages[RegionValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasPhoneNumberValidationMessage =>
|
||||
this.fieldsValidationMessages[PhoneNumberValueKey]?.isNotEmpty ?? false;
|
||||
bool get hasLastNameValidationMessage =>
|
||||
|
|
@ -247,6 +272,8 @@ extension ValueProperties on FormStateHelper {
|
|||
|
||||
String? get emailValidationMessage =>
|
||||
this.fieldsValidationMessages[EmailValueKey];
|
||||
String? get regionValidationMessage =>
|
||||
this.fieldsValidationMessages[RegionValueKey];
|
||||
String? get phoneNumberValidationMessage =>
|
||||
this.fieldsValidationMessages[PhoneNumberValueKey];
|
||||
String? get lastNameValidationMessage =>
|
||||
|
|
@ -260,6 +287,8 @@ extension ValueProperties on FormStateHelper {
|
|||
extension Methods on FormStateHelper {
|
||||
void setEmailValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[EmailValueKey] = validationMessage;
|
||||
void setRegionValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[RegionValueKey] = validationMessage;
|
||||
void setPhoneNumberValidationMessage(String? validationMessage) =>
|
||||
this.fieldsValidationMessages[PhoneNumberValueKey] = validationMessage;
|
||||
void setLastNameValidationMessage(String? validationMessage) =>
|
||||
|
|
@ -272,6 +301,7 @@ extension Methods on FormStateHelper {
|
|||
/// Clears text input fields on the Form
|
||||
void clearForm() {
|
||||
emailValue = '';
|
||||
regionValue = '';
|
||||
phoneNumberValue = '';
|
||||
lastNameValue = '';
|
||||
firstNameValue = '';
|
||||
|
|
@ -282,6 +312,7 @@ extension Methods on FormStateHelper {
|
|||
void validateForm() {
|
||||
this.setValidationMessages({
|
||||
EmailValueKey: getValidationMessage(EmailValueKey),
|
||||
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
||||
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
||||
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
||||
|
|
@ -306,6 +337,7 @@ String? getValidationMessage(String key) {
|
|||
void updateValidationData(FormStateHelper model) =>
|
||||
model.setValidationMessages({
|
||||
EmailValueKey: getValidationMessage(EmailValueKey),
|
||||
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
||||
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
||||
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
||||
|
|
|
|||
|
|
@ -47,10 +47,6 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
|
||||
String? get selectedGender => _selectedGender;
|
||||
|
||||
// Birthday
|
||||
String? _selectedBirthday;
|
||||
|
||||
String? get selectedBirthday => _selectedBirthday;
|
||||
|
||||
// First name
|
||||
bool _focusPhoneNumber = false;
|
||||
|
|
@ -67,16 +63,17 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
|
||||
String get selectedCountry => _selectedCountry;
|
||||
|
||||
// Region
|
||||
String _selectedRegion = 'Addis Ababa';
|
||||
|
||||
String get selectedRegion => _selectedRegion;
|
||||
|
||||
// Occupation
|
||||
bool _focusOccupation = false;
|
||||
|
||||
bool get focusOccupation => _focusOccupation;
|
||||
|
||||
// Region
|
||||
bool _focusRegion = false;
|
||||
|
||||
bool get focusRegion => _focusRegion;
|
||||
|
||||
// User data
|
||||
final Map<String, dynamic> _userData = {};
|
||||
|
||||
|
|
@ -100,11 +97,6 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
rebuildUi();
|
||||
}
|
||||
|
||||
// Birthday
|
||||
void setBirthday(String value) {
|
||||
_selectedBirthday = value;
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
// Phone number
|
||||
void setPhoneNumberFocus() {
|
||||
|
|
@ -119,47 +111,168 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
}
|
||||
|
||||
// Country
|
||||
List<String> getCountries() => ['Ethiopia', 'Other'];
|
||||
// Country
|
||||
List<String> getCountries() => [
|
||||
"Afghanistan",
|
||||
"Albania",
|
||||
"Algeria",
|
||||
"Andorra",
|
||||
"Angola",
|
||||
"Argentina",
|
||||
"Armenia",
|
||||
"Australia",
|
||||
"Austria",
|
||||
"Azerbaijan",
|
||||
"Bahrain",
|
||||
"Bangladesh",
|
||||
"Belarus",
|
||||
"Belgium",
|
||||
"Belize",
|
||||
"Benin",
|
||||
"Bhutan",
|
||||
"Bolivia",
|
||||
"Bosnia and Herzegovina",
|
||||
"Botswana",
|
||||
"Brazil",
|
||||
"Brunei",
|
||||
"Bulgaria",
|
||||
"Burkina Faso",
|
||||
"Burundi",
|
||||
"Cambodia",
|
||||
"Cameroon",
|
||||
"Canada",
|
||||
"Chad",
|
||||
"Chile",
|
||||
"China",
|
||||
"Colombia",
|
||||
"Comoros",
|
||||
"Congo",
|
||||
"Costa Rica",
|
||||
"Croatia",
|
||||
"Cuba",
|
||||
"Cyprus",
|
||||
"Czech Republic",
|
||||
"Denmark",
|
||||
"Djibouti",
|
||||
"Dominican Republic",
|
||||
"Ecuador",
|
||||
"Egypt",
|
||||
"El Salvador",
|
||||
"Eritrea",
|
||||
"Estonia",
|
||||
"Eswatini",
|
||||
"Ethiopia",
|
||||
"Finland",
|
||||
"France",
|
||||
"Gabon",
|
||||
"Gambia",
|
||||
"Georgia",
|
||||
"Germany",
|
||||
"Ghana",
|
||||
"Greece",
|
||||
"Guatemala",
|
||||
"Guinea",
|
||||
"Haiti",
|
||||
"Honduras",
|
||||
"Hungary",
|
||||
"Iceland",
|
||||
"India",
|
||||
"Indonesia",
|
||||
"Iran",
|
||||
"Iraq",
|
||||
"Ireland",
|
||||
"Israel",
|
||||
"Italy",
|
||||
"Jamaica",
|
||||
"Japan",
|
||||
"Jordan",
|
||||
"Kazakhstan",
|
||||
"Kenya",
|
||||
"Kuwait",
|
||||
"Kyrgyzstan",
|
||||
"Laos",
|
||||
"Latvia",
|
||||
"Lebanon",
|
||||
"Liberia",
|
||||
"Libya",
|
||||
"Lithuania",
|
||||
"Luxembourg",
|
||||
"Madagascar",
|
||||
"Malawi",
|
||||
"Malaysia",
|
||||
"Maldives",
|
||||
"Mali",
|
||||
"Malta",
|
||||
"Mexico",
|
||||
"Moldova",
|
||||
"Monaco",
|
||||
"Mongolia",
|
||||
"Morocco",
|
||||
"Mozambique",
|
||||
"Myanmar",
|
||||
"Namibia",
|
||||
"Nepal",
|
||||
"Netherlands",
|
||||
"New Zealand",
|
||||
"Nicaragua",
|
||||
"Niger",
|
||||
"Nigeria",
|
||||
"North Korea",
|
||||
"Norway",
|
||||
"Oman",
|
||||
"Pakistan",
|
||||
"Panama",
|
||||
"Paraguay",
|
||||
"Peru",
|
||||
"Philippines",
|
||||
"Poland",
|
||||
"Portugal",
|
||||
"Qatar",
|
||||
"Romania",
|
||||
"Russia",
|
||||
"Rwanda",
|
||||
"Saudi Arabia",
|
||||
"Senegal",
|
||||
"Serbia",
|
||||
"Singapore",
|
||||
"Slovakia",
|
||||
"Slovenia",
|
||||
"Somalia",
|
||||
"South Africa",
|
||||
"South Korea",
|
||||
"Spain",
|
||||
"Sri Lanka",
|
||||
"Sudan",
|
||||
"Sweden",
|
||||
"Switzerland",
|
||||
"Syria",
|
||||
"Taiwan",
|
||||
"Tajikistan",
|
||||
"Tanzania",
|
||||
"Thailand",
|
||||
"Tunisia",
|
||||
"Turkey",
|
||||
"Uganda",
|
||||
"Ukraine",
|
||||
"United Arab Emirates",
|
||||
"United Kingdom",
|
||||
"United States",
|
||||
"Uruguay",
|
||||
"Uzbekistan",
|
||||
"Venezuela",
|
||||
"Vietnam",
|
||||
"Yemen",
|
||||
"Zambia",
|
||||
"Zimbabwe"
|
||||
];
|
||||
|
||||
void setSelectedCountry(String value) {
|
||||
_selectedCountry = value;
|
||||
if (selectedCountry != 'Ethiopia') {
|
||||
_selectedRegion = 'Other';
|
||||
} else {
|
||||
_selectedRegion = 'Addis Ababa';
|
||||
}
|
||||
|
||||
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
// Region
|
||||
List<String> getRegions(String country) {
|
||||
if (country == 'Ethiopia') {
|
||||
return [
|
||||
'Afar',
|
||||
'SNNPR',
|
||||
'Amhara',
|
||||
'Harari',
|
||||
'Oromia',
|
||||
'Sidama',
|
||||
'Somali',
|
||||
'Tigray',
|
||||
'Gambela',
|
||||
'Dire Dawa',
|
||||
'Addis Ababa',
|
||||
'Central Ethiopia',
|
||||
'Benishangul-Gumuz',
|
||||
'South West Ethiopia',
|
||||
];
|
||||
} else {
|
||||
return ['Other'];
|
||||
}
|
||||
}
|
||||
|
||||
void setSelectedRegion(String value) {
|
||||
_selectedRegion = value;
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
// Occupation
|
||||
void setOccupationFocus() {
|
||||
|
|
@ -167,6 +280,12 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
|||
rebuildUi();
|
||||
}
|
||||
|
||||
// Region
|
||||
void setRegionFocus() {
|
||||
_focusRegion = true;
|
||||
rebuildUi();
|
||||
}
|
||||
|
||||
// User data
|
||||
void addUserData(Map<String, dynamic> data) {
|
||||
_userData.addAll(data);
|
||||
|
|
|
|||
|
|
@ -1,103 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import '../common/app_colors.dart';
|
||||
import '../common/ui_helpers.dart';
|
||||
import 'package:omni_datetime_picker/omni_datetime_picker.dart';
|
||||
|
||||
class BirthdaySelector extends StatelessWidget {
|
||||
final String? birthday;
|
||||
final void Function(DateTime)? onSelected;
|
||||
|
||||
const BirthdaySelector({super.key, this.birthday, this.onSelected});
|
||||
|
||||
DateTime _initialDate() {
|
||||
try {
|
||||
final parsedDate = format.parse(birthday ?? '');
|
||||
return parsedDate.isAfter(DateTime.now()) ? DateTime.now() : parsedDate;
|
||||
} catch (_) {
|
||||
return DateTime.now();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pickDateTime(
|
||||
BuildContext context,
|
||||
) async {
|
||||
DateTime? dateTime = await showOmniDateTimePicker(
|
||||
context: context,
|
||||
is24HourMode: false,
|
||||
isShowSeconds: false,
|
||||
title: _buildTitle(),
|
||||
lastDate: DateTime.now(),
|
||||
firstDate: DateTime(1900),
|
||||
barrierDismissible: true,
|
||||
initialDate: _initialDate(),
|
||||
titleSeparator: const Divider(),
|
||||
padding: const EdgeInsets.all(16),
|
||||
type: OmniDateTimePickerType.date,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
||||
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 24),
|
||||
theme: ThemeData(
|
||||
colorScheme:
|
||||
const ColorScheme.light().copyWith(primary: kcPrimaryColor),
|
||||
),
|
||||
);
|
||||
|
||||
if (dateTime != null) {
|
||||
// String formattedDateTime = DateFormat('d MMM, yyyy').format(dateTime);
|
||||
|
||||
if (onSelected != null) {
|
||||
onSelected!(dateTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(
|
||||
BuildContext context,
|
||||
) =>
|
||||
_buildButtonWrapper(
|
||||
context,
|
||||
);
|
||||
|
||||
Widget _buildButtonWrapper(BuildContext context) => Container(
|
||||
height: 50,
|
||||
width: double.maxFinite,
|
||||
margin: const EdgeInsets.only(bottom: 15),
|
||||
child: _buildContainerWrapper(context),
|
||||
);
|
||||
|
||||
Widget _buildContainerWrapper(BuildContext context) => GestureDetector(
|
||||
onTap: () async => await _pickDateTime(
|
||||
context,
|
||||
),
|
||||
child: _buildContainer(),
|
||||
);
|
||||
|
||||
Widget _buildTitle() => Text('Birthday', style: style16DG600);
|
||||
|
||||
Widget _buildContainer() => Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
color: kcPrimaryColor.withOpacity(0.1),
|
||||
border: Border.all(color: kcPrimaryColor),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: _buildButtonRowWrapper(),
|
||||
);
|
||||
|
||||
Widget _buildButtonRowWrapper() => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: _buildButtonRowChildren(),
|
||||
);
|
||||
|
||||
List<Widget> _buildButtonRowChildren() => [_buildText(), _buildIcon()];
|
||||
|
||||
Widget _buildText() => Text(
|
||||
birthday ?? 'Pick birthday',
|
||||
style: const TextStyle(color: kcDarkGrey),
|
||||
);
|
||||
|
||||
Widget _buildIcon() => const Icon(
|
||||
Icons.calendar_month,
|
||||
color: kcPrimaryColor,
|
||||
);
|
||||
}
|
||||
|
|
@ -15,14 +15,16 @@ class CancelLearnPracticeSheet extends StatelessWidget {
|
|||
final GestureTapCallback? onContinue;
|
||||
|
||||
const CancelLearnPracticeSheet(
|
||||
{super.key, this.onClose, this.onCancel, this.onContinue,required this.user});
|
||||
{super.key,
|
||||
this.onClose,
|
||||
this.onCancel,
|
||||
this.onContinue,
|
||||
required this.user});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) =>
|
||||
_buildSheetWrapper();
|
||||
Widget build(BuildContext context) => _buildSheetWrapper();
|
||||
|
||||
Widget _buildSheetWrapper() =>
|
||||
CustomBottomSheet(
|
||||
Widget _buildSheetWrapper() => CustomBottomSheet(
|
||||
height: 500, onTap: onClose, child: _buildColumnWrapper());
|
||||
|
||||
Widget _buildColumnWrapper() => Padding(
|
||||
|
|
|
|||
|
|
@ -29,11 +29,8 @@ class LearnPracticeResultsWrapper
|
|||
children: _buildColumnChildren(viewModel),
|
||||
);
|
||||
|
||||
List<Widget> _buildColumnChildren(LearnPracticeViewModel viewModel) => [
|
||||
_buildTitle(),
|
||||
verticalSpaceSmall,
|
||||
_buildResults(viewModel)
|
||||
];
|
||||
List<Widget> _buildColumnChildren(LearnPracticeViewModel viewModel) =>
|
||||
[_buildTitle(), verticalSpaceSmall, _buildResults(viewModel)];
|
||||
|
||||
Widget _buildTitle() => Text(
|
||||
'Conversation Review',
|
||||
|
|
@ -49,7 +46,7 @@ class LearnPracticeResultsWrapper
|
|||
itemBuilder: (context, index) => _buildResult(viewModel.answers[index]),
|
||||
);
|
||||
|
||||
|
||||
|
||||
Widget _buildResult(Map<String,dynamic> answer) => LearnPracticeResultCard(answer: answer,);
|
||||
Widget _buildResult(Map<String, dynamic> answer) => LearnPracticeResultCard(
|
||||
answer: answer,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,8 @@ class LearnPracticeTipSection extends ViewModelWidget<LearnPracticeViewModel> {
|
|||
const LearnPracticeTipSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context,LearnPracticeViewModel viewModel) => _buildContainer(viewModel);
|
||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||
_buildContainer(viewModel);
|
||||
|
||||
Widget _buildContainer(LearnPracticeViewModel viewModel) => Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name: yimaru_app
|
||||
version: 0.1.4+6
|
||||
version: 0.1.5+7
|
||||
publish_to: 'none'
|
||||
description: A new Flutter project.
|
||||
|
||||
|
|
|
|||
|
|
@ -1992,6 +1992,13 @@ class MockVoiceRecorderService extends _i1.Mock
|
|||
),
|
||||
) as _i5.WaveformRecorderController);
|
||||
|
||||
@override
|
||||
bool get isRecording => (super.noSuchMethod(
|
||||
Invocation.getter(#isRecording),
|
||||
returnValue: false,
|
||||
returnValueForMissingStub: false,
|
||||
) as bool);
|
||||
|
||||
@override
|
||||
int get listenersCount => (super.noSuchMethod(
|
||||
Invocation.getter(#listenersCount),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user