Merge branch 'release/0.1.5'
-fix(onboarding): Remove birthday and fix other fields
This commit is contained in:
commit
2d5039486f
|
|
@ -14,12 +14,10 @@ class VoiceRecorderService with ListenableServiceMixin {
|
||||||
|
|
||||||
WaveformRecorderController get waveController => _waveController;
|
WaveformRecorderController get waveController => _waveController;
|
||||||
|
|
||||||
|
|
||||||
bool _isRecording = false;
|
bool _isRecording = false;
|
||||||
|
|
||||||
bool get isRecording => _isRecording;
|
bool get isRecording => _isRecording;
|
||||||
|
|
||||||
|
|
||||||
// Start voice recording
|
// Start voice recording
|
||||||
Future<void> startRecording() async {
|
Future<void> startRecording() async {
|
||||||
await _waveController.startRecording();
|
await _waveController.startRecording();
|
||||||
|
|
@ -41,5 +39,4 @@ class VoiceRecorderService with ListenableServiceMixin {
|
||||||
if (file == null) return null;
|
if (file == null) return null;
|
||||||
return file.path;
|
return file.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ class LearnPracticeView extends StackedView<LearnPracticeViewModel> {
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
PopScope(
|
PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
onPopInvokedWithResult: (value, data)
|
onPopInvokedWithResult: (value, data) async =>
|
||||||
async=>await _showSheet(context: context, viewModel: viewModel),
|
await _showSheet(context: context, viewModel: viewModel),
|
||||||
child: _buildScaffoldWrapper(viewModel));
|
child: _buildScaffoldWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
Voice? _playing;
|
Voice? _playing;
|
||||||
|
|
||||||
Voice? get playing =>_playing;
|
Voice? get playing => _playing;
|
||||||
|
|
||||||
// Learn practices
|
// Learn practices
|
||||||
List<LearnPractice> _practices = [];
|
List<LearnPractice> _practices = [];
|
||||||
|
|
@ -126,7 +126,6 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
Future<void> _startRecording() async =>
|
Future<void> _startRecording() async =>
|
||||||
await _voiceRecorderService.startRecording();
|
await _voiceRecorderService.startRecording();
|
||||||
|
|
||||||
|
|
||||||
// Play practice audio
|
// Play practice audio
|
||||||
void _listenToAudio() {
|
void _listenToAudio() {
|
||||||
_audioPlayerService.durationStream.listen((dur) {
|
_audioPlayerService.durationStream.listen((dur) {
|
||||||
|
|
@ -151,45 +150,37 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
await _audioPlayerService.playUrl(question.voicePrompt ?? '');
|
await _audioPlayerService.playUrl(question.voicePrompt ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> playResult({required Map<String,dynamic> answer,required Voice voice})async{
|
Future<void> playResult(
|
||||||
setBusyObject(
|
{required Map<String, dynamic> answer, required Voice voice}) async {
|
||||||
playing: voice,
|
setBusyObject(playing: voice, object: answer['busy_object']);
|
||||||
object: answer['busy_object']);
|
await playAudio(voice: voice, answer: answer);
|
||||||
await playAudio(voice: voice,answer: answer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> playAudio({required Map<String,dynamic> answer,required Voice voice}) async =>
|
Future<void> playAudio(
|
||||||
await runBusyFuture(_playAudio(voice:voice,answer:answer),
|
{required Map<String, dynamic> answer, required Voice voice}) async =>
|
||||||
|
await runBusyFuture(_playAudio(voice: voice, answer: answer),
|
||||||
busyObject: answer['busy_object']);
|
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) {
|
||||||
if(voice == Voice.recorded){
|
await _audioPlayerService.playLocal(answer['recorded_voice_answer']);
|
||||||
await _audioPlayerService
|
} else {
|
||||||
.playLocal(answer['recorded_voice_answer']);
|
|
||||||
}else{
|
|
||||||
await _audioPlayerService.playUrl(answer['sample_voice_answer']);
|
await _audioPlayerService.playUrl(answer['sample_voice_answer']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> pauseAudio() async {
|
Future<void> pauseAudio() async {
|
||||||
await _audioPlayerService.pause();
|
await _audioPlayerService.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set busy object
|
// Set busy object
|
||||||
void setBusyObject({required String object,required Voice playing}) {
|
void setBusyObject({required String object, required Voice playing}) {
|
||||||
_playing = playing;
|
_playing = playing;
|
||||||
_busyObject = object;
|
_busyObject = object;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Dialogue
|
// Dialogue
|
||||||
Future<bool?> showAbortDialog() async {
|
Future<bool?> showAbortDialog() async {
|
||||||
DialogResponse? response = await _dialogService.showDialog(
|
DialogResponse? response = await _dialogService.showDialog(
|
||||||
|
|
@ -219,13 +210,14 @@ 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();
|
await stopRecording();
|
||||||
_answers.add({
|
_answers.add({
|
||||||
'busy_object': question.id.toString(),
|
'busy_object': question.id.toString(),
|
||||||
'sample_text_answer': question.audioCorrectAnswerText,
|
'sample_text_answer': question.audioCorrectAnswerText,
|
||||||
'sample_voice_answer': question.sampleAnswerVoicePrompt,
|
'sample_voice_answer': question.sampleAnswerVoicePrompt,
|
||||||
'recorded_voice_answer' : _voiceRecorderService.getRecordedAudio() ,
|
'recorded_voice_answer': _voiceRecorderService.getRecordedAudio(),
|
||||||
});
|
});
|
||||||
if (index != _questions.length) {
|
if (index != _questions.length) {
|
||||||
_questionSetController.nextPage(
|
_questionSetController.nextPage(
|
||||||
|
|
@ -266,6 +258,5 @@ class LearnPracticeViewModel extends ReactiveViewModel {
|
||||||
|
|
||||||
Future<void> _getLearnPracticeQuestions(int id) async {
|
Future<void> _getLearnPracticeQuestions(int id) async {
|
||||||
_questions = await _apiService.getLearnQuestions(id);
|
_questions = await _apiService.getLearnQuestions(id);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,8 @@ class InteractLearnPracticeScreen
|
||||||
void _start(LearnPracticeViewModel viewModel) =>
|
void _start(LearnPracticeViewModel viewModel) =>
|
||||||
viewModel.playVoicePrompt(question);
|
viewModel.playVoicePrompt(question);
|
||||||
|
|
||||||
|
|
||||||
Future<void> _stop(LearnPracticeViewModel viewModel) async =>
|
Future<void> _stop(LearnPracticeViewModel viewModel) async =>
|
||||||
await viewModel.nextQuestion(index: index,question: question);
|
await viewModel.nextQuestion(index: index, question: question);
|
||||||
|
|
||||||
Future<void> _showSheet(
|
Future<void> _showSheet(
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
|
|
@ -96,24 +95,29 @@ class InteractLearnPracticeScreen
|
||||||
{required BuildContext context,
|
{required BuildContext context,
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
[
|
[
|
||||||
_buildAppBarWrapper(context: context,viewModel: viewModel),
|
_buildAppBarWrapper(context: context, viewModel: viewModel),
|
||||||
_buildSpeakingIndicatorWrapper(viewModel),
|
_buildSpeakingIndicatorWrapper(viewModel),
|
||||||
_buildLowerButtonsSectionWrapper(context: context, viewModel: viewModel)
|
_buildLowerButtonsSectionWrapper(context: context, viewModel: viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBarWrapper( {required BuildContext context,
|
Widget _buildAppBarWrapper(
|
||||||
required LearnPracticeViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
children: [
|
children: [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAppBar(context: context,viewModel: viewModel),
|
_buildAppBar(context: context, viewModel: viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar( {required BuildContext context,
|
Widget _buildAppBar(
|
||||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
SmallAppBar(
|
||||||
showBackButton: true,
|
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})');
|
title: 'Practice Speaking ($index/${viewModel.questions.length})');
|
||||||
|
|
||||||
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
Widget _buildSpeakingIndicatorWrapper(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
viewModel.pop();
|
viewModel.pop();
|
||||||
viewModel.pop();
|
viewModel.pop();
|
||||||
viewModel.stopRecording();
|
viewModel.stopRecording();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showSheet(
|
Future<void> _showSheet(
|
||||||
|
|
@ -32,40 +31,50 @@ class LearnPracticeIntroScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context,viewModel: viewModel);
|
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper( {required BuildContext context,
|
Widget _buildScaffoldWrapper(
|
||||||
required LearnPracticeViewModel viewModel}) => Scaffold(
|
{required BuildContext context,
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(context: context,viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold( {required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
SafeArea(child: _buildColumnWrapper(context: context,viewModel: viewModel));
|
Scaffold(
|
||||||
|
backgroundColor: kcBackgroundColor,
|
||||||
Widget _buildColumnWrapper( {required BuildContext context,
|
body: _buildScaffold(context: context, viewModel: viewModel),
|
||||||
required LearnPracticeViewModel viewModel}) => Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
|
||||||
child: _buildColumn(context: context,viewModel: viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildColumn( {required BuildContext context,
|
Widget _buildScaffold(
|
||||||
required LearnPracticeViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
SafeArea(
|
||||||
|
child: _buildColumnWrapper(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
|
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(
|
||||||
children: [
|
children: [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAppBar(context: context,viewModel: viewModel),
|
_buildAppBar(context: context, viewModel: viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildBodyColumnWrapper(viewModel),
|
_buildBodyColumnWrapper(viewModel),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar( {required BuildContext context,
|
Widget _buildAppBar(
|
||||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
SmallAppBar(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
title: 'Practice Speaking',
|
title: 'Practice Speaking',
|
||||||
onTap: () async => await _showSheet(context: context,viewModel: viewModel),
|
onTap: () async =>
|
||||||
|
await _showSheet(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class LearnPracticeQuestionsScreen
|
||||||
PageView(
|
PageView(
|
||||||
controller: viewModel.questionController,
|
controller: viewModel.questionController,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
children: _buildScreens(index:index,question: question),
|
children: _buildScreens(index: index, question: question),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScreens({
|
List<Widget> _buildScreens({
|
||||||
|
|
@ -46,20 +46,25 @@ class LearnPracticeQuestionsScreen
|
||||||
required LearnQuestion question,
|
required LearnQuestion question,
|
||||||
}) =>
|
}) =>
|
||||||
[
|
[
|
||||||
_buildStartLearnPracticeScreen(index:index,question: question),
|
_buildStartLearnPracticeScreen(index: index, question: question),
|
||||||
_buildInteractLearnPracticeScreen(index:index,question: question)
|
_buildInteractLearnPracticeScreen(index: index, question: question)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildStartLearnPracticeScreen({
|
Widget _buildStartLearnPracticeScreen({
|
||||||
required int index,
|
required int index,
|
||||||
required LearnQuestion question,}
|
required LearnQuestion question,
|
||||||
) => StartLearnPracticeScreen(
|
}) =>
|
||||||
|
StartLearnPracticeScreen(
|
||||||
index: index,
|
index: index,
|
||||||
question: question,
|
question: question,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildInteractLearnPracticeScreen({
|
Widget _buildInteractLearnPracticeScreen({
|
||||||
required int index,
|
required int index,
|
||||||
required LearnQuestion question,}) =>
|
required LearnQuestion question,
|
||||||
InteractLearnPracticeScreen(index: index,question: question,);
|
}) =>
|
||||||
|
InteractLearnPracticeScreen(
|
||||||
|
index: index,
|
||||||
|
question: question,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,9 @@ import '../../../widgets/small_app_bar.dart';
|
||||||
|
|
||||||
class LearnPracticeResultScreen
|
class LearnPracticeResultScreen
|
||||||
extends ViewModelWidget<LearnPracticeViewModel> {
|
extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
|
|
||||||
const LearnPracticeResultScreen({super.key});
|
const LearnPracticeResultScreen({super.key});
|
||||||
|
|
||||||
|
void _navigate(LearnPracticeViewModel viewModel) {
|
||||||
void _navigate(LearnPracticeViewModel viewModel){
|
|
||||||
viewModel.questionSetController.jumpToPage(0);
|
viewModel.questionSetController.jumpToPage(0);
|
||||||
viewModel.goTo(0);
|
viewModel.goTo(0);
|
||||||
}
|
}
|
||||||
|
|
@ -25,7 +23,6 @@ class LearnPracticeResultScreen
|
||||||
viewModel.pop();
|
viewModel.pop();
|
||||||
viewModel.pop();
|
viewModel.pop();
|
||||||
viewModel.stopRecording();
|
viewModel.stopRecording();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showSheet(
|
Future<void> _showSheet(
|
||||||
|
|
@ -40,42 +37,57 @@ class LearnPracticeResultScreen
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context,viewModel: viewModel);
|
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper({required BuildContext context,
|
Widget _buildScaffoldWrapper(
|
||||||
required LearnPracticeViewModel viewModel}) => Scaffold(
|
{required BuildContext context,
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(context: context,viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold({required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
SafeArea(child: _buildBodyColumnWrapper(context: context,viewModel: viewModel));
|
Scaffold(
|
||||||
|
backgroundColor: kcBackgroundColor,
|
||||||
|
body: _buildScaffold(context: context, viewModel: viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildBodyColumnWrapper({required BuildContext context,
|
Widget _buildScaffold(
|
||||||
required LearnPracticeViewModel viewModel}) => Padding(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
SafeArea(
|
||||||
|
child:
|
||||||
|
_buildBodyColumnWrapper(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
|
Widget _buildBodyColumnWrapper(
|
||||||
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBodyColumn(context: context,viewModel: viewModel),
|
child: _buildBodyColumn(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyColumn({required BuildContext context,
|
Widget _buildBodyColumn(
|
||||||
required LearnPracticeViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
children: _buildBodyColumnChildren(context: context,viewModel: viewModel),
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
|
children:
|
||||||
|
_buildBodyColumnChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyColumnChildren({required BuildContext context,
|
List<Widget> _buildBodyColumnChildren(
|
||||||
required LearnPracticeViewModel viewModel}) => [
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
[
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAppBar(context: context,viewModel: viewModel),
|
_buildAppBar(context: context, viewModel: viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildBodyWrapper(viewModel)
|
_buildBodyWrapper(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar({required BuildContext context,
|
Widget _buildAppBar(
|
||||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
SmallAppBar(
|
||||||
title: 'Result',
|
title: 'Result',
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onTap: () async => await _showSheet(context: context,viewModel: viewModel),
|
onTap: () async =>
|
||||||
|
await _showSheet(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
@ -148,6 +160,5 @@ class LearnPracticeResultScreen
|
||||||
borderColor: kcPrimaryColor,
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
onTap: () => _navigate(viewModel),
|
onTap: () => _navigate(viewModel),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
final int index;
|
final int index;
|
||||||
final LearnQuestion question;
|
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 {
|
Future<void> _cancel(LearnPracticeViewModel viewModel) async {
|
||||||
viewModel.pop();
|
viewModel.pop();
|
||||||
|
|
@ -37,50 +38,67 @@ class StartLearnPracticeScreen extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(context: context,viewModel: viewModel);
|
_buildScaffoldWrapper(context: context, viewModel: viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper( {required BuildContext context,
|
Widget _buildScaffoldWrapper(
|
||||||
required LearnPracticeViewModel viewModel}) => Scaffold(
|
{required BuildContext context,
|
||||||
backgroundColor: kcBackgroundColor,
|
|
||||||
body: _buildScaffold(context: context,viewModel: viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildScaffold( {required BuildContext context,
|
|
||||||
required LearnPracticeViewModel viewModel}) =>
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
SafeArea(child: _buildBodyColumnWrapper(context: context,viewModel: viewModel));
|
Scaffold(
|
||||||
|
backgroundColor: kcBackgroundColor,
|
||||||
|
body: _buildScaffold(context: context, viewModel: viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildBodyColumnWrapper( {required BuildContext context,
|
Widget _buildScaffold(
|
||||||
required LearnPracticeViewModel viewModel}) => Padding(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
SafeArea(
|
||||||
|
child:
|
||||||
|
_buildBodyColumnWrapper(context: context, viewModel: viewModel));
|
||||||
|
|
||||||
|
Widget _buildBodyColumnWrapper(
|
||||||
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBodyColumn(context: context,viewModel: viewModel),
|
child: _buildBodyColumn(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyColumn( {required BuildContext context,
|
Widget _buildBodyColumn(
|
||||||
required LearnPracticeViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyColumnChildren(context: context,viewModel: viewModel),
|
children:
|
||||||
|
_buildBodyColumnChildren(context: context, viewModel: viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyColumnChildren( {required BuildContext context,
|
List<Widget> _buildBodyColumnChildren(
|
||||||
required LearnPracticeViewModel viewModel}) => [
|
{required BuildContext context,
|
||||||
_buildAppBarWrapper(context: context,viewModel: viewModel),
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
[
|
||||||
|
_buildAppBarWrapper(context: context, viewModel: viewModel),
|
||||||
_buildStartButtonWrapper(viewModel),
|
_buildStartButtonWrapper(viewModel),
|
||||||
_buildLowerButtonsSectionWrapper(viewModel)
|
_buildLowerButtonsSectionWrapper(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBarWrapper( {required BuildContext context,
|
Widget _buildAppBarWrapper(
|
||||||
required LearnPracticeViewModel viewModel}) => Column(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
children: [
|
children: [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAppBar(context: context,viewModel: viewModel),
|
_buildAppBar(context: context, viewModel: viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAppBar( {required BuildContext context,
|
Widget _buildAppBar(
|
||||||
required LearnPracticeViewModel viewModel}) => SmallAppBar(
|
{required BuildContext context,
|
||||||
|
required LearnPracticeViewModel viewModel}) =>
|
||||||
|
SmallAppBar(
|
||||||
showBackButton: true,
|
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})');
|
title: 'Practice Speaking ($index/${viewModel.questions.length})');
|
||||||
|
|
||||||
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
Widget _buildSheet(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked/stacked_annotations.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/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/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/country_region_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/educational_background_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: 'topic', validator: FormValidator.validateForm),
|
||||||
FormTextField(
|
FormTextField(
|
||||||
name: 'fullName', validator: FormValidator.validateFullNameForm),
|
name: 'fullName', validator: FormValidator.validateFullNameForm),
|
||||||
|
FormTextField(name: 'region', validator: FormValidator.validateForm),
|
||||||
FormTextField(name: 'challenge', validator: FormValidator.validateForm),
|
FormTextField(name: 'challenge', validator: FormValidator.validateForm),
|
||||||
FormTextField(name: 'occupation', validator: FormValidator.validateForm),
|
FormTextField(name: 'occupation', validator: FormValidator.validateForm),
|
||||||
FormTextField(name: 'languageGoal', validator: FormValidator.validateForm),
|
FormTextField(name: 'languageGoal', validator: FormValidator.validateForm),
|
||||||
|
|
@ -50,25 +50,23 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
} else if (viewModel.currentPage == 1) {
|
} else if (viewModel.currentPage == 1) {
|
||||||
viewModel.resetGenderFormScreen();
|
viewModel.resetGenderFormScreen();
|
||||||
} else if (viewModel.currentPage == 2) {
|
} else if (viewModel.currentPage == 2) {
|
||||||
viewModel.resetBirthdayFormScreen();
|
|
||||||
} else if (viewModel.currentPage == 3) {
|
|
||||||
viewModel.resetAgeGroupFormScreen();
|
viewModel.resetAgeGroupFormScreen();
|
||||||
} else if (viewModel.currentPage == 4) {
|
} else if (viewModel.currentPage == 3) {
|
||||||
viewModel.resetEducationalBackgroundFormScreen();
|
viewModel.resetEducationalBackgroundFormScreen();
|
||||||
} else if (viewModel.currentPage == 5) {
|
} else if (viewModel.currentPage == 4) {
|
||||||
occupationController.clear();
|
occupationController.clear();
|
||||||
viewModel.resetOccupationFormScreen();
|
viewModel.resetOccupationFormScreen();
|
||||||
} else if (viewModel.currentPage == 6) {
|
} else if (viewModel.currentPage == 5) {
|
||||||
viewModel.resetCountryRegionFormScreen();
|
viewModel.resetCountryRegionFormScreen();
|
||||||
} else if (viewModel.currentPage == 7) {
|
} else if (viewModel.currentPage == 6) {
|
||||||
viewModel.resetLearningGoalFormScreen();
|
viewModel.resetLearningGoalFormScreen();
|
||||||
} else if (viewModel.currentPage == 8) {
|
} else if (viewModel.currentPage == 7) {
|
||||||
languageGoalController.clear();
|
languageGoalController.clear();
|
||||||
viewModel.resetLanguageGoalFormScreen();
|
viewModel.resetLanguageGoalFormScreen();
|
||||||
} else if (viewModel.currentPage == 9) {
|
} else if (viewModel.currentPage == 8) {
|
||||||
challengeController.clear();
|
challengeController.clear();
|
||||||
viewModel.resetChallengeFormScreen();
|
viewModel.resetChallengeFormScreen();
|
||||||
} else if (viewModel.currentPage == 10) {
|
} else if (viewModel.currentPage == 9) {
|
||||||
topicController.clear();
|
topicController.clear();
|
||||||
viewModel.resetTopicFormScreen();
|
viewModel.resetTopicFormScreen();
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +115,6 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
List<Widget> _buildScreens() => [
|
List<Widget> _buildScreens() => [
|
||||||
_buildFullNameForm(),
|
_buildFullNameForm(),
|
||||||
_buildGenderForm(),
|
_buildGenderForm(),
|
||||||
_buildBirthdayForm(),
|
|
||||||
_buildAgeGroupForm(),
|
_buildAgeGroupForm(),
|
||||||
_buildEducationalBackgroundForm(),
|
_buildEducationalBackgroundForm(),
|
||||||
_buildOccupationForm(),
|
_buildOccupationForm(),
|
||||||
|
|
@ -133,8 +130,6 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
|
|
||||||
Widget _buildGenderForm() => const GenderFormScreen();
|
Widget _buildGenderForm() => const GenderFormScreen();
|
||||||
|
|
||||||
Widget _buildBirthdayForm() => const BirthdayFormScreen();
|
|
||||||
|
|
||||||
Widget _buildAgeGroupForm() => const AgeGroupFormScreen();
|
Widget _buildAgeGroupForm() => const AgeGroupFormScreen();
|
||||||
|
|
||||||
Widget _buildEducationalBackgroundForm() =>
|
Widget _buildEducationalBackgroundForm() =>
|
||||||
|
|
@ -143,7 +138,9 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
Widget _buildOccupationForm() =>
|
Widget _buildOccupationForm() =>
|
||||||
OccupationFormScreen(occupationController: occupationController);
|
OccupationFormScreen(occupationController: occupationController);
|
||||||
|
|
||||||
Widget _buildCountryRegionForm() => const CountryRegionFormScreen();
|
Widget _buildCountryRegionForm() => CountryRegionFormScreen(
|
||||||
|
regionController: regionController,
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildLearningGoalForm() => const LearningGoalFormScreen();
|
Widget _buildLearningGoalForm() => const LearningGoalFormScreen();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ const bool _autoTextFieldValidation = true;
|
||||||
|
|
||||||
const String TopicValueKey = 'topic';
|
const String TopicValueKey = 'topic';
|
||||||
const String FullNameValueKey = 'fullName';
|
const String FullNameValueKey = 'fullName';
|
||||||
|
const String RegionValueKey = 'region';
|
||||||
const String ChallengeValueKey = 'challenge';
|
const String ChallengeValueKey = 'challenge';
|
||||||
const String OccupationValueKey = 'occupation';
|
const String OccupationValueKey = 'occupation';
|
||||||
const String LanguageGoalValueKey = 'languageGoal';
|
const String LanguageGoalValueKey = 'languageGoal';
|
||||||
|
|
@ -27,6 +28,7 @@ final Map<String, FocusNode> _OnboardingViewFocusNodes = {};
|
||||||
final Map<String, String? Function(String?)?> _OnboardingViewTextValidations = {
|
final Map<String, String? Function(String?)?> _OnboardingViewTextValidations = {
|
||||||
TopicValueKey: FormValidator.validateForm,
|
TopicValueKey: FormValidator.validateForm,
|
||||||
FullNameValueKey: FormValidator.validateFullNameForm,
|
FullNameValueKey: FormValidator.validateFullNameForm,
|
||||||
|
RegionValueKey: FormValidator.validateForm,
|
||||||
ChallengeValueKey: FormValidator.validateForm,
|
ChallengeValueKey: FormValidator.validateForm,
|
||||||
OccupationValueKey: FormValidator.validateForm,
|
OccupationValueKey: FormValidator.validateForm,
|
||||||
LanguageGoalValueKey: FormValidator.validateForm,
|
LanguageGoalValueKey: FormValidator.validateForm,
|
||||||
|
|
@ -37,6 +39,8 @@ mixin $OnboardingView {
|
||||||
_getFormTextEditingController(TopicValueKey);
|
_getFormTextEditingController(TopicValueKey);
|
||||||
TextEditingController get fullNameController =>
|
TextEditingController get fullNameController =>
|
||||||
_getFormTextEditingController(FullNameValueKey);
|
_getFormTextEditingController(FullNameValueKey);
|
||||||
|
TextEditingController get regionController =>
|
||||||
|
_getFormTextEditingController(RegionValueKey);
|
||||||
TextEditingController get challengeController =>
|
TextEditingController get challengeController =>
|
||||||
_getFormTextEditingController(ChallengeValueKey);
|
_getFormTextEditingController(ChallengeValueKey);
|
||||||
TextEditingController get occupationController =>
|
TextEditingController get occupationController =>
|
||||||
|
|
@ -46,6 +50,7 @@ mixin $OnboardingView {
|
||||||
|
|
||||||
FocusNode get topicFocusNode => _getFormFocusNode(TopicValueKey);
|
FocusNode get topicFocusNode => _getFormFocusNode(TopicValueKey);
|
||||||
FocusNode get fullNameFocusNode => _getFormFocusNode(FullNameValueKey);
|
FocusNode get fullNameFocusNode => _getFormFocusNode(FullNameValueKey);
|
||||||
|
FocusNode get regionFocusNode => _getFormFocusNode(RegionValueKey);
|
||||||
FocusNode get challengeFocusNode => _getFormFocusNode(ChallengeValueKey);
|
FocusNode get challengeFocusNode => _getFormFocusNode(ChallengeValueKey);
|
||||||
FocusNode get occupationFocusNode => _getFormFocusNode(OccupationValueKey);
|
FocusNode get occupationFocusNode => _getFormFocusNode(OccupationValueKey);
|
||||||
FocusNode get languageGoalFocusNode =>
|
FocusNode get languageGoalFocusNode =>
|
||||||
|
|
@ -77,6 +82,7 @@ mixin $OnboardingView {
|
||||||
void syncFormWithViewModel(FormStateHelper model) {
|
void syncFormWithViewModel(FormStateHelper model) {
|
||||||
topicController.addListener(() => _updateFormData(model));
|
topicController.addListener(() => _updateFormData(model));
|
||||||
fullNameController.addListener(() => _updateFormData(model));
|
fullNameController.addListener(() => _updateFormData(model));
|
||||||
|
regionController.addListener(() => _updateFormData(model));
|
||||||
challengeController.addListener(() => _updateFormData(model));
|
challengeController.addListener(() => _updateFormData(model));
|
||||||
occupationController.addListener(() => _updateFormData(model));
|
occupationController.addListener(() => _updateFormData(model));
|
||||||
languageGoalController.addListener(() => _updateFormData(model));
|
languageGoalController.addListener(() => _updateFormData(model));
|
||||||
|
|
@ -93,6 +99,7 @@ mixin $OnboardingView {
|
||||||
void listenToFormUpdated(FormViewModel model) {
|
void listenToFormUpdated(FormViewModel model) {
|
||||||
topicController.addListener(() => _updateFormData(model));
|
topicController.addListener(() => _updateFormData(model));
|
||||||
fullNameController.addListener(() => _updateFormData(model));
|
fullNameController.addListener(() => _updateFormData(model));
|
||||||
|
regionController.addListener(() => _updateFormData(model));
|
||||||
challengeController.addListener(() => _updateFormData(model));
|
challengeController.addListener(() => _updateFormData(model));
|
||||||
occupationController.addListener(() => _updateFormData(model));
|
occupationController.addListener(() => _updateFormData(model));
|
||||||
languageGoalController.addListener(() => _updateFormData(model));
|
languageGoalController.addListener(() => _updateFormData(model));
|
||||||
|
|
@ -107,6 +114,7 @@ mixin $OnboardingView {
|
||||||
..addAll({
|
..addAll({
|
||||||
TopicValueKey: topicController.text,
|
TopicValueKey: topicController.text,
|
||||||
FullNameValueKey: fullNameController.text,
|
FullNameValueKey: fullNameController.text,
|
||||||
|
RegionValueKey: regionController.text,
|
||||||
ChallengeValueKey: challengeController.text,
|
ChallengeValueKey: challengeController.text,
|
||||||
OccupationValueKey: occupationController.text,
|
OccupationValueKey: occupationController.text,
|
||||||
LanguageGoalValueKey: languageGoalController.text,
|
LanguageGoalValueKey: languageGoalController.text,
|
||||||
|
|
@ -153,6 +161,7 @@ extension ValueProperties on FormStateHelper {
|
||||||
|
|
||||||
String? get topicValue => this.formValueMap[TopicValueKey] as String?;
|
String? get topicValue => this.formValueMap[TopicValueKey] as String?;
|
||||||
String? get fullNameValue => this.formValueMap[FullNameValueKey] 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 challengeValue => this.formValueMap[ChallengeValueKey] as String?;
|
||||||
String? get occupationValue =>
|
String? get occupationValue =>
|
||||||
this.formValueMap[OccupationValueKey] as String?;
|
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) {
|
set challengeValue(String? value) {
|
||||||
this.setData(
|
this.setData(
|
||||||
this.formValueMap..addAll({ChallengeValueKey: value}),
|
this.formValueMap..addAll({ChallengeValueKey: value}),
|
||||||
|
|
@ -220,6 +239,9 @@ extension ValueProperties on FormStateHelper {
|
||||||
bool get hasFullName =>
|
bool get hasFullName =>
|
||||||
this.formValueMap.containsKey(FullNameValueKey) &&
|
this.formValueMap.containsKey(FullNameValueKey) &&
|
||||||
(fullNameValue?.isNotEmpty ?? false);
|
(fullNameValue?.isNotEmpty ?? false);
|
||||||
|
bool get hasRegion =>
|
||||||
|
this.formValueMap.containsKey(RegionValueKey) &&
|
||||||
|
(regionValue?.isNotEmpty ?? false);
|
||||||
bool get hasChallenge =>
|
bool get hasChallenge =>
|
||||||
this.formValueMap.containsKey(ChallengeValueKey) &&
|
this.formValueMap.containsKey(ChallengeValueKey) &&
|
||||||
(challengeValue?.isNotEmpty ?? false);
|
(challengeValue?.isNotEmpty ?? false);
|
||||||
|
|
@ -234,6 +256,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
this.fieldsValidationMessages[TopicValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[TopicValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasFullNameValidationMessage =>
|
bool get hasFullNameValidationMessage =>
|
||||||
this.fieldsValidationMessages[FullNameValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[FullNameValueKey]?.isNotEmpty ?? false;
|
||||||
|
bool get hasRegionValidationMessage =>
|
||||||
|
this.fieldsValidationMessages[RegionValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasChallengeValidationMessage =>
|
bool get hasChallengeValidationMessage =>
|
||||||
this.fieldsValidationMessages[ChallengeValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[ChallengeValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasOccupationValidationMessage =>
|
bool get hasOccupationValidationMessage =>
|
||||||
|
|
@ -245,6 +269,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
this.fieldsValidationMessages[TopicValueKey];
|
this.fieldsValidationMessages[TopicValueKey];
|
||||||
String? get fullNameValidationMessage =>
|
String? get fullNameValidationMessage =>
|
||||||
this.fieldsValidationMessages[FullNameValueKey];
|
this.fieldsValidationMessages[FullNameValueKey];
|
||||||
|
String? get regionValidationMessage =>
|
||||||
|
this.fieldsValidationMessages[RegionValueKey];
|
||||||
String? get challengeValidationMessage =>
|
String? get challengeValidationMessage =>
|
||||||
this.fieldsValidationMessages[ChallengeValueKey];
|
this.fieldsValidationMessages[ChallengeValueKey];
|
||||||
String? get occupationValidationMessage =>
|
String? get occupationValidationMessage =>
|
||||||
|
|
@ -258,6 +284,8 @@ extension Methods on FormStateHelper {
|
||||||
this.fieldsValidationMessages[TopicValueKey] = validationMessage;
|
this.fieldsValidationMessages[TopicValueKey] = validationMessage;
|
||||||
void setFullNameValidationMessage(String? validationMessage) =>
|
void setFullNameValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[FullNameValueKey] = validationMessage;
|
this.fieldsValidationMessages[FullNameValueKey] = validationMessage;
|
||||||
|
void setRegionValidationMessage(String? validationMessage) =>
|
||||||
|
this.fieldsValidationMessages[RegionValueKey] = validationMessage;
|
||||||
void setChallengeValidationMessage(String? validationMessage) =>
|
void setChallengeValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[ChallengeValueKey] = validationMessage;
|
this.fieldsValidationMessages[ChallengeValueKey] = validationMessage;
|
||||||
void setOccupationValidationMessage(String? validationMessage) =>
|
void setOccupationValidationMessage(String? validationMessage) =>
|
||||||
|
|
@ -269,6 +297,7 @@ extension Methods on FormStateHelper {
|
||||||
void clearForm() {
|
void clearForm() {
|
||||||
topicValue = '';
|
topicValue = '';
|
||||||
fullNameValue = '';
|
fullNameValue = '';
|
||||||
|
regionValue = '';
|
||||||
challengeValue = '';
|
challengeValue = '';
|
||||||
occupationValue = '';
|
occupationValue = '';
|
||||||
languageGoalValue = '';
|
languageGoalValue = '';
|
||||||
|
|
@ -279,6 +308,7 @@ extension Methods on FormStateHelper {
|
||||||
this.setValidationMessages({
|
this.setValidationMessages({
|
||||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
TopicValueKey: getValidationMessage(TopicValueKey),
|
||||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||||
|
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
||||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||||
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
||||||
|
|
@ -303,6 +333,7 @@ void updateValidationData(FormStateHelper model) =>
|
||||||
model.setValidationMessages({
|
model.setValidationMessages({
|
||||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
TopicValueKey: getValidationMessage(TopicValueKey),
|
||||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||||
|
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
||||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||||
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
String? get selectedGender => _selectedGender;
|
String? get selectedGender => _selectedGender;
|
||||||
|
|
||||||
// Birthday
|
|
||||||
String? _selectedBirthday;
|
|
||||||
|
|
||||||
String? get selectedBirthday => _selectedBirthday;
|
|
||||||
|
|
||||||
// Age group
|
// Age group
|
||||||
final List<Map<String, dynamic>> _ageGroups = [
|
final List<Map<String, dynamic>> _ageGroups = [
|
||||||
{
|
{
|
||||||
|
|
@ -105,10 +100,10 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
String get selectedCountry => _selectedCountry;
|
String get selectedCountry => _selectedCountry;
|
||||||
|
|
||||||
// Country
|
// Region
|
||||||
String _selectedRegion = 'Addis Ababa';
|
bool _focusRegion = false;
|
||||||
|
|
||||||
String get selectedRegion => _selectedRegion;
|
bool get focusRegion => _focusRegion;
|
||||||
|
|
||||||
// Learning goal
|
// Learning goal
|
||||||
String? _selectedLearningGoal;
|
String? _selectedLearningGoal;
|
||||||
|
|
@ -247,12 +242,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
bool isSelectedGender(String value) => _selectedGender == value;
|
bool isSelectedGender(String value) => _selectedGender == value;
|
||||||
|
|
||||||
// Birthday
|
|
||||||
void setBirthday(String value) {
|
|
||||||
_selectedBirthday = value;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Age group
|
// Age group
|
||||||
void setSelectedAgeGroup(Map<String, dynamic> value) {
|
void setSelectedAgeGroup(Map<String, dynamic> value) {
|
||||||
_selectedAgeGroup = value;
|
_selectedAgeGroup = value;
|
||||||
|
|
@ -270,44 +259,168 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Country
|
// 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) {
|
void setSelectedCountry(String value) {
|
||||||
_selectedCountry = value;
|
_selectedCountry = value;
|
||||||
if (selectedCountry != 'Ethiopia') {
|
|
||||||
_selectedRegion = 'Other';
|
|
||||||
} else {
|
|
||||||
_selectedRegion = 'Addis Ababa';
|
|
||||||
}
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Region
|
// Region
|
||||||
List<String> getRegions(String country) {
|
void setRegionFocus() {
|
||||||
if (country == 'Ethiopia') {
|
_focusRegion = true;
|
||||||
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();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -414,12 +527,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset birthday form screen
|
|
||||||
void resetBirthdayFormScreen() {
|
|
||||||
_selectedBirthday = null;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset age group form screen
|
// Reset age group form screen
|
||||||
void resetAgeGroupFormScreen() {
|
void resetAgeGroupFormScreen() {
|
||||||
_selectedAgeGroup = null;
|
_selectedAgeGroup = null;
|
||||||
|
|
@ -441,7 +548,6 @@ class OnboardingViewModel extends ReactiveViewModel
|
||||||
// Reset country region form screen
|
// Reset country region form screen
|
||||||
void resetCountryRegionFormScreen() {
|
void resetCountryRegionFormScreen() {
|
||||||
_selectedCountry = 'Ethiopia';
|
_selectedCountry = 'Ethiopia';
|
||||||
_selectedRegion = 'Addis Ababa';
|
|
||||||
rebuildUi();
|
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/views/onboarding/onboarding_viewmodel.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_dropdown.dart';
|
import 'package:yimaru_app/ui/widgets/custom_dropdown.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
import '../onboarding_view.form.dart';
|
||||||
|
|
||||||
class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
const CountryRegionFormScreen({super.key});
|
final TextEditingController regionController;
|
||||||
|
const CountryRegionFormScreen({super.key, required this.regionController});
|
||||||
|
|
||||||
void _pop(OnboardingViewModel viewModel) {
|
void _pop(OnboardingViewModel viewModel) {
|
||||||
viewModel.resetCountryRegionFormScreen();
|
viewModel.resetCountryRegionFormScreen();
|
||||||
|
|
@ -19,8 +21,8 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
|
'region': regionController.text,
|
||||||
'country': viewModel.selectedCountry,
|
'country': viewModel.selectedCountry,
|
||||||
'region': viewModel.selectedRegion
|
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
|
@ -83,8 +85,11 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildCountryDropDown(viewModel),
|
_buildCountryDropDown(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildRegionDropDown(viewModel),
|
_buildRegionFormField(viewModel),
|
||||||
verticalSpaceMedium,
|
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||||
|
verticalSpaceTiny,
|
||||||
|
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||||
|
_buildRegionValidatorWrapper(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
|
|
@ -112,16 +117,23 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
items: (value, props) => viewModel.getCountries(),
|
items: (value, props) => viewModel.getCountries(),
|
||||||
onChanged: (value) =>
|
onChanged: (value) =>
|
||||||
viewModel.setSelectedCountry(value ?? 'Ethiopia'));
|
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) =>
|
Widget _buildRegionValidatorWrapper(OnboardingViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
viewModel.hasRegionValidationMessage
|
||||||
hint: 'Select region',
|
? _buildRegionValidator(viewModel)
|
||||||
icon: _buildSearchIcon(),
|
: Container();
|
||||||
selectedItem: viewModel.selectedRegion,
|
|
||||||
items: (value, props) =>
|
Widget _buildRegionValidator(OnboardingViewModel viewModel) => Text(
|
||||||
viewModel.getRegions(viewModel.selectedCountry),
|
viewModel.regionValidationMessage!,
|
||||||
onChanged: (value) =>
|
style: style12R700,
|
||||||
viewModel.setSelectedRegion(value ?? 'Addis Ababa'),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Icon _buildSearchIcon() => const Icon(
|
Icon _buildSearchIcon() => const Icon(
|
||||||
|
|
@ -140,7 +152,9 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: () => _next(viewModel),
|
onTap: regionController.text.isNotEmpty ? () => _next(viewModel) : null,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: regionController.text.isNotEmpty
|
||||||
|
? kcPrimaryColor
|
||||||
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
|
|
@ -25,6 +26,7 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'profile_completed': true,
|
'profile_completed': true,
|
||||||
'preferred_language': 'en',
|
'preferred_language': 'en',
|
||||||
|
'birth_day': DateFormat('yyyy-MM-dd').format(DateTime.now()),
|
||||||
'favoutite_topic': viewModel.selectedTopic ?? topicController.text,
|
'favoutite_topic': viewModel.selectedTopic ?? topicController.text,
|
||||||
};
|
};
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import 'package:flutter/services.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked/stacked_annotations.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/custom_form_label.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/small_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/small_app_bar.dart';
|
||||||
|
|
||||||
|
|
@ -22,6 +21,7 @@ import 'profile_detail_view.form.dart';
|
||||||
|
|
||||||
@FormView(fields: [
|
@FormView(fields: [
|
||||||
FormTextField(name: 'email', validator: FormValidator.validateForm),
|
FormTextField(name: 'email', validator: FormValidator.validateForm),
|
||||||
|
FormTextField(name: 'region', validator: FormValidator.validateForm),
|
||||||
FormTextField(
|
FormTextField(
|
||||||
name: 'phoneNumber', validator: FormValidator.validatePhoneNumberForm),
|
name: 'phoneNumber', validator: FormValidator.validatePhoneNumberForm),
|
||||||
FormTextField(name: 'lastName', validator: FormValidator.validateForm),
|
FormTextField(name: 'lastName', validator: FormValidator.validateForm),
|
||||||
|
|
@ -34,13 +34,13 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
|
|
||||||
Future<void> _update(ProfileDetailViewModel viewModel) async {
|
Future<void> _update(ProfileDetailViewModel viewModel) async {
|
||||||
Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
'region': viewModel.selectedRegion,
|
'region':regionController.text,
|
||||||
'gender': viewModel.selectedGender,
|
'gender': viewModel.selectedGender,
|
||||||
'last_name': lastNameController.text,
|
'last_name': lastNameController.text,
|
||||||
'country': viewModel.selectedCountry,
|
'country': viewModel.selectedCountry,
|
||||||
'first_name': firstNameController.text,
|
'first_name': firstNameController.text,
|
||||||
'occupation': occupationController.text,
|
'occupation': occupationController.text,
|
||||||
'birth_day': viewModel.selectedBirthday,
|
'birth_day': DateFormat('d MMM, yyyy').format(DateTime.now()),
|
||||||
};
|
};
|
||||||
|
|
||||||
viewModel.addUserData(data);
|
viewModel.addUserData(data);
|
||||||
|
|
@ -68,15 +68,14 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
void _onModelReady(ProfileDetailViewModel viewModel) {
|
void _onModelReady(ProfileDetailViewModel viewModel) {
|
||||||
phoneNumberController.text = '251900000000';
|
phoneNumberController.text = '251900000000';
|
||||||
emailController.text = viewModel.user?.email ?? '';
|
emailController.text = viewModel.user?.email ?? '';
|
||||||
|
regionController.text = viewModel.user?.region ?? '';
|
||||||
lastNameController.text = viewModel.user?.lastName ?? '';
|
lastNameController.text = viewModel.user?.lastName ?? '';
|
||||||
firstNameController.text = viewModel.user?.firstName ?? '';
|
firstNameController.text = viewModel.user?.firstName ?? '';
|
||||||
occupationController.text = viewModel.user?.occupation ?? '';
|
occupationController.text = viewModel.user?.occupation ?? '';
|
||||||
viewModel.clearUserData();
|
viewModel.clearUserData();
|
||||||
viewModel.setGender(viewModel.user?.gender ?? '');
|
viewModel.setGender(viewModel.user?.gender ?? '');
|
||||||
viewModel.setSelectedCountry(viewModel.user?.country ?? 'Ethiopia');
|
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
|
@override
|
||||||
|
|
@ -185,14 +184,17 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildGenderFormFieldWrapper(viewModel),
|
_buildGenderFormFieldWrapper(viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildBirthdayColumn(viewModel),
|
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildPhoneNumberFormFieldSection(viewModel),
|
_buildPhoneNumberFormFieldSection(viewModel),
|
||||||
verticalSpaceTiny,
|
verticalSpaceTiny,
|
||||||
_buildEmailFormFieldSection(viewModel),
|
_buildEmailFormFieldSection(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildCountryRegionSection(viewModel),
|
_buildCountryDropdownLabel(),
|
||||||
|
verticalSpaceSmall,
|
||||||
|
_buildCountryDropdown(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
_buildRegionFormFieldWrapper(viewModel),
|
||||||
|
verticalSpaceMedium,
|
||||||
|
|
||||||
_buildOccupationDropdownWrapper(viewModel),
|
_buildOccupationDropdownWrapper(viewModel),
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildLowerColumn(viewModel)
|
_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) =>
|
Widget _buildPhoneNumberFormFieldSection(ProfileDetailViewModel viewModel) =>
|
||||||
Column(
|
Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -533,39 +511,6 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
style: validationStyle,
|
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(
|
Widget _buildCountryDropdownLabel() => CustomFormLabel(
|
||||||
label: 'Country',
|
label: 'Country',
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
|
|
@ -579,38 +524,48 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
onChanged: (value) => viewModel.setSelectedCountry(value ?? 'Ethiopia'),
|
onChanged: (value) => viewModel.setSelectedCountry(value ?? 'Ethiopia'),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildRegionDropdownColumnWrapper(ProfileDetailViewModel viewModel) =>
|
Widget _buildRegionFormFieldWrapper(ProfileDetailViewModel viewModel) =>
|
||||||
Expanded(
|
Column(
|
||||||
child: _buildRegionDropdownColumn(viewModel),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildRegionDropdownColumn(ProfileDetailViewModel viewModel) => Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: _buildRegionDropdownChildren(viewModel),
|
children: _buildRegionFormFieldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildRegionDropdownChildren(ProfileDetailViewModel viewModel) =>
|
List<Widget> _buildRegionFormFieldChildren(
|
||||||
|
ProfileDetailViewModel viewModel) =>
|
||||||
[
|
[
|
||||||
_buildRegionDropdownLabel(),
|
_buildRegionFormFieldLabel(),verticalSpaceSmall,
|
||||||
verticalSpaceSmall,
|
_buildRegionFormField(viewModel),
|
||||||
_buildRegionDropdown(viewModel)
|
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||||
|
verticalSpaceTiny,
|
||||||
|
if (viewModel.hasRegionValidationMessage && viewModel.focusRegion)
|
||||||
|
_buildRegionValidatorWrapper(viewModel),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildRegionDropdownLabel() => CustomFormLabel(
|
Widget _buildRegionFormFieldLabel() => CustomFormLabel(
|
||||||
label: 'Region',
|
label: 'Region',
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildRegionDropdown(ProfileDetailViewModel viewModel) =>
|
Widget _buildRegionFormField(ProfileDetailViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
TextFormField(
|
||||||
hint: 'Select region',
|
controller: regionController,
|
||||||
selectedItem: viewModel.selectedRegion,
|
onTap: viewModel.setRegionFocus,
|
||||||
items: (value, props) =>
|
decoration: inputDecoration(
|
||||||
viewModel.getRegions(viewModel.selectedCountry),
|
hint: 'Enter Your City',
|
||||||
onChanged: (value) =>
|
focus: viewModel.focusRegion,
|
||||||
viewModel.setSelectedRegion(value ?? 'Addis Ababa'),
|
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) =>
|
Widget _buildOccupationDropdownWrapper(ProfileDetailViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import 'package:yimaru_app/ui/common/validators/form_validator.dart';
|
||||||
const bool _autoTextFieldValidation = true;
|
const bool _autoTextFieldValidation = true;
|
||||||
|
|
||||||
const String EmailValueKey = 'email';
|
const String EmailValueKey = 'email';
|
||||||
|
const String RegionValueKey = 'region';
|
||||||
const String PhoneNumberValueKey = 'phoneNumber';
|
const String PhoneNumberValueKey = 'phoneNumber';
|
||||||
const String LastNameValueKey = 'lastName';
|
const String LastNameValueKey = 'lastName';
|
||||||
const String FirstNameValueKey = 'firstName';
|
const String FirstNameValueKey = 'firstName';
|
||||||
|
|
@ -27,6 +28,7 @@ final Map<String, FocusNode> _ProfileDetailViewFocusNodes = {};
|
||||||
final Map<String, String? Function(String?)?>
|
final Map<String, String? Function(String?)?>
|
||||||
_ProfileDetailViewTextValidations = {
|
_ProfileDetailViewTextValidations = {
|
||||||
EmailValueKey: FormValidator.validateForm,
|
EmailValueKey: FormValidator.validateForm,
|
||||||
|
RegionValueKey: FormValidator.validateForm,
|
||||||
PhoneNumberValueKey: FormValidator.validatePhoneNumberForm,
|
PhoneNumberValueKey: FormValidator.validatePhoneNumberForm,
|
||||||
LastNameValueKey: FormValidator.validateForm,
|
LastNameValueKey: FormValidator.validateForm,
|
||||||
FirstNameValueKey: FormValidator.validateForm,
|
FirstNameValueKey: FormValidator.validateForm,
|
||||||
|
|
@ -36,6 +38,8 @@ final Map<String, String? Function(String?)?>
|
||||||
mixin $ProfileDetailView {
|
mixin $ProfileDetailView {
|
||||||
TextEditingController get emailController =>
|
TextEditingController get emailController =>
|
||||||
_getFormTextEditingController(EmailValueKey);
|
_getFormTextEditingController(EmailValueKey);
|
||||||
|
TextEditingController get regionController =>
|
||||||
|
_getFormTextEditingController(RegionValueKey);
|
||||||
TextEditingController get phoneNumberController =>
|
TextEditingController get phoneNumberController =>
|
||||||
_getFormTextEditingController(PhoneNumberValueKey);
|
_getFormTextEditingController(PhoneNumberValueKey);
|
||||||
TextEditingController get lastNameController =>
|
TextEditingController get lastNameController =>
|
||||||
|
|
@ -46,6 +50,7 @@ mixin $ProfileDetailView {
|
||||||
_getFormTextEditingController(OccupationValueKey);
|
_getFormTextEditingController(OccupationValueKey);
|
||||||
|
|
||||||
FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey);
|
FocusNode get emailFocusNode => _getFormFocusNode(EmailValueKey);
|
||||||
|
FocusNode get regionFocusNode => _getFormFocusNode(RegionValueKey);
|
||||||
FocusNode get phoneNumberFocusNode => _getFormFocusNode(PhoneNumberValueKey);
|
FocusNode get phoneNumberFocusNode => _getFormFocusNode(PhoneNumberValueKey);
|
||||||
FocusNode get lastNameFocusNode => _getFormFocusNode(LastNameValueKey);
|
FocusNode get lastNameFocusNode => _getFormFocusNode(LastNameValueKey);
|
||||||
FocusNode get firstNameFocusNode => _getFormFocusNode(FirstNameValueKey);
|
FocusNode get firstNameFocusNode => _getFormFocusNode(FirstNameValueKey);
|
||||||
|
|
@ -76,6 +81,7 @@ mixin $ProfileDetailView {
|
||||||
/// with the latest textController values
|
/// with the latest textController values
|
||||||
void syncFormWithViewModel(FormStateHelper model) {
|
void syncFormWithViewModel(FormStateHelper model) {
|
||||||
emailController.addListener(() => _updateFormData(model));
|
emailController.addListener(() => _updateFormData(model));
|
||||||
|
regionController.addListener(() => _updateFormData(model));
|
||||||
phoneNumberController.addListener(() => _updateFormData(model));
|
phoneNumberController.addListener(() => _updateFormData(model));
|
||||||
lastNameController.addListener(() => _updateFormData(model));
|
lastNameController.addListener(() => _updateFormData(model));
|
||||||
firstNameController.addListener(() => _updateFormData(model));
|
firstNameController.addListener(() => _updateFormData(model));
|
||||||
|
|
@ -92,6 +98,7 @@ mixin $ProfileDetailView {
|
||||||
)
|
)
|
||||||
void listenToFormUpdated(FormViewModel model) {
|
void listenToFormUpdated(FormViewModel model) {
|
||||||
emailController.addListener(() => _updateFormData(model));
|
emailController.addListener(() => _updateFormData(model));
|
||||||
|
regionController.addListener(() => _updateFormData(model));
|
||||||
phoneNumberController.addListener(() => _updateFormData(model));
|
phoneNumberController.addListener(() => _updateFormData(model));
|
||||||
lastNameController.addListener(() => _updateFormData(model));
|
lastNameController.addListener(() => _updateFormData(model));
|
||||||
firstNameController.addListener(() => _updateFormData(model));
|
firstNameController.addListener(() => _updateFormData(model));
|
||||||
|
|
@ -106,6 +113,7 @@ mixin $ProfileDetailView {
|
||||||
model.formValueMap
|
model.formValueMap
|
||||||
..addAll({
|
..addAll({
|
||||||
EmailValueKey: emailController.text,
|
EmailValueKey: emailController.text,
|
||||||
|
RegionValueKey: regionController.text,
|
||||||
PhoneNumberValueKey: phoneNumberController.text,
|
PhoneNumberValueKey: phoneNumberController.text,
|
||||||
LastNameValueKey: lastNameController.text,
|
LastNameValueKey: lastNameController.text,
|
||||||
FirstNameValueKey: firstNameController.text,
|
FirstNameValueKey: firstNameController.text,
|
||||||
|
|
@ -152,6 +160,7 @@ extension ValueProperties on FormStateHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
String? get emailValue => this.formValueMap[EmailValueKey] as String?;
|
String? get emailValue => this.formValueMap[EmailValueKey] as String?;
|
||||||
|
String? get regionValue => this.formValueMap[RegionValueKey] as String?;
|
||||||
String? get phoneNumberValue =>
|
String? get phoneNumberValue =>
|
||||||
this.formValueMap[PhoneNumberValueKey] as String?;
|
this.formValueMap[PhoneNumberValueKey] as String?;
|
||||||
String? get lastNameValue => this.formValueMap[LastNameValueKey] 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) {
|
set phoneNumberValue(String? value) {
|
||||||
this.setData(
|
this.setData(
|
||||||
this.formValueMap..addAll({PhoneNumberValueKey: value}),
|
this.formValueMap..addAll({PhoneNumberValueKey: value}),
|
||||||
|
|
@ -221,6 +241,9 @@ extension ValueProperties on FormStateHelper {
|
||||||
bool get hasEmail =>
|
bool get hasEmail =>
|
||||||
this.formValueMap.containsKey(EmailValueKey) &&
|
this.formValueMap.containsKey(EmailValueKey) &&
|
||||||
(emailValue?.isNotEmpty ?? false);
|
(emailValue?.isNotEmpty ?? false);
|
||||||
|
bool get hasRegion =>
|
||||||
|
this.formValueMap.containsKey(RegionValueKey) &&
|
||||||
|
(regionValue?.isNotEmpty ?? false);
|
||||||
bool get hasPhoneNumber =>
|
bool get hasPhoneNumber =>
|
||||||
this.formValueMap.containsKey(PhoneNumberValueKey) &&
|
this.formValueMap.containsKey(PhoneNumberValueKey) &&
|
||||||
(phoneNumberValue?.isNotEmpty ?? false);
|
(phoneNumberValue?.isNotEmpty ?? false);
|
||||||
|
|
@ -236,6 +259,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
|
|
||||||
bool get hasEmailValidationMessage =>
|
bool get hasEmailValidationMessage =>
|
||||||
this.fieldsValidationMessages[EmailValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[EmailValueKey]?.isNotEmpty ?? false;
|
||||||
|
bool get hasRegionValidationMessage =>
|
||||||
|
this.fieldsValidationMessages[RegionValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasPhoneNumberValidationMessage =>
|
bool get hasPhoneNumberValidationMessage =>
|
||||||
this.fieldsValidationMessages[PhoneNumberValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[PhoneNumberValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasLastNameValidationMessage =>
|
bool get hasLastNameValidationMessage =>
|
||||||
|
|
@ -247,6 +272,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
|
|
||||||
String? get emailValidationMessage =>
|
String? get emailValidationMessage =>
|
||||||
this.fieldsValidationMessages[EmailValueKey];
|
this.fieldsValidationMessages[EmailValueKey];
|
||||||
|
String? get regionValidationMessage =>
|
||||||
|
this.fieldsValidationMessages[RegionValueKey];
|
||||||
String? get phoneNumberValidationMessage =>
|
String? get phoneNumberValidationMessage =>
|
||||||
this.fieldsValidationMessages[PhoneNumberValueKey];
|
this.fieldsValidationMessages[PhoneNumberValueKey];
|
||||||
String? get lastNameValidationMessage =>
|
String? get lastNameValidationMessage =>
|
||||||
|
|
@ -260,6 +287,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
extension Methods on FormStateHelper {
|
extension Methods on FormStateHelper {
|
||||||
void setEmailValidationMessage(String? validationMessage) =>
|
void setEmailValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[EmailValueKey] = validationMessage;
|
this.fieldsValidationMessages[EmailValueKey] = validationMessage;
|
||||||
|
void setRegionValidationMessage(String? validationMessage) =>
|
||||||
|
this.fieldsValidationMessages[RegionValueKey] = validationMessage;
|
||||||
void setPhoneNumberValidationMessage(String? validationMessage) =>
|
void setPhoneNumberValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[PhoneNumberValueKey] = validationMessage;
|
this.fieldsValidationMessages[PhoneNumberValueKey] = validationMessage;
|
||||||
void setLastNameValidationMessage(String? validationMessage) =>
|
void setLastNameValidationMessage(String? validationMessage) =>
|
||||||
|
|
@ -272,6 +301,7 @@ extension Methods on FormStateHelper {
|
||||||
/// Clears text input fields on the Form
|
/// Clears text input fields on the Form
|
||||||
void clearForm() {
|
void clearForm() {
|
||||||
emailValue = '';
|
emailValue = '';
|
||||||
|
regionValue = '';
|
||||||
phoneNumberValue = '';
|
phoneNumberValue = '';
|
||||||
lastNameValue = '';
|
lastNameValue = '';
|
||||||
firstNameValue = '';
|
firstNameValue = '';
|
||||||
|
|
@ -282,6 +312,7 @@ extension Methods on FormStateHelper {
|
||||||
void validateForm() {
|
void validateForm() {
|
||||||
this.setValidationMessages({
|
this.setValidationMessages({
|
||||||
EmailValueKey: getValidationMessage(EmailValueKey),
|
EmailValueKey: getValidationMessage(EmailValueKey),
|
||||||
|
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||||
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
||||||
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
||||||
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
||||||
|
|
@ -306,6 +337,7 @@ String? getValidationMessage(String key) {
|
||||||
void updateValidationData(FormStateHelper model) =>
|
void updateValidationData(FormStateHelper model) =>
|
||||||
model.setValidationMessages({
|
model.setValidationMessages({
|
||||||
EmailValueKey: getValidationMessage(EmailValueKey),
|
EmailValueKey: getValidationMessage(EmailValueKey),
|
||||||
|
RegionValueKey: getValidationMessage(RegionValueKey),
|
||||||
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
PhoneNumberValueKey: getValidationMessage(PhoneNumberValueKey),
|
||||||
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
LastNameValueKey: getValidationMessage(LastNameValueKey),
|
||||||
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
FirstNameValueKey: getValidationMessage(FirstNameValueKey),
|
||||||
|
|
|
||||||
|
|
@ -47,10 +47,6 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
String? get selectedGender => _selectedGender;
|
String? get selectedGender => _selectedGender;
|
||||||
|
|
||||||
// Birthday
|
|
||||||
String? _selectedBirthday;
|
|
||||||
|
|
||||||
String? get selectedBirthday => _selectedBirthday;
|
|
||||||
|
|
||||||
// First name
|
// First name
|
||||||
bool _focusPhoneNumber = false;
|
bool _focusPhoneNumber = false;
|
||||||
|
|
@ -67,16 +63,17 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
|
|
||||||
String get selectedCountry => _selectedCountry;
|
String get selectedCountry => _selectedCountry;
|
||||||
|
|
||||||
// Region
|
|
||||||
String _selectedRegion = 'Addis Ababa';
|
|
||||||
|
|
||||||
String get selectedRegion => _selectedRegion;
|
|
||||||
|
|
||||||
// Occupation
|
// Occupation
|
||||||
bool _focusOccupation = false;
|
bool _focusOccupation = false;
|
||||||
|
|
||||||
bool get focusOccupation => _focusOccupation;
|
bool get focusOccupation => _focusOccupation;
|
||||||
|
|
||||||
|
// Region
|
||||||
|
bool _focusRegion = false;
|
||||||
|
|
||||||
|
bool get focusRegion => _focusRegion;
|
||||||
|
|
||||||
// User data
|
// User data
|
||||||
final Map<String, dynamic> _userData = {};
|
final Map<String, dynamic> _userData = {};
|
||||||
|
|
||||||
|
|
@ -100,11 +97,6 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Birthday
|
|
||||||
void setBirthday(String value) {
|
|
||||||
_selectedBirthday = value;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Phone number
|
// Phone number
|
||||||
void setPhoneNumberFocus() {
|
void setPhoneNumberFocus() {
|
||||||
|
|
@ -119,47 +111,168 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Country
|
// 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) {
|
void setSelectedCountry(String value) {
|
||||||
_selectedCountry = value;
|
_selectedCountry = value;
|
||||||
if (selectedCountry != 'Ethiopia') {
|
|
||||||
_selectedRegion = 'Other';
|
|
||||||
} else {
|
|
||||||
_selectedRegion = 'Addis Ababa';
|
|
||||||
}
|
|
||||||
|
|
||||||
rebuildUi();
|
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
|
// Occupation
|
||||||
void setOccupationFocus() {
|
void setOccupationFocus() {
|
||||||
|
|
@ -167,6 +280,12 @@ class ProfileDetailViewModel extends ReactiveViewModel
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Region
|
||||||
|
void setRegionFocus() {
|
||||||
|
_focusRegion = true;
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
// User data
|
// User data
|
||||||
void addUserData(Map<String, dynamic> data) {
|
void addUserData(Map<String, dynamic> data) {
|
||||||
_userData.addAll(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;
|
final GestureTapCallback? onContinue;
|
||||||
|
|
||||||
const CancelLearnPracticeSheet(
|
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
|
@override
|
||||||
Widget build(BuildContext context) =>
|
Widget build(BuildContext context) => _buildSheetWrapper();
|
||||||
_buildSheetWrapper();
|
|
||||||
|
|
||||||
Widget _buildSheetWrapper() =>
|
Widget _buildSheetWrapper() => CustomBottomSheet(
|
||||||
CustomBottomSheet(
|
|
||||||
height: 500, onTap: onClose, child: _buildColumnWrapper());
|
height: 500, onTap: onClose, child: _buildColumnWrapper());
|
||||||
|
|
||||||
Widget _buildColumnWrapper() => Padding(
|
Widget _buildColumnWrapper() => Padding(
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,8 @@ class LearnPracticeResultsWrapper
|
||||||
children: _buildColumnChildren(viewModel),
|
children: _buildColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren(LearnPracticeViewModel viewModel) => [
|
List<Widget> _buildColumnChildren(LearnPracticeViewModel viewModel) =>
|
||||||
_buildTitle(),
|
[_buildTitle(), verticalSpaceSmall, _buildResults(viewModel)];
|
||||||
verticalSpaceSmall,
|
|
||||||
_buildResults(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
'Conversation Review',
|
'Conversation Review',
|
||||||
|
|
@ -46,10 +43,10 @@ class LearnPracticeResultsWrapper
|
||||||
itemCount: viewModel.answers.length,
|
itemCount: viewModel.answers.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
separatorBuilder: (context, index) => verticalSpaceSmall,
|
separatorBuilder: (context, index) => verticalSpaceSmall,
|
||||||
itemBuilder: (context, index) => _buildResult( viewModel.answers[index]),
|
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});
|
const LearnPracticeTipSection({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context,LearnPracticeViewModel viewModel) => _buildContainer(viewModel);
|
Widget build(BuildContext context, LearnPracticeViewModel viewModel) =>
|
||||||
|
_buildContainer(viewModel);
|
||||||
|
|
||||||
Widget _buildContainer(LearnPracticeViewModel viewModel) => Container(
|
Widget _buildContainer(LearnPracticeViewModel viewModel) => Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25),
|
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 25),
|
||||||
|
|
@ -24,7 +25,7 @@ class LearnPracticeTipSection extends ViewModelWidget<LearnPracticeViewModel> {
|
||||||
Widget _buildColumn(LearnPracticeViewModel viewModel) => Column(
|
Widget _buildColumn(LearnPracticeViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildColumnChildren( viewModel),
|
children: _buildColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildColumnChildren(LearnPracticeViewModel viewModel) =>
|
List<Widget> _buildColumnChildren(LearnPracticeViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
name: yimaru_app
|
name: yimaru_app
|
||||||
version: 0.1.4+6
|
version: 0.1.5+7
|
||||||
publish_to: 'none'
|
publish_to: 'none'
|
||||||
description: A new Flutter project.
|
description: A new Flutter project.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1992,6 +1992,13 @@ class MockVoiceRecorderService extends _i1.Mock
|
||||||
),
|
),
|
||||||
) as _i5.WaveformRecorderController);
|
) as _i5.WaveformRecorderController);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isRecording => (super.noSuchMethod(
|
||||||
|
Invocation.getter(#isRecording),
|
||||||
|
returnValue: false,
|
||||||
|
returnValueForMissingStub: false,
|
||||||
|
) as bool);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get listenersCount => (super.noSuchMethod(
|
int get listenersCount => (super.noSuchMethod(
|
||||||
Invocation.getter(#listenersCount),
|
Invocation.getter(#listenersCount),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user