fix(auth): Fix token refresh
This commit is contained in:
parent
c222b3c67a
commit
1713a8957a
|
|
@ -3,7 +3,8 @@
|
||||||
<application
|
<application
|
||||||
android:label="Yimaru"
|
android:label="Yimaru"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -26,6 +26,9 @@ import 'package:yimaru_app/services/authentication_service.dart';
|
||||||
import 'package:yimaru_app/services/api_service.dart';
|
import 'package:yimaru_app/services/api_service.dart';
|
||||||
import 'package:yimaru_app/services/secure_storage_service.dart';
|
import 'package:yimaru_app/services/secure_storage_service.dart';
|
||||||
import 'package:yimaru_app/services/dio_service.dart';
|
import 'package:yimaru_app/services/dio_service.dart';
|
||||||
|
import 'package:yimaru_app/services/status_checker_service.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/welcome/welcome_view.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart';
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
||||||
@StackedApp(
|
@StackedApp(
|
||||||
|
|
@ -50,6 +53,8 @@ import 'package:yimaru_app/services/dio_service.dart';
|
||||||
MaterialRoute(page: LearnView),
|
MaterialRoute(page: LearnView),
|
||||||
MaterialRoute(page: LearnLevelView),
|
MaterialRoute(page: LearnLevelView),
|
||||||
MaterialRoute(page: LearnModuleView),
|
MaterialRoute(page: LearnModuleView),
|
||||||
|
MaterialRoute(page: WelcomeView),
|
||||||
|
MaterialRoute(page: AssessmentView),
|
||||||
// @stacked-route
|
// @stacked-route
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
|
|
@ -60,6 +65,7 @@ import 'package:yimaru_app/services/dio_service.dart';
|
||||||
LazySingleton(classType: ApiService),
|
LazySingleton(classType: ApiService),
|
||||||
LazySingleton(classType: SecureStorageService),
|
LazySingleton(classType: SecureStorageService),
|
||||||
LazySingleton(classType: DioService),
|
LazySingleton(classType: DioService),
|
||||||
|
LazySingleton(classType: StatusCheckerService),
|
||||||
// @stacked-service
|
// @stacked-service
|
||||||
],
|
],
|
||||||
bottomsheets: [
|
bottomsheets: [
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import '../services/api_service.dart';
|
||||||
import '../services/authentication_service.dart';
|
import '../services/authentication_service.dart';
|
||||||
import '../services/dio_service.dart';
|
import '../services/dio_service.dart';
|
||||||
import '../services/secure_storage_service.dart';
|
import '../services/secure_storage_service.dart';
|
||||||
|
import '../services/status_checker_service.dart';
|
||||||
|
|
||||||
final locator = StackedLocator.instance;
|
final locator = StackedLocator.instance;
|
||||||
|
|
||||||
|
|
@ -34,4 +35,5 @@ Future<void> setupLocator({
|
||||||
locator.registerLazySingleton(() => ApiService());
|
locator.registerLazySingleton(() => ApiService());
|
||||||
locator.registerLazySingleton(() => SecureStorageService());
|
locator.registerLazySingleton(() => SecureStorageService());
|
||||||
locator.registerLazySingleton(() => DioService());
|
locator.registerLazySingleton(() => DioService());
|
||||||
|
locator.registerLazySingleton(() => StatusCheckerService());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,13 @@
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'package:flutter/material.dart' as _i22;
|
import 'package:flutter/material.dart' as _i24;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stacked/stacked.dart' as _i1;
|
import 'package:stacked/stacked.dart' as _i1;
|
||||||
import 'package:stacked_services/stacked_services.dart' as _i23;
|
import 'package:stacked_services/stacked_services.dart' as _i25;
|
||||||
import 'package:yimaru_app/ui/views/account_privacy/account_privacy_view.dart'
|
import 'package:yimaru_app/ui/views/account_privacy/account_privacy_view.dart'
|
||||||
as _i10;
|
as _i10;
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/assessment_view.dart' as _i23;
|
||||||
import 'package:yimaru_app/ui/views/call_support/call_support_view.dart'
|
import 'package:yimaru_app/ui/views/call_support/call_support_view.dart'
|
||||||
as _i13;
|
as _i13;
|
||||||
import 'package:yimaru_app/ui/views/downloads/downloads_view.dart' as _i7;
|
import 'package:yimaru_app/ui/views/downloads/downloads_view.dart' as _i7;
|
||||||
|
|
@ -37,6 +38,7 @@ import 'package:yimaru_app/ui/views/telegram_support/telegram_support_view.dart'
|
||||||
as _i12;
|
as _i12;
|
||||||
import 'package:yimaru_app/ui/views/terms_and_conditions/terms_and_conditions_view.dart'
|
import 'package:yimaru_app/ui/views/terms_and_conditions/terms_and_conditions_view.dart'
|
||||||
as _i16;
|
as _i16;
|
||||||
|
import 'package:yimaru_app/ui/views/welcome/welcome_view.dart' as _i22;
|
||||||
|
|
||||||
class Routes {
|
class Routes {
|
||||||
static const homeView = '/home-view';
|
static const homeView = '/home-view';
|
||||||
|
|
@ -79,6 +81,10 @@ class Routes {
|
||||||
|
|
||||||
static const learnModuleView = '/learn-module-view';
|
static const learnModuleView = '/learn-module-view';
|
||||||
|
|
||||||
|
static const welcomeView = '/welcome-view';
|
||||||
|
|
||||||
|
static const assessmentView = '/assessment-view';
|
||||||
|
|
||||||
static const all = <String>{
|
static const all = <String>{
|
||||||
homeView,
|
homeView,
|
||||||
onboardingView,
|
onboardingView,
|
||||||
|
|
@ -100,6 +106,8 @@ class Routes {
|
||||||
learnView,
|
learnView,
|
||||||
learnLevelView,
|
learnLevelView,
|
||||||
learnModuleView,
|
learnModuleView,
|
||||||
|
welcomeView,
|
||||||
|
assessmentView,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,129 +193,154 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
Routes.learnModuleView,
|
Routes.learnModuleView,
|
||||||
page: _i21.LearnModuleView,
|
page: _i21.LearnModuleView,
|
||||||
),
|
),
|
||||||
|
_i1.RouteDef(
|
||||||
|
Routes.welcomeView,
|
||||||
|
page: _i22.WelcomeView,
|
||||||
|
),
|
||||||
|
_i1.RouteDef(
|
||||||
|
Routes.assessmentView,
|
||||||
|
page: _i23.AssessmentView,
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
final _pagesMap = <Type, _i1.StackedRouteFactory>{
|
||||||
_i2.HomeView: (data) {
|
_i2.HomeView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i2.HomeView(),
|
builder: (context) => const _i2.HomeView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i3.OnboardingView: (data) {
|
_i3.OnboardingView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i3.OnboardingView(),
|
builder: (context) => const _i3.OnboardingView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i4.StartupView: (data) {
|
_i4.StartupView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
final args = data.getArgs<StartupViewArguments>(
|
||||||
builder: (context) => const _i4.StartupView(),
|
orElse: () => const StartupViewArguments(),
|
||||||
|
);
|
||||||
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
|
builder: (context) => _i4.StartupView(key: args.key, label: args.label),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i5.ProfileView: (data) {
|
_i5.ProfileView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i5.ProfileView(),
|
builder: (context) => const _i5.ProfileView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i6.ProfileDetailView: (data) {
|
_i6.ProfileDetailView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i6.ProfileDetailView(),
|
builder: (context) => const _i6.ProfileDetailView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i7.DownloadsView: (data) {
|
_i7.DownloadsView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i7.DownloadsView(),
|
builder: (context) => const _i7.DownloadsView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i8.ProgressView: (data) {
|
_i8.ProgressView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i8.ProgressView(),
|
builder: (context) => const _i8.ProgressView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i9.OngoingProgressView: (data) {
|
_i9.OngoingProgressView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i9.OngoingProgressView(),
|
builder: (context) => const _i9.OngoingProgressView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i10.AccountPrivacyView: (data) {
|
_i10.AccountPrivacyView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i10.AccountPrivacyView(),
|
builder: (context) => const _i10.AccountPrivacyView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i11.SupportView: (data) {
|
_i11.SupportView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i11.SupportView(),
|
builder: (context) => const _i11.SupportView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i12.TelegramSupportView: (data) {
|
_i12.TelegramSupportView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i12.TelegramSupportView(),
|
builder: (context) => const _i12.TelegramSupportView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i13.CallSupportView: (data) {
|
_i13.CallSupportView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i13.CallSupportView(),
|
builder: (context) => const _i13.CallSupportView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i14.LanguageView: (data) {
|
_i14.LanguageView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i14.LanguageView(),
|
builder: (context) => const _i14.LanguageView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i15.PrivacyPolicyView: (data) {
|
_i15.PrivacyPolicyView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i15.PrivacyPolicyView(),
|
builder: (context) => const _i15.PrivacyPolicyView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i16.TermsAndConditionsView: (data) {
|
_i16.TermsAndConditionsView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i16.TermsAndConditionsView(),
|
builder: (context) => const _i16.TermsAndConditionsView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i17.RegisterView: (data) {
|
_i17.RegisterView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i17.RegisterView(),
|
builder: (context) => const _i17.RegisterView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i18.LoginView: (data) {
|
_i18.LoginView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i18.LoginView(),
|
builder: (context) => const _i18.LoginView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i19.LearnView: (data) {
|
_i19.LearnView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i19.LearnView(),
|
builder: (context) => const _i19.LearnView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i20.LearnLevelView: (data) {
|
_i20.LearnLevelView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i20.LearnLevelView(),
|
builder: (context) => const _i20.LearnLevelView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
_i21.LearnModuleView: (data) {
|
_i21.LearnModuleView: (data) {
|
||||||
return _i22.MaterialPageRoute<dynamic>(
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
builder: (context) => const _i21.LearnModuleView(),
|
builder: (context) => const _i21.LearnModuleView(),
|
||||||
settings: data,
|
settings: data,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
_i22.WelcomeView: (data) {
|
||||||
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
|
builder: (context) => const _i22.WelcomeView(),
|
||||||
|
settings: data,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
_i23.AssessmentView: (data) {
|
||||||
|
final args = data.getArgs<AssessmentViewArguments>(nullOk: false);
|
||||||
|
return _i24.MaterialPageRoute<dynamic>(
|
||||||
|
builder: (context) =>
|
||||||
|
_i23.AssessmentView(key: args.key, data: args.data),
|
||||||
|
settings: data,
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -317,7 +350,61 @@ class StackedRouter extends _i1.RouterBase {
|
||||||
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
|
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NavigatorStateExtension on _i23.NavigationService {
|
class StartupViewArguments {
|
||||||
|
const StartupViewArguments({
|
||||||
|
this.key,
|
||||||
|
this.label = 'Loading',
|
||||||
|
});
|
||||||
|
|
||||||
|
final _i24.Key? key;
|
||||||
|
|
||||||
|
final String label;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '{"key": "$key", "label": "$label"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant StartupViewArguments other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return other.key == key && other.label == label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return key.hashCode ^ label.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssessmentViewArguments {
|
||||||
|
const AssessmentViewArguments({
|
||||||
|
this.key,
|
||||||
|
required this.data,
|
||||||
|
});
|
||||||
|
|
||||||
|
final _i24.Key? key;
|
||||||
|
|
||||||
|
final Map<String, dynamic> data;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return '{"key": "$key", "data": "$data"}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(covariant AssessmentViewArguments other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
return other.key == key && other.data == data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
return key.hashCode ^ data.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NavigatorStateExtension on _i25.NavigationService {
|
||||||
Future<dynamic> navigateToHomeView([
|
Future<dynamic> navigateToHomeView([
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -346,14 +433,17 @@ extension NavigatorStateExtension on _i23.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> navigateToStartupView([
|
Future<dynamic> navigateToStartupView({
|
||||||
|
_i24.Key? key,
|
||||||
|
String label = 'Loading',
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
Map<String, String>? parameters,
|
Map<String, String>? parameters,
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
transition,
|
transition,
|
||||||
]) async {
|
}) async {
|
||||||
return navigateTo<dynamic>(Routes.startupView,
|
return navigateTo<dynamic>(Routes.startupView,
|
||||||
|
arguments: StartupViewArguments(key: key, label: label),
|
||||||
id: routerId,
|
id: routerId,
|
||||||
preventDuplicates: preventDuplicates,
|
preventDuplicates: preventDuplicates,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
|
|
@ -598,6 +688,37 @@ extension NavigatorStateExtension on _i23.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<dynamic> navigateToWelcomeView([
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
]) async {
|
||||||
|
return navigateTo<dynamic>(Routes.welcomeView,
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> navigateToAssessmentView({
|
||||||
|
_i24.Key? key,
|
||||||
|
required Map<String, dynamic> data,
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
}) async {
|
||||||
|
return navigateTo<dynamic>(Routes.assessmentView,
|
||||||
|
arguments: AssessmentViewArguments(key: key, data: data),
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithHomeView([
|
Future<dynamic> replaceWithHomeView([
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
|
|
@ -626,14 +747,17 @@ extension NavigatorStateExtension on _i23.NavigationService {
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> replaceWithStartupView([
|
Future<dynamic> replaceWithStartupView({
|
||||||
|
_i24.Key? key,
|
||||||
|
String label = 'Loading',
|
||||||
int? routerId,
|
int? routerId,
|
||||||
bool preventDuplicates = true,
|
bool preventDuplicates = true,
|
||||||
Map<String, String>? parameters,
|
Map<String, String>? parameters,
|
||||||
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
transition,
|
transition,
|
||||||
]) async {
|
}) async {
|
||||||
return replaceWith<dynamic>(Routes.startupView,
|
return replaceWith<dynamic>(Routes.startupView,
|
||||||
|
arguments: StartupViewArguments(key: key, label: label),
|
||||||
id: routerId,
|
id: routerId,
|
||||||
preventDuplicates: preventDuplicates,
|
preventDuplicates: preventDuplicates,
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
|
|
@ -877,4 +1001,35 @@ extension NavigatorStateExtension on _i23.NavigationService {
|
||||||
parameters: parameters,
|
parameters: parameters,
|
||||||
transition: transition);
|
transition: transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<dynamic> replaceWithWelcomeView([
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
]) async {
|
||||||
|
return replaceWith<dynamic>(Routes.welcomeView,
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> replaceWithAssessmentView({
|
||||||
|
_i24.Key? key,
|
||||||
|
required Map<String, dynamic> data,
|
||||||
|
int? routerId,
|
||||||
|
bool preventDuplicates = true,
|
||||||
|
Map<String, String>? parameters,
|
||||||
|
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
|
||||||
|
transition,
|
||||||
|
}) async {
|
||||||
|
return replaceWith<dynamic>(Routes.assessmentView,
|
||||||
|
arguments: AssessmentViewArguments(key: key, data: data),
|
||||||
|
id: routerId,
|
||||||
|
preventDuplicates: preventDuplicates,
|
||||||
|
parameters: parameters,
|
||||||
|
transition: transition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,8 @@ class MainApp extends StatelessWidget {
|
||||||
Widget _buildMaterialApp() => MaterialApp(
|
Widget _buildMaterialApp() => MaterialApp(
|
||||||
initialRoute: Routes.startupView,
|
initialRoute: Routes.startupView,
|
||||||
theme: ThemeData(fontFamily: 'Aeonik'),
|
theme: ThemeData(fontFamily: 'Aeonik'),
|
||||||
onGenerateRoute: StackedRouter().onGenerateRoute,
|
|
||||||
navigatorKey: StackedService.navigatorKey,
|
navigatorKey: StackedService.navigatorKey,
|
||||||
|
onGenerateRoute: StackedRouter().onGenerateRoute,
|
||||||
navigatorObservers: [StackedService.routeObserver],
|
navigatorObservers: [StackedService.routeObserver],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
StudioProjects/yimaru_app/lib/models/assessment.dart
Normal file
20
StudioProjects/yimaru_app/lib/models/assessment.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
import 'package:yimaru_app/models/option.dart';
|
||||||
|
import 'package:yimaru_app/models/question.dart';
|
||||||
|
part 'assessment.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class Assessment {
|
||||||
|
@JsonKey(name: 'Question')
|
||||||
|
final Question? question;
|
||||||
|
|
||||||
|
@JsonKey(name: 'Options')
|
||||||
|
final List<Option>? options;
|
||||||
|
|
||||||
|
const Assessment({this.options, this.question});
|
||||||
|
|
||||||
|
factory Assessment.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$AssessmentFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$AssessmentToJson(this);
|
||||||
|
}
|
||||||
22
StudioProjects/yimaru_app/lib/models/assessment.g.dart
Normal file
22
StudioProjects/yimaru_app/lib/models/assessment.g.dart
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'assessment.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
Assessment _$AssessmentFromJson(Map<String, dynamic> json) => Assessment(
|
||||||
|
options: (json['Options'] as List<dynamic>?)
|
||||||
|
?.map((e) => Option.fromJson(e as Map<String, dynamic>))
|
||||||
|
.toList(),
|
||||||
|
question: json['Question'] == null
|
||||||
|
? null
|
||||||
|
: Question.fromJson(json['Question'] as Map<String, dynamic>),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$AssessmentToJson(Assessment instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'Question': instance.question,
|
||||||
|
'Options': instance.options,
|
||||||
|
};
|
||||||
17
StudioProjects/yimaru_app/lib/models/option.dart
Normal file
17
StudioProjects/yimaru_app/lib/models/option.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
part 'option.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class Option {
|
||||||
|
@JsonKey(name: 'question_id')
|
||||||
|
final int? questionId;
|
||||||
|
|
||||||
|
@JsonKey(name: 'option_text')
|
||||||
|
final String? optionText;
|
||||||
|
|
||||||
|
const Option({this.optionText, this.questionId});
|
||||||
|
|
||||||
|
factory Option.fromJson(Map<String, dynamic> json) => _$OptionFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$OptionToJson(this);
|
||||||
|
}
|
||||||
17
StudioProjects/yimaru_app/lib/models/option.g.dart
Normal file
17
StudioProjects/yimaru_app/lib/models/option.g.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'option.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
Option _$OptionFromJson(Map<String, dynamic> json) => Option(
|
||||||
|
optionText: json['option_text'] as String?,
|
||||||
|
questionId: (json['question_id'] as num?)?.toInt(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$OptionToJson(Option instance) => <String, dynamic>{
|
||||||
|
'question_id': instance.questionId,
|
||||||
|
'option_text': instance.optionText,
|
||||||
|
};
|
||||||
36
StudioProjects/yimaru_app/lib/models/question.dart
Normal file
36
StudioProjects/yimaru_app/lib/models/question.dart
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
part 'question.g.dart';
|
||||||
|
|
||||||
|
@JsonSerializable()
|
||||||
|
class Question {
|
||||||
|
final int? id;
|
||||||
|
|
||||||
|
final int? points;
|
||||||
|
|
||||||
|
final String? title;
|
||||||
|
|
||||||
|
final String? description;
|
||||||
|
|
||||||
|
@JsonKey(name: 'is_active')
|
||||||
|
final bool? isActive;
|
||||||
|
|
||||||
|
@JsonKey(name: 'question_type')
|
||||||
|
final String? questionType;
|
||||||
|
|
||||||
|
@JsonKey(name: 'difficulty_level')
|
||||||
|
final String? difficultyLevel;
|
||||||
|
|
||||||
|
const Question(
|
||||||
|
{this.id,
|
||||||
|
this.title,
|
||||||
|
this.points,
|
||||||
|
this.isActive,
|
||||||
|
this.description,
|
||||||
|
this.questionType,
|
||||||
|
this.difficultyLevel});
|
||||||
|
|
||||||
|
factory Question.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$QuestionFromJson(json);
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => _$QuestionToJson(this);
|
||||||
|
}
|
||||||
27
StudioProjects/yimaru_app/lib/models/question.g.dart
Normal file
27
StudioProjects/yimaru_app/lib/models/question.g.dart
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'question.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
Question _$QuestionFromJson(Map<String, dynamic> json) => Question(
|
||||||
|
id: (json['id'] as num?)?.toInt(),
|
||||||
|
title: json['title'] as String?,
|
||||||
|
points: (json['points'] as num?)?.toInt(),
|
||||||
|
isActive: json['is_active'] as bool?,
|
||||||
|
description: json['description'] as String?,
|
||||||
|
questionType: json['question_type'] as String?,
|
||||||
|
difficultyLevel: json['difficulty_level'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$QuestionToJson(Question instance) => <String, dynamic>{
|
||||||
|
'id': instance.id,
|
||||||
|
'points': instance.points,
|
||||||
|
'title': instance.title,
|
||||||
|
'description': instance.description,
|
||||||
|
'is_active': instance.isActive,
|
||||||
|
'question_type': instance.questionType,
|
||||||
|
'difficulty_level': instance.difficultyLevel,
|
||||||
|
};
|
||||||
|
|
@ -7,13 +7,19 @@ class UserModel {
|
||||||
@JsonKey(name: 'user_id')
|
@JsonKey(name: 'user_id')
|
||||||
final int? userId;
|
final int? userId;
|
||||||
|
|
||||||
|
final bool? profileCompleted;
|
||||||
|
|
||||||
@JsonKey(name: 'access_token')
|
@JsonKey(name: 'access_token')
|
||||||
final String? accessToken;
|
final String? accessToken;
|
||||||
|
|
||||||
@JsonKey(name: 'refresh_token')
|
@JsonKey(name: 'refresh_token')
|
||||||
final String? refreshToken;
|
final String? refreshToken;
|
||||||
|
|
||||||
UserModel({this.userId, this.accessToken, this.refreshToken});
|
const UserModel(
|
||||||
|
{this.userId,
|
||||||
|
this.accessToken,
|
||||||
|
this.profileCompleted,
|
||||||
|
this.refreshToken});
|
||||||
|
|
||||||
factory UserModel.fromJson(Map<String, dynamic> json) =>
|
factory UserModel.fromJson(Map<String, dynamic> json) =>
|
||||||
_$UserModelFromJson(json);
|
_$UserModelFromJson(json);
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,13 @@ part of 'user_model.dart';
|
||||||
UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel(
|
UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel(
|
||||||
userId: (json['user_id'] as num?)?.toInt(),
|
userId: (json['user_id'] as num?)?.toInt(),
|
||||||
accessToken: json['access_token'] as String?,
|
accessToken: json['access_token'] as String?,
|
||||||
|
profileCompleted: json['profileCompleted'] as bool?,
|
||||||
refreshToken: json['refresh_token'] as String?,
|
refreshToken: json['refresh_token'] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
|
Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
|
||||||
'user_id': instance.userId,
|
'user_id': instance.userId,
|
||||||
|
'profileCompleted': instance.profileCompleted,
|
||||||
'access_token': instance.accessToken,
|
'access_token': instance.accessToken,
|
||||||
'refresh_token': instance.refreshToken,
|
'refresh_token': instance.refreshToken,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:yimaru_app/models/assessment.dart';
|
||||||
import 'package:yimaru_app/models/user_model.dart';
|
import 'package:yimaru_app/models/user_model.dart';
|
||||||
import 'package:yimaru_app/services/dio_service.dart';
|
import 'package:yimaru_app/services/dio_service.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_constants.dart';
|
import 'package:yimaru_app/ui/common/app_constants.dart';
|
||||||
|
|
@ -9,32 +10,12 @@ import '../ui/common/enmus.dart';
|
||||||
class ApiService {
|
class ApiService {
|
||||||
final _service = locator<DioService>();
|
final _service = locator<DioService>();
|
||||||
|
|
||||||
// Http headers
|
|
||||||
Map<String, dynamic> _getHeaders({String? token}) => {
|
|
||||||
|
|
||||||
// if (token != null) 'Authorization': 'Bearer $token',
|
|
||||||
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Content-Type': 'application/json; charset=UTF-8',
|
|
||||||
if (token != null) 'Authorization': 'Bearer $token'
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dio options
|
|
||||||
Options? _getOptions({String? token}) {
|
|
||||||
return Options(
|
|
||||||
// followRedirects: false,
|
|
||||||
// validateStatus: (status) => true,
|
|
||||||
headers: _getHeaders(token: token),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register
|
// Register
|
||||||
Future<Map<String, dynamic>> register(Map<String, dynamic> data) async {
|
Future<Map<String, dynamic>> register(Map<String, dynamic> data) async {
|
||||||
try {
|
try {
|
||||||
Response response = await _service.dio.post(
|
Response response = await _service.dio.post(
|
||||||
'$baseUrl/$userUrl/$kRegisterUrl',
|
'$baseUrl/$userUrl/$kRegisterUrl',
|
||||||
data: data,
|
data: data,
|
||||||
options: _getOptions(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
|
@ -62,7 +43,6 @@ class ApiService {
|
||||||
Response response = await _service.dio.post(
|
Response response = await _service.dio.post(
|
||||||
'$baseUrl/$kLoginUrl',
|
'$baseUrl/$kLoginUrl',
|
||||||
data: data,
|
data: data,
|
||||||
options: _getOptions(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
|
@ -91,7 +71,6 @@ class ApiService {
|
||||||
Response response = await _service.dio.post(
|
Response response = await _service.dio.post(
|
||||||
'$baseUrl/$userUrl/$kVerifyOtpUrl',
|
'$baseUrl/$userUrl/$kVerifyOtpUrl',
|
||||||
data: data,
|
data: data,
|
||||||
options: _getOptions(),
|
|
||||||
);
|
);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -119,7 +98,6 @@ class ApiService {
|
||||||
Response response = await _service.dio.post(
|
Response response = await _service.dio.post(
|
||||||
'$baseUrl/$userUrl/$kResendOtpUrl',
|
'$baseUrl/$userUrl/$kResendOtpUrl',
|
||||||
data: data,
|
data: data,
|
||||||
options: _getOptions(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
|
@ -146,7 +124,6 @@ class ApiService {
|
||||||
try {
|
try {
|
||||||
Response response = await _service.dio.get(
|
Response response = await _service.dio.get(
|
||||||
'$baseUrl/$userUrl/${user?.userId}/$kProfileStatusUrl',
|
'$baseUrl/$userUrl/${user?.userId}/$kProfileStatusUrl',
|
||||||
options: _getOptions(token: user?.accessToken),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
|
|
@ -168,4 +145,60 @@ class ApiService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update profile
|
||||||
|
Future<Map<String, dynamic>> updateProfile(
|
||||||
|
{required UserModel? user, required Map<String, dynamic> data}) async {
|
||||||
|
try {
|
||||||
|
Response response = await _service.dio.put(
|
||||||
|
'$baseUrl/$userUrl',
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
|
||||||
|
print(response.statusCode);
|
||||||
|
print(response.data);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.success,
|
||||||
|
'message': 'Profile updated successfully'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
'message': 'Unknown Error Occurred'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Exception ${e.toString()}');
|
||||||
|
return {
|
||||||
|
'message': e.toString(),
|
||||||
|
'status': ResponseStatus.failure,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assessments
|
||||||
|
Future<List<Assessment>> getAssessments() async {
|
||||||
|
try {
|
||||||
|
List<Assessment> assessments = [];
|
||||||
|
|
||||||
|
final Response response =
|
||||||
|
await _service.dio.get('$baseUrl/$kAssessmentsUrl');
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
var data = response.data;
|
||||||
|
var decodedData = data['data'] as List;
|
||||||
|
assessments = decodedData.map(
|
||||||
|
(e) {
|
||||||
|
return Assessment.fromJson(e);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return assessments;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,21 +12,52 @@ class AuthenticationService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String?> getAccessToken() async =>
|
||||||
|
await _secureService.getString('accessToken');
|
||||||
|
|
||||||
|
Future<String?> getRefreshToken() async =>
|
||||||
|
await _secureService.getString('refreshToken');
|
||||||
|
|
||||||
|
Future<int?> getUserId() async => await _secureService.getInt('userId');
|
||||||
|
|
||||||
|
Future<void> saveTokens({
|
||||||
|
required String access,
|
||||||
|
required String refresh,
|
||||||
|
}) async {
|
||||||
|
await _secureService.setString('accessToken', access);
|
||||||
|
await _secureService.setString('refreshToken', refresh);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> saveUserData(Map<String, dynamic> data) async {
|
Future<void> saveUserData(Map<String, dynamic> data) async {
|
||||||
await _secureService.setInt('userId', data['userId']);
|
await _secureService.setInt('userId', data['userId']);
|
||||||
await _secureService.setString('accessToken', data['accessToken']);
|
await _secureService.setString('accessToken', data['accessToken']);
|
||||||
await _secureService.setString('refreshToken', data['refreshToken']);
|
await _secureService.setString('refreshToken', data['refreshToken']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> saveProfileCompleted(bool value) async {
|
||||||
|
await _secureService.setBool('profileCompleted', value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> isFirstTimeInstall() async =>
|
||||||
|
await _secureService.getBool('firstTimeInstall') ?? true;
|
||||||
|
|
||||||
|
Future<void> setFirstTimeInstall(bool value) async {
|
||||||
|
await _secureService.setBool('firstTimeInstall', value);
|
||||||
|
}
|
||||||
|
|
||||||
Future<UserModel> getUser() async {
|
Future<UserModel> getUser() async {
|
||||||
UserModel user = UserModel(
|
UserModel user = UserModel(
|
||||||
userId: await _secureService.getInt('userId'),
|
userId: await _secureService.getInt('userId'),
|
||||||
accessToken: await _secureService.getString('accessToken'),
|
accessToken: await _secureService.getString('accessToken'),
|
||||||
refreshToken: await _secureService.getString('refreshToken'));
|
refreshToken: await _secureService.getString('refreshToken'),
|
||||||
|
profileCompleted: await _secureService.getBool('profileCompleted'),
|
||||||
|
);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> logOut() async {
|
Future<void> logOut() async {
|
||||||
|
bool firstTimeInstall = await isFirstTimeInstall();
|
||||||
await _secureService.clear();
|
await _secureService.clear();
|
||||||
|
await setFirstTimeInstall(firstTimeInstall);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,175 @@
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
import 'package:yimaru_app/app/app.router.dart';
|
||||||
|
import 'package:yimaru_app/models/user_model.dart';
|
||||||
|
import 'package:yimaru_app/services/authentication_service.dart';
|
||||||
|
import 'package:yimaru_app/services/secure_storage_service.dart';
|
||||||
|
|
||||||
|
import '../app/app.locator.dart';
|
||||||
import '../ui/common/app_constants.dart';
|
import '../ui/common/app_constants.dart';
|
||||||
|
|
||||||
class DioService {
|
class DioService {
|
||||||
|
final _navigationService = locator<NavigationService>();
|
||||||
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
final Dio _dio = Dio();
|
final Dio _dio = Dio();
|
||||||
|
final Dio _refreshDio = Dio(); // separate instance
|
||||||
|
|
||||||
|
bool _isRefreshing = false;
|
||||||
|
final List<void Function()> _retryQueue = [];
|
||||||
|
|
||||||
DioService() {
|
DioService() {
|
||||||
_dio.options.baseUrl = baseUrl;
|
_dio.options
|
||||||
_dio.options.connectTimeout = const Duration(seconds: 30);
|
..baseUrl = baseUrl
|
||||||
_dio.options.receiveTimeout = const Duration(seconds: 30);
|
..connectTimeout = const Duration(seconds: 30)
|
||||||
|
..receiveTimeout = const Duration(seconds: 30);
|
||||||
|
|
||||||
_dio.interceptors.add(
|
_dio.interceptors.add(
|
||||||
InterceptorsWrapper(
|
InterceptorsWrapper(
|
||||||
onRequest: (options, handler) {
|
onError: _onError,
|
||||||
debugPrint('➡️➡️➡️ REQUEST ➡️➡️➡️');
|
onRequest: _onRequest,
|
||||||
debugPrint('➡️ Data: ${options.data}');
|
onResponse: _onResponse,
|
||||||
debugPrint('➡️ Headers: ${options.headers}');
|
|
||||||
debugPrint('➡️ ${options.method} ${options.uri}');
|
|
||||||
handler.next(options);
|
|
||||||
},
|
|
||||||
onResponse: (response, handler) {
|
|
||||||
debugPrint('✅✅✅ RESPONSE ✅✅✅');
|
|
||||||
debugPrint('✅ Data : ${response.data}');
|
|
||||||
debugPrint('✅ Status Code : ${response.statusCode}');
|
|
||||||
handler.next(response);
|
|
||||||
},
|
|
||||||
onError: (error, handler) {
|
|
||||||
debugPrint('❌❌❌ ERROR ❌❌❌');
|
|
||||||
debugPrint('❌ ${error.message}');
|
|
||||||
debugPrint('❌ URI: ${error.requestOptions.uri}');
|
|
||||||
debugPrint('❌ Headers sent: ${error.requestOptions.headers}');
|
|
||||||
handler.next(error);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onResponse(
|
||||||
|
Response response,
|
||||||
|
ResponseInterceptorHandler handler,
|
||||||
|
) {
|
||||||
|
debugPrint('✅✅✅✅INITIALIZING RESPONSE✅✅✅✅');
|
||||||
|
debugPrint('✅ ${response.statusCode} ${response.requestOptions.uri}');
|
||||||
|
debugPrint('✅ DATA: ${response.data}');
|
||||||
|
debugPrint('✅✅✅✅FINALIZING RESPONSE✅✅✅✅');
|
||||||
|
|
||||||
|
handler.next(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onRequest(
|
||||||
|
RequestOptions options,
|
||||||
|
RequestInterceptorHandler handler,
|
||||||
|
) async {
|
||||||
|
final token = await _authenticationService.getAccessToken();
|
||||||
|
|
||||||
|
if (token != null) {
|
||||||
|
options.headers['Authorization'] = 'Bearer $token';
|
||||||
|
}
|
||||||
|
|
||||||
|
options.headers['Accept'] = 'application/json';
|
||||||
|
options.headers['Content-Type'] = 'application/json';
|
||||||
|
|
||||||
|
debugPrint('️️➡️➡️➡️➡️INITIALIZING REQUEST➡️➡️➡️➡️');
|
||||||
|
debugPrint('➡️ ${options.method} ${options.uri}');
|
||||||
|
debugPrint('➡️ HEADERS: ${options.headers}');
|
||||||
|
debugPrint('➡️ DATA: ${options.data}');
|
||||||
|
debugPrint('️️➡️➡️➡️➡️FINALIZING REQUEST➡️➡️➡️➡️');
|
||||||
|
|
||||||
|
handler.next(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onError(
|
||||||
|
DioException error,
|
||||||
|
ErrorInterceptorHandler handler,
|
||||||
|
) async {
|
||||||
|
debugPrint('❌❌❌❌INITIALIZING ERROR❌❌❌❌');
|
||||||
|
debugPrint('❌ ${error.response?.data} ${error.requestOptions.uri}');
|
||||||
|
debugPrint('❌ ${error.response?.statusCode} ${error.requestOptions.uri}');
|
||||||
|
debugPrint('❌❌❌❌FINALIZING ERROR❌❌❌❌');
|
||||||
|
|
||||||
|
if (error.response?.statusCode == 401 &&
|
||||||
|
!_isRefreshRequest(error.requestOptions)) {
|
||||||
|
return _handle401(error, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.next(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _handle401(
|
||||||
|
DioException error,
|
||||||
|
ErrorInterceptorHandler handler,
|
||||||
|
) async {
|
||||||
|
final requestOptions = error.requestOptions;
|
||||||
|
|
||||||
|
if (_isRefreshing) {
|
||||||
|
_retryQueue.add(() async {
|
||||||
|
final response = await _dio.fetch(requestOptions);
|
||||||
|
handler.resolve(response);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isRefreshing = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final refreshed = await _refreshToken();
|
||||||
|
|
||||||
|
if (!refreshed) {
|
||||||
|
handler.reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await _dio.fetch(requestOptions);
|
||||||
|
|
||||||
|
for (final retry in _retryQueue) {
|
||||||
|
retry();
|
||||||
|
}
|
||||||
|
_retryQueue.clear();
|
||||||
|
|
||||||
|
handler.resolve(response);
|
||||||
|
} catch (e) {
|
||||||
|
handler.reject(error);
|
||||||
|
} finally {
|
||||||
|
_isRefreshing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _refreshToken() async {
|
||||||
|
final UserModel user = await _authenticationService.getUser();
|
||||||
|
|
||||||
|
if (user.refreshToken == null) return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String,dynamic> data = {
|
||||||
|
'role': 'STUDENT',
|
||||||
|
'user_id': user.userId,
|
||||||
|
'access_token': user.accessToken,
|
||||||
|
'refresh_token': user.refreshToken
|
||||||
|
};
|
||||||
|
print(data);
|
||||||
|
final response = await _refreshDio.post(
|
||||||
|
'$baseUrl/$kRefreshTokenUrl',
|
||||||
|
data: data,
|
||||||
|
options: Options(
|
||||||
|
followRedirects: false,
|
||||||
|
validateStatus: (status) => true,
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
print('Refresh response');
|
||||||
|
print(response.data);
|
||||||
|
await _authenticationService.saveTokens(
|
||||||
|
access: response.data['access_token'],
|
||||||
|
refresh: response.data['refresh_token'],
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
print('Refresh response exception');
|
||||||
|
print(e.toString());
|
||||||
|
// await _authenticationService.logOut();
|
||||||
|
// await _navigationService.replaceWithLoginView();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isRefreshRequest(RequestOptions options) {
|
||||||
|
return options.path.contains(kRefreshTokenUrl);
|
||||||
|
}
|
||||||
|
|
||||||
Dio get dio => _dio;
|
Dio get dio => _dio;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
import 'package:battery_plus/battery_plus.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:in_app_update/in_app_update.dart';
|
||||||
|
import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart';
|
||||||
|
import 'package:storage_info/storage_info.dart';
|
||||||
|
import 'package:yimaru_app/services/secure_storage_service.dart';
|
||||||
|
|
||||||
|
import '../app/app.locator.dart';
|
||||||
|
|
||||||
|
class StatusCheckerService {
|
||||||
|
final storage = locator<SecureStorageService>();
|
||||||
|
|
||||||
|
bool _previousConnection = true;
|
||||||
|
|
||||||
|
bool get previousConnection => _previousConnection;
|
||||||
|
|
||||||
|
Future<int> getBatteryLevel() async {
|
||||||
|
final battery = Battery();
|
||||||
|
final batteryLevel = await battery.batteryLevel;
|
||||||
|
return batteryLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> userAuthenticated() async {
|
||||||
|
await checkAndUpdate();
|
||||||
|
|
||||||
|
if (await storage.getString('authenticated') != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> checkConnection() async {
|
||||||
|
if (await InternetConnection().hasInternetAccess) {
|
||||||
|
_previousConnection = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (_previousConnection) {
|
||||||
|
// showErrorToast('Check your internet connection');
|
||||||
|
_previousConnection = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<int> getAvailableStorage() async {
|
||||||
|
try {
|
||||||
|
final availableStorage =
|
||||||
|
await StorageInfo().getStorageFreeSpace(SpaceUnit.Bytes);
|
||||||
|
return availableStorage.toInt(); // Convert GB to bytes
|
||||||
|
} catch (e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> checkAndUpdate() async {
|
||||||
|
const requiredStorage = 500 * 1024 * 1024;
|
||||||
|
|
||||||
|
final batteryLevel =
|
||||||
|
await getBatteryLevel(); // Implement getBatteryLevel function
|
||||||
|
final int storageAvailable =
|
||||||
|
await getAvailableStorage(); // Implement getAvailableStorage
|
||||||
|
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
||||||
|
if (batteryLevel < 20 || storageAvailable < requiredStorage) {
|
||||||
|
// KewedeConst().showErrorToast(
|
||||||
|
// 'Unable to update app, please charge your phone & free up space.');
|
||||||
|
} else if (batteryLevel < 20) {
|
||||||
|
// KewedeConst()
|
||||||
|
// .showErrorToast('Unable to update app, please charge your phone.');
|
||||||
|
} else if (storageAvailable < requiredStorage) {
|
||||||
|
// KewedeConst()
|
||||||
|
// .showErrorToast('Unable to update app, please free up space.');
|
||||||
|
}
|
||||||
|
// Show user-friendly message explaining why update failed and suggesting solutions (e.g., charge device, free up space)
|
||||||
|
return; // Prevent update from starting
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (await checkConnection()) {
|
||||||
|
await InAppUpdate
|
||||||
|
.checkForUpdate(); // Continue update only if sufficient resources available
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... rest of your update logic ...
|
||||||
|
} on PlatformException {
|
||||||
|
// Handle specific error code for better user experience and potentially different error messages for each issue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
//String baseUrl = 'http://195.35.29.82:8080';
|
String baseUrl = 'http://195.35.29.82:8080';
|
||||||
String baseUrl = 'https://api.yimaru.yaltopia.com';
|
//String baseUrl = 'https://api.yimaru.yaltopia.com';
|
||||||
|
|
||||||
String userUrl = 'api/v1/user';
|
String userUrl = 'api/v1/user';
|
||||||
|
|
||||||
|
|
@ -9,6 +9,10 @@ String kVerifyOtpUrl = 'verify-otp';
|
||||||
|
|
||||||
String kResendOtpUrl = 'resend-otp';
|
String kResendOtpUrl = 'resend-otp';
|
||||||
|
|
||||||
|
String kRefreshTokenUrl = 'api/v1/auth/refresh';
|
||||||
|
|
||||||
String kLoginUrl = 'api/v1/auth/customer-login';
|
String kLoginUrl = 'api/v1/auth/customer-login';
|
||||||
|
|
||||||
String kProfileStatusUrl = 'is-profile-completed';
|
String kProfileStatusUrl = 'is-profile-completed';
|
||||||
|
|
||||||
|
String kAssessmentsUrl = 'api/v1/assessment/questions';
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,6 @@ enum RegistrationType { phone, email }
|
||||||
enum ResponseStatus { success, failure }
|
enum ResponseStatus { success, failure }
|
||||||
|
|
||||||
enum LearnLevelStatus { pending, started, completed }
|
enum LearnLevelStatus { pending, started, completed }
|
||||||
|
|
||||||
|
// Levels
|
||||||
|
enum ProficiencyLevels { a1, a2, b1, b2, none }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
Map<String, String> splitFullName(String fullName) {
|
||||||
|
final parts = fullName.trim().split(RegExp(r'\s+'));
|
||||||
|
|
||||||
|
if (parts.length == 1) {
|
||||||
|
return {
|
||||||
|
'last_name': '',
|
||||||
|
'nick_name': parts[0],
|
||||||
|
'first_name': parts[0],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'nick_name': parts.first,
|
||||||
|
'first_name': parts.first,
|
||||||
|
'last_name': parts.sublist(1).join(' '),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -252,7 +252,8 @@ void showErrorToast(String message) {
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
style: ToastificationStyle.fillColored,
|
style: ToastificationStyle.fillColored,
|
||||||
description: buildToastDescription(message),
|
description: buildToastDescription(message),
|
||||||
autoCloseDuration: const Duration(seconds: 10),
|
borderSide: const BorderSide(color: kcWhite),
|
||||||
|
autoCloseDuration: const Duration(seconds: 5),
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 15),
|
margin: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +270,8 @@ void showSuccessToast(String message) {
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
style: ToastificationStyle.fillColored,
|
style: ToastificationStyle.fillColored,
|
||||||
description: buildToastDescription(message),
|
description: buildToastDescription(message),
|
||||||
autoCloseDuration: const Duration(seconds: 10),
|
borderSide: const BorderSide(color: kcWhite),
|
||||||
|
autoCloseDuration: const Duration(seconds: 5),
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 15),
|
margin: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/Assessment_form_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/assessment_completion_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/assessment_failure_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/assessment_intro_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/assessment_result_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/result_analysis_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/retake_assessment_screen.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/screens/start_lesson_screen.dart';
|
||||||
|
|
||||||
|
import 'assessment_viewmodel.dart';
|
||||||
|
|
||||||
|
class AssessmentView extends StackedView<AssessmentViewModel> {
|
||||||
|
final Map<String, dynamic> data;
|
||||||
|
|
||||||
|
const AssessmentView({Key? key, required this.data}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onViewModelReady(AssessmentViewModel viewModel) {
|
||||||
|
viewModel.getAssessments();
|
||||||
|
viewModel.initUserData(data);
|
||||||
|
super.onViewModelReady(viewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget builder(
|
||||||
|
BuildContext context,
|
||||||
|
AssessmentViewModel viewModel,
|
||||||
|
Widget? child,
|
||||||
|
) =>
|
||||||
|
_buildAssessmentScreens(viewModel);
|
||||||
|
|
||||||
|
Widget _buildAssessmentScreens(AssessmentViewModel viewModel) => IndexedStack(
|
||||||
|
index: viewModel.currentPage,
|
||||||
|
children: _buildScreens(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildScreens() => [
|
||||||
|
_buildAssessmentIntro(),
|
||||||
|
_buildAssessment(),
|
||||||
|
// _buildAssessmentFailure(),
|
||||||
|
// _buildRetakeAssessment(),
|
||||||
|
// _buildResultAnalysis(),
|
||||||
|
// _buildAssessmentCompletion(),
|
||||||
|
_buildAssessmentResult(),
|
||||||
|
_buildStartLesson(),
|
||||||
|
];
|
||||||
|
|
||||||
|
Widget _buildAssessmentIntro() => const AssessmentIntroScreen();
|
||||||
|
|
||||||
|
Widget _buildAssessment() => const AssessmentFormScreen();
|
||||||
|
|
||||||
|
Widget _buildAssessmentFailure() => const AssessmentFailureScreen();
|
||||||
|
|
||||||
|
Widget _buildRetakeAssessment() => const RetakeAssessmentScreen();
|
||||||
|
|
||||||
|
Widget _buildResultAnalysis() => const ResultAnalysisScreen();
|
||||||
|
|
||||||
|
Widget _buildAssessmentCompletion() => const AssessmentCompletionScreen();
|
||||||
|
|
||||||
|
Widget _buildAssessmentResult() => const AssessmentResultScreen();
|
||||||
|
|
||||||
|
Widget _buildStartLesson() => const StartLessonScreen();
|
||||||
|
|
||||||
|
@override
|
||||||
|
AssessmentViewModel viewModelBuilder(
|
||||||
|
BuildContext context,
|
||||||
|
) =>
|
||||||
|
AssessmentViewModel();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,252 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
|
|
||||||
|
import '../../../app/app.locator.dart';
|
||||||
|
import '../../../app/app.router.dart';
|
||||||
|
import '../../../models/assessment.dart';
|
||||||
|
import '../../../models/user_model.dart';
|
||||||
|
import '../../../services/api_service.dart';
|
||||||
|
import '../../../services/authentication_service.dart';
|
||||||
|
import '../home/home_view.dart';
|
||||||
|
|
||||||
|
class AssessmentViewModel extends BaseViewModel {
|
||||||
|
final _apiService = locator<ApiService>();
|
||||||
|
final _navigationService = locator<NavigationService>();
|
||||||
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
|
int _currentPage = 0;
|
||||||
|
|
||||||
|
int get currentPage => _currentPage;
|
||||||
|
|
||||||
|
final PageController _pageController = PageController();
|
||||||
|
|
||||||
|
PageController get pageController => _pageController;
|
||||||
|
|
||||||
|
int _previousPage = 0;
|
||||||
|
|
||||||
|
int get previousPage => _previousPage;
|
||||||
|
|
||||||
|
// Assessment
|
||||||
|
|
||||||
|
int _currentQuestion = 0;
|
||||||
|
|
||||||
|
int get currentQuestion => _currentQuestion;
|
||||||
|
|
||||||
|
ProficiencyLevels _proficiencyLevel = ProficiencyLevels.none;
|
||||||
|
|
||||||
|
ProficiencyLevels get proficiencyLevel => _proficiencyLevel;
|
||||||
|
|
||||||
|
List<Assessment> _assessments = [];
|
||||||
|
|
||||||
|
List<Assessment> get assessments => _assessments;
|
||||||
|
|
||||||
|
final Map<String, dynamic> _selectedAnswers = {};
|
||||||
|
|
||||||
|
Map<String, dynamic> get selectedAnswers => _selectedAnswers;
|
||||||
|
|
||||||
|
// User data
|
||||||
|
final Map<String, dynamic> _userData = {};
|
||||||
|
|
||||||
|
Map<String, dynamic> get userData => _userData;
|
||||||
|
|
||||||
|
// Assessment
|
||||||
|
|
||||||
|
int countCorrectAnswersUntil(int untilQuestion) {
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i <= untilQuestion; i++) {
|
||||||
|
final answer = _selectedAnswers[i.toString()];
|
||||||
|
|
||||||
|
if (answer is Map<String, dynamic> && answer['correct'] == true) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> evaluateAssessment() {
|
||||||
|
if (_currentQuestion == 5) {
|
||||||
|
// A1
|
||||||
|
final correctCount = countCorrectAnswersUntil(5);
|
||||||
|
print('All : $_selectedAnswers');
|
||||||
|
print('Question page : $_currentQuestion');
|
||||||
|
print('Correct A1: $correctCount');
|
||||||
|
|
||||||
|
if (correctCount > 3) {
|
||||||
|
return {'continue': true, 'level': ProficiencyLevels.a1};
|
||||||
|
} else {
|
||||||
|
return {'continue': false, 'level': ProficiencyLevels.a1};
|
||||||
|
}
|
||||||
|
} else if (_currentQuestion == 10) {
|
||||||
|
// A2
|
||||||
|
|
||||||
|
final correctCount = countCorrectAnswersUntil(10);
|
||||||
|
print('All : $_selectedAnswers');
|
||||||
|
print('Question page : $_currentQuestion');
|
||||||
|
print('Correct A2: $correctCount');
|
||||||
|
|
||||||
|
if (correctCount > 3) {
|
||||||
|
return {'continue': true, 'level': ProficiencyLevels.a2};
|
||||||
|
} else {
|
||||||
|
return {'continue': false, 'level': ProficiencyLevels.a2};
|
||||||
|
}
|
||||||
|
} else if (_currentQuestion == 16) {
|
||||||
|
// B1
|
||||||
|
final correctCount = countCorrectAnswersUntil(16);
|
||||||
|
print('All : $_selectedAnswers');
|
||||||
|
print('Question page : $_currentQuestion');
|
||||||
|
print('Correct B1: $correctCount');
|
||||||
|
|
||||||
|
if (correctCount > 4) {
|
||||||
|
return {'continue': true, 'level': ProficiencyLevels.b1};
|
||||||
|
} else {
|
||||||
|
return {'continue': false, 'level': ProficiencyLevels.b1};
|
||||||
|
}
|
||||||
|
} else if (_currentQuestion == 22) {
|
||||||
|
final correctCount = countCorrectAnswersUntil(16);
|
||||||
|
print('All : $_selectedAnswers');
|
||||||
|
print('Question page : $_currentQuestion');
|
||||||
|
print('Correct B2: $correctCount');
|
||||||
|
|
||||||
|
if (correctCount > 4) {
|
||||||
|
return {'continue': true, 'level': ProficiencyLevels.b2};
|
||||||
|
} else {
|
||||||
|
return {'continue': false, 'level': ProficiencyLevels.b2};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {'continue': true, 'level': ProficiencyLevels.none};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSelectedAnswer({required int question, required String option}) {
|
||||||
|
bool correct = false;
|
||||||
|
final generator = Random();
|
||||||
|
int random = generator.nextInt(4);
|
||||||
|
if (option == _assessments[question - 1].options?[random].optionText) {
|
||||||
|
correct = true;
|
||||||
|
}
|
||||||
|
final data = {
|
||||||
|
question.toString(): {
|
||||||
|
'option': option,
|
||||||
|
'correct': correct,
|
||||||
|
'answer': _assessments[question - 1].options?[random].optionText
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_selectedAnswers.addAll(data);
|
||||||
|
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSelectedAnswer({required int question, required String answer}) {
|
||||||
|
return _selectedAnswers[question.toString()]?['option'] == answer;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getAssessments() async {
|
||||||
|
_assessments = await runBusyFuture<List<Assessment>>(_getAssessments());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Assessment>> _getAssessments() async {
|
||||||
|
List<Assessment> response = await _apiService.getAssessments();
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; i++) {
|
||||||
|
final generator = Random();
|
||||||
|
int random = generator.nextInt(15);
|
||||||
|
response.add(response[random]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add user data
|
||||||
|
void initUserData(Map<String, dynamic> data) {
|
||||||
|
clearUserData();
|
||||||
|
_userData.addAll(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addUserData(Map<String, dynamic> data) {
|
||||||
|
_userData.addAll(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearUserData() {
|
||||||
|
_userData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complete profile
|
||||||
|
Future<void> completeProfile() async {
|
||||||
|
Map<String, dynamic> response =
|
||||||
|
await runBusyFuture<Map<String, dynamic>>(_completeProfile());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _completeProfile() async {
|
||||||
|
print(_userData);
|
||||||
|
UserModel user = await _authenticationService.getUser();
|
||||||
|
Map<String, dynamic> response =
|
||||||
|
await _apiService.updateProfile(data: _userData, user: user);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
|
||||||
|
void nextQuestion() {
|
||||||
|
_currentQuestion++;
|
||||||
|
Map<String, dynamic> response = evaluateAssessment();
|
||||||
|
|
||||||
|
if (response['level'] == ProficiencyLevels.none) {
|
||||||
|
_pageController.jumpToPage(_currentQuestion);
|
||||||
|
} else {
|
||||||
|
if (response['continue']) {
|
||||||
|
_pageController.jumpToPage(_currentQuestion);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
_proficiencyLevel = response['level'];
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void previousQuestion() {
|
||||||
|
if (_currentQuestion != 0) {
|
||||||
|
_currentQuestion--;
|
||||||
|
_pageController.previousPage(
|
||||||
|
duration: const Duration(microseconds: 100), curve: Curves.linear);
|
||||||
|
rebuildUi();
|
||||||
|
} else {
|
||||||
|
_navigationService.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void next({int? page}) async {
|
||||||
|
if (page == null) {
|
||||||
|
if (_previousPage != 0) {
|
||||||
|
_currentPage = _previousPage;
|
||||||
|
} else {
|
||||||
|
_currentPage++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_previousPage = _currentPage;
|
||||||
|
_currentPage = page;
|
||||||
|
}
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop() {
|
||||||
|
if (_currentPage != 0) {
|
||||||
|
_currentPage--;
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> navigateToLanguage() async =>
|
||||||
|
await _navigationService.navigateToLanguageView();
|
||||||
|
|
||||||
|
Future<void> replaceWithHome() async =>
|
||||||
|
await _navigationService.clearStackAndShowView(const HomeView());
|
||||||
|
}
|
||||||
|
|
@ -3,28 +3,28 @@ import 'package:flutter_svg/svg.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';
|
||||||
|
import 'package:yimaru_app/ui/views/assessment/assessment_viewmodel.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class AssessmentCompletionScreen extends ViewModelWidget<OnboardingViewModel> {
|
class AssessmentCompletionScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
const AssessmentCompletionScreen({super.key});
|
const AssessmentCompletionScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildAppBar(), _buildExpandedBody(viewModel)];
|
[_buildAppBar(), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildAppBar() => const LargeAppBar(
|
Widget _buildAppBar() => const LargeAppBar(
|
||||||
|
|
@ -32,30 +32,30 @@ class AssessmentCompletionScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showLanguageSelection: false,
|
showLanguageSelection: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(viewModel),
|
children: _buildBodyChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildBodyChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
||||||
|
|
||||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildUpperColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildIcon(),
|
_buildIcon(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
|
@ -84,12 +84,12 @@ class AssessmentCompletionScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
|
|
@ -4,62 +4,61 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class AssessmentFailureScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../assessment_viewmodel.dart';
|
||||||
|
|
||||||
|
class AssessmentFailureScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
const AssessmentFailureScreen({super.key});
|
const AssessmentFailureScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(viewModel),
|
children: _buildBodyChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildBodyChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
||||||
|
|
||||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildUpperColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildIcon(),
|
_buildIcon(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
|
@ -86,18 +85,18 @@ class AssessmentFailureScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLowerColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildLowerColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: _buildLowerColumnChildren(viewModel),
|
children: _buildLowerColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSkipButtonWrapper(viewModel)
|
_buildSkipButtonWrapper(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
safe: false,
|
safe: false,
|
||||||
|
|
@ -108,12 +107,12 @@ class AssessmentFailureScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildSkipButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildSkipButton(viewModel),
|
child: _buildSkipButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButton(OnboardingViewModel viewModel) =>
|
Widget _buildSkipButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Skip',
|
text: 'Skip',
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
import 'package:flutter/material.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/widgets/custom_small_radio_button.dart';
|
||||||
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
|
import '../assessment_viewmodel.dart';
|
||||||
|
import 'assessment_loading_screen.dart';
|
||||||
|
|
||||||
|
class AssessmentFormScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
|
const AssessmentFormScreen({super.key});
|
||||||
|
|
||||||
|
//final PageController _pageController = PageController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
|
_buildAssessmentScreens(viewModel);
|
||||||
|
|
||||||
|
Widget _buildAssessmentScreens(AssessmentViewModel viewModel) =>
|
||||||
|
viewModel.isBusy
|
||||||
|
? _buildPageLoadingIndicator()
|
||||||
|
: _buildAssessmentScreensWrapper(viewModel);
|
||||||
|
|
||||||
|
Widget _buildPageLoadingIndicator() => const AssessmentLoadingScreen();
|
||||||
|
|
||||||
|
Widget _buildAssessmentScreensWrapper(AssessmentViewModel viewModel) =>
|
||||||
|
PopScope(
|
||||||
|
canPop: false,
|
||||||
|
onPopInvokedWithResult: (value, data) => viewModel.previousQuestion(),
|
||||||
|
child: _buildScaffoldWrapper(viewModel));
|
||||||
|
|
||||||
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
|
backgroundColor: kcBackgroundColor,
|
||||||
|
body: _buildScaffold(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: _buildScaffoldChildren(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
|
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
|
||||||
|
showBackButton: true,
|
||||||
|
showLanguageSelection: false,
|
||||||
|
onPop: viewModel.previousQuestion,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
|
child: _buildAssessment(viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildAssessment(AssessmentViewModel viewModel) => PageView.builder(
|
||||||
|
controller: viewModel.pageController,
|
||||||
|
itemCount: viewModel.assessments.length,
|
||||||
|
itemBuilder: (cotext, index) =>
|
||||||
|
_buildBody(index: index, viewModel: viewModel));
|
||||||
|
|
||||||
|
Widget _buildBody(
|
||||||
|
{required int index, required AssessmentViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: _buildBodyChildren(viewModel: viewModel, index: index),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildBodyChildren(
|
||||||
|
{required int index, required AssessmentViewModel viewModel}) =>
|
||||||
|
[
|
||||||
|
_buildUpperColumnWrapper(viewModel: viewModel, index: index),
|
||||||
|
_buildContinueButtonWrapper(viewModel: viewModel, question: index + 1)
|
||||||
|
];
|
||||||
|
|
||||||
|
Widget _buildUpperColumnWrapper(
|
||||||
|
{required int index, required AssessmentViewModel viewModel}) =>
|
||||||
|
Expanded(
|
||||||
|
child: _buildUpperColumn(index: index, viewModel: viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildUpperColumn(
|
||||||
|
{required int index, required AssessmentViewModel viewModel}) =>
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: _buildUpperColumnChildren(index: index, viewModel: viewModel),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildUpperColumnChildren(
|
||||||
|
{required int index, required AssessmentViewModel viewModel}) =>
|
||||||
|
[
|
||||||
|
verticalSpaceMedium,
|
||||||
|
_buildTitle(index: index, viewModel: viewModel),
|
||||||
|
verticalSpaceMedium,
|
||||||
|
_buildAnswers(index: index, viewModel: viewModel)
|
||||||
|
];
|
||||||
|
|
||||||
|
Widget _buildTitle(
|
||||||
|
{required int index, required AssessmentViewModel viewModel}) =>
|
||||||
|
Text(
|
||||||
|
'Q${index + 1}. ${viewModel.assessments[index].question?.title} ',
|
||||||
|
style: style16DG600,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildAnswers(
|
||||||
|
{required int index, required AssessmentViewModel viewModel}) =>
|
||||||
|
ListView.builder(
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemCount: viewModel.assessments[index].options?.length,
|
||||||
|
itemBuilder: (context, inner) => _buildAnswer(
|
||||||
|
title: viewModel.assessments[index].options?[inner].optionText ?? '',
|
||||||
|
selected: viewModel.isSelectedAnswer(
|
||||||
|
question: index + 1,
|
||||||
|
answer: viewModel.assessments[index].options?[inner].optionText ??
|
||||||
|
''),
|
||||||
|
onTap: () => viewModel.setSelectedAnswer(
|
||||||
|
question: index + 1,
|
||||||
|
option: viewModel.assessments[index].options?[inner].optionText ??
|
||||||
|
''),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildAnswer(
|
||||||
|
{required String title,
|
||||||
|
required bool selected,
|
||||||
|
required GestureTapCallback onTap}) =>
|
||||||
|
CustomSmallRadioButton(
|
||||||
|
title: title,
|
||||||
|
onTap: onTap,
|
||||||
|
selected: selected,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildContinueButtonWrapper(
|
||||||
|
{required int question, required AssessmentViewModel viewModel}) =>
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
|
child: _buildContinueButton(viewModel: viewModel, question: question),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildContinueButton(
|
||||||
|
{required int question, required AssessmentViewModel viewModel}) =>
|
||||||
|
CustomElevatedButton(
|
||||||
|
height: 55,
|
||||||
|
borderRadius: 12,
|
||||||
|
foregroundColor: kcWhite,
|
||||||
|
text: viewModel.currentQuestion == viewModel.assessments.length - 1
|
||||||
|
? 'Finish'
|
||||||
|
: 'Continue',
|
||||||
|
backgroundColor:
|
||||||
|
viewModel.selectedAnswers.containsKey(question.toString())
|
||||||
|
? kcPrimaryColor
|
||||||
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
|
onTap: viewModel.selectedAnswers.containsKey(question.toString())
|
||||||
|
?
|
||||||
|
// viewModel.currentQuestion == viewModel.assessments.length - 1
|
||||||
|
// ? () => viewModel.next()
|
||||||
|
// :
|
||||||
|
() => viewModel.nextQuestion()
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -3,66 +3,65 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class AssessmentIntroScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../assessment_viewmodel.dart';
|
||||||
|
|
||||||
|
class AssessmentIntroScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
const AssessmentIntroScreen({super.key});
|
const AssessmentIntroScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(viewModel),
|
children: _buildBodyChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildBodyChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
||||||
|
|
||||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildUpperColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSubTitle(),
|
_buildSubTitle(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'Want a quick assessment to know your English level?',
|
'Want a quick assessment to know your English level?',
|
||||||
|
|
@ -78,18 +77,18 @@ class AssessmentIntroScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLowerColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildLowerColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: _buildLowerColumnChildren(viewModel),
|
children: _buildLowerColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSkipButtonWrapper(viewModel)
|
_buildSkipButtonWrapper(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
safe: false,
|
safe: false,
|
||||||
|
|
@ -100,18 +99,19 @@ class AssessmentIntroScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildSkipButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildSkipButton(viewModel),
|
child: _buildSkipButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButton(OnboardingViewModel viewModel) =>
|
Widget _buildSkipButton(AssessmentViewModel viewModel) =>
|
||||||
const CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Skip',
|
text: 'Skip',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
borderColor: kcPrimaryColor,
|
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
|
borderColor: kcPrimaryColor,
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
|
onTap: () => viewModel.next(page: 3),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:yimaru_app/ui/widgets/page_loading_indicator.dart';
|
||||||
|
|
||||||
|
import '../../../common/app_colors.dart';
|
||||||
|
import '../../../widgets/large_app_bar.dart';
|
||||||
|
|
||||||
|
class AssessmentLoadingScreen extends StatelessWidget {
|
||||||
|
const AssessmentLoadingScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => _buildScaffoldWrapper();
|
||||||
|
|
||||||
|
Widget _buildScaffoldWrapper() => Scaffold(
|
||||||
|
backgroundColor: kcBackgroundColor,
|
||||||
|
body: _buildScaffold(),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildScaffold() => Stack(
|
||||||
|
children: [_buildColumn(), _buildPageIndicator()],
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildColumn() => Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: _buildColumnChildren(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildColumnChildren() => [_buildAppBar(), _buildBody()];
|
||||||
|
|
||||||
|
Widget _buildAppBar() => const LargeAppBar(
|
||||||
|
showBackButton: true,
|
||||||
|
showLanguageSelection: true,
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildBody() => Expanded(child: Container());
|
||||||
|
|
||||||
|
Widget _buildPageIndicator() => const PageLoadingIndicator();
|
||||||
|
}
|
||||||
|
|
@ -4,64 +4,63 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class AssessmentResultScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../assessment_viewmodel.dart';
|
||||||
|
|
||||||
|
class AssessmentResultScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
const AssessmentResultScreen({super.key});
|
const AssessmentResultScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(viewModel),
|
children: _buildBodyChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildBodyChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
||||||
|
|
||||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildUpperColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildTitle(),
|
_buildTitle(viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildPrimarySubTitle(),
|
_buildPrimarySubTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
|
@ -70,10 +69,10 @@ class AssessmentResultScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
_buildSecondarySubTitle()
|
_buildSecondarySubTitle()
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle(AssessmentViewModel viewModel) => Text(
|
||||||
'You’re likely a B1 speaker!',
|
'You’re likely a ${viewModel.proficiencyLevel.name.toUpperCase()} speaker!',
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 25,
|
fontSize: 25,
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -94,18 +93,18 @@ class AssessmentResultScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLowerColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildLowerColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: _buildLowerColumnChildren(viewModel),
|
children: _buildLowerColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSkipButtonWrapper(viewModel)
|
_buildSkipButtonWrapper(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
safe: false,
|
safe: false,
|
||||||
|
|
@ -116,12 +115,12 @@ class AssessmentResultScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildSkipButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildSkipButton(viewModel),
|
child: _buildSkipButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButton(OnboardingViewModel viewModel) =>
|
Widget _buildSkipButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
|
|
@ -3,45 +3,46 @@ import 'package:flutter_svg/svg.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';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class ResultAnalysisScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../assessment_viewmodel.dart';
|
||||||
|
|
||||||
|
class ResultAnalysisScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
const ResultAnalysisScreen({super.key});
|
const ResultAnalysisScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
verticalSpaceMassive,
|
verticalSpaceMassive,
|
||||||
_buildIcon(),
|
_buildIcon(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
|
@ -50,11 +51,11 @@ class ResultAnalysisScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
_buildSubTitle(),
|
_buildSubTitle(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(language: false));
|
);
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
Widget _buildIcon() => SvgPicture.asset(
|
||||||
'assets/icons/progress_indicator.svg',
|
'assets/icons/progress_indicator.svg',
|
||||||
|
|
@ -3,54 +3,55 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class RetakeAssessmentScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../assessment_viewmodel.dart';
|
||||||
|
|
||||||
|
class RetakeAssessmentScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
const RetakeAssessmentScreen({super.key});
|
const RetakeAssessmentScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(viewModel),
|
children: _buildBodyChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildBodyChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
[_buildUpperColumn(viewModel), _buildLowerColumn(viewModel)];
|
||||||
|
|
||||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildUpperColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildIcon(),
|
_buildIcon(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
|
|
@ -59,11 +60,11 @@ class RetakeAssessmentScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
_buildSubTitle(),
|
_buildSubTitle(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(AssessmentViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(language: false));
|
);
|
||||||
|
|
||||||
Widget _buildIcon() => const Icon(
|
Widget _buildIcon() => const Icon(
|
||||||
Icons.warning_amber_rounded,
|
Icons.warning_amber_rounded,
|
||||||
|
|
@ -87,18 +88,18 @@ class RetakeAssessmentScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLowerColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildLowerColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: _buildLowerColumnChildren(viewModel),
|
children: _buildLowerColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildLowerColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildLowerColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
_buildContinueButton(viewModel),
|
_buildContinueButton(viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSkipButtonWrapper(viewModel)
|
_buildSkipButtonWrapper(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
safe: false,
|
safe: false,
|
||||||
|
|
@ -109,12 +110,12 @@ class RetakeAssessmentScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildSkipButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildSkipButton(viewModel),
|
child: _buildSkipButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSkipButton(OnboardingViewModel viewModel) =>
|
Widget _buildSkipButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Skip',
|
text: 'Skip',
|
||||||
|
|
@ -4,27 +4,42 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class StartLessonScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../../../common/enmus.dart';
|
||||||
|
import '../assessment_viewmodel.dart';
|
||||||
|
|
||||||
|
class StartLessonScreen extends ViewModelWidget<AssessmentViewModel> {
|
||||||
const StartLessonScreen({super.key});
|
const StartLessonScreen({super.key});
|
||||||
|
|
||||||
|
Future<void> _start(AssessmentViewModel viewModel) async {
|
||||||
|
if (viewModel.proficiencyLevel != ProficiencyLevels.none) {
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'preferred_language': 'en',
|
||||||
|
'knowledge_level': viewModel.proficiencyLevel.name.toUpperCase()
|
||||||
|
};
|
||||||
|
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
await viewModel.completeProfile();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, AssessmentViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(AssessmentViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Column(
|
Widget _buildScaffold(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildAppBar(), _buildExpandedBody(viewModel)];
|
[_buildAppBar(), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildAppBar() => const LargeAppBar(
|
Widget _buildAppBar() => const LargeAppBar(
|
||||||
|
|
@ -32,52 +47,52 @@ class StartLessonScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
showLanguageSelection: false,
|
showLanguageSelection: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(AssessmentViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBody(OnboardingViewModel viewModel) => Column(
|
Widget _buildBody(AssessmentViewModel viewModel) => Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildBodyChildren(viewModel),
|
children: _buildBodyChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildBodyChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildBodyChildren(AssessmentViewModel viewModel) =>
|
||||||
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
[_buildUpperColumn(viewModel), _buildContinueButtonWrapper(viewModel)];
|
||||||
|
|
||||||
Widget _buildUpperColumn(OnboardingViewModel viewModel) => Column(
|
Widget _buildUpperColumn(AssessmentViewModel viewModel) => Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: _buildUpperColumnChildren(viewModel),
|
children: _buildUpperColumnChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(AssessmentViewModel viewModel) => [
|
||||||
verticalSpaceLarge,
|
verticalSpaceLarge,
|
||||||
_buildIcon(),
|
_buildIcon(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(viewModel),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildSubTitle(),
|
_buildSubTitle(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset('assets/icons/mascot.svg');
|
Widget _buildIcon() => SvgPicture.asset('assets/icons/mascot.svg');
|
||||||
|
|
||||||
Widget _buildTitle() => const Text.rich(
|
Widget _buildTitle(AssessmentViewModel viewModel) => Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'Welcome aboard',
|
text: 'Welcome aboard',
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 25,
|
fontSize: 25,
|
||||||
color: kcDarkGrey,
|
color: kcDarkGrey,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: ', Bisrat!',
|
text: ', ${viewModel.userData['first_name']}!',
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 25,
|
fontSize: 25,
|
||||||
color: kcPrimaryColor,
|
color: kcPrimaryColor,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -91,18 +106,18 @@ class StartLessonScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(AssessmentViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50),
|
padding: const EdgeInsets.only(bottom: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(AssessmentViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
text: 'Go to My Lessons',
|
text: 'Go to My Lessons',
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
onTap: () async => await viewModel.navigateToHome(),
|
onTap: () async => await _start(viewModel),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ 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/views/learn/learn_view.dart';
|
import 'package:yimaru_app/ui/views/learn/learn_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/profile/profile_view.dart';
|
import 'package:yimaru_app/ui/views/profile/profile_view.dart';
|
||||||
|
import 'package:yimaru_app/ui/views/startup/startup_view.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/coming_soon.dart';
|
import 'package:yimaru_app/ui/widgets/coming_soon.dart';
|
||||||
|
|
||||||
import 'home_viewmodel.dart';
|
import 'home_viewmodel.dart';
|
||||||
|
|
@ -22,18 +23,26 @@ class HomeView extends StackedView<HomeViewModel> {
|
||||||
@override
|
@override
|
||||||
Widget builder(
|
Widget builder(
|
||||||
BuildContext context, HomeViewModel viewModel, Widget? child) =>
|
BuildContext context, HomeViewModel viewModel, Widget? child) =>
|
||||||
_buildScaffold(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
|
Widget _buildScaffoldWrapper(HomeViewModel viewModel) => viewModel.isBusy
|
||||||
|
? const StartupView(
|
||||||
|
label: 'Checking user info',
|
||||||
|
)
|
||||||
|
: _buildScaffold(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffold(HomeViewModel viewModel) => Scaffold(
|
Widget _buildScaffold(HomeViewModel viewModel) => Scaffold(
|
||||||
body: getViewForIndex(viewModel.currentIndex),
|
body: getViewForIndex(viewModel.currentIndex),
|
||||||
bottomNavigationBar: BottomNavigationBar(
|
bottomNavigationBar: _buildBottomNav(viewModel),
|
||||||
onTap: viewModel.setCurrentIndex,
|
);
|
||||||
items: _buildNavBarItems(),
|
|
||||||
selectedItemColor: kcPrimaryColor,
|
Widget _buildBottomNav(HomeViewModel viewModel) => BottomNavigationBar(
|
||||||
backgroundColor: kcBackgroundColor,
|
onTap: viewModel.setCurrentIndex,
|
||||||
type: BottomNavigationBarType.fixed,
|
items: _buildNavBarItems(),
|
||||||
currentIndex: viewModel.currentIndex,
|
selectedItemColor: kcPrimaryColor,
|
||||||
),
|
backgroundColor: kcBackgroundColor,
|
||||||
|
type: BottomNavigationBarType.fixed,
|
||||||
|
currentIndex: viewModel.currentIndex,
|
||||||
);
|
);
|
||||||
|
|
||||||
List<BottomNavigationBarItem> _buildNavBarItems() => [
|
List<BottomNavigationBarItem> _buildNavBarItems() => [
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'package:yimaru_app/app/app.dialogs.dart';
|
||||||
import 'package:yimaru_app/app/app.locator.dart';
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
import 'package:yimaru_app/app/app.router.dart';
|
import 'package:yimaru_app/app/app.router.dart';
|
||||||
import 'package:yimaru_app/models/user_model.dart';
|
import 'package:yimaru_app/models/user_model.dart';
|
||||||
|
import 'package:yimaru_app/services/status_checker_service.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_strings.dart';
|
import 'package:yimaru_app/ui/common/app_strings.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
|
@ -14,6 +15,7 @@ import '../../common/enmus.dart';
|
||||||
class HomeViewModel extends BaseViewModel {
|
class HomeViewModel extends BaseViewModel {
|
||||||
final _apiService = locator<ApiService>();
|
final _apiService = locator<ApiService>();
|
||||||
final _dialogService = locator<DialogService>();
|
final _dialogService = locator<DialogService>();
|
||||||
|
final _statusChecker = locator<StatusCheckerService>();
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
final _bottomSheetService = locator<BottomSheetService>();
|
final _bottomSheetService = locator<BottomSheetService>();
|
||||||
final _authenticationService = locator<AuthenticationService>();
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
@ -30,16 +32,16 @@ class HomeViewModel extends BaseViewModel {
|
||||||
|
|
||||||
void showDialog() {
|
void showDialog() {
|
||||||
_dialogService.showCustomDialog(
|
_dialogService.showCustomDialog(
|
||||||
variant: DialogType.infoAlert,
|
|
||||||
title: 'Stacked Rocks!',
|
title: 'Stacked Rocks!',
|
||||||
|
variant: DialogType.infoAlert,
|
||||||
description: 'Give stacked stars on Github',
|
description: 'Give stacked stars on Github',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showBottomSheet() {
|
void showBottomSheet() {
|
||||||
_bottomSheetService.showCustomSheet(
|
_bottomSheetService.showCustomSheet(
|
||||||
variant: BottomSheetType.notice,
|
|
||||||
title: ksHomeBottomSheetTitle,
|
title: ksHomeBottomSheetTitle,
|
||||||
|
variant: BottomSheetType.notice,
|
||||||
description: ksHomeBottomSheetDescription,
|
description: ksHomeBottomSheetDescription,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -50,13 +52,27 @@ class HomeViewModel extends BaseViewModel {
|
||||||
|
|
||||||
// Remote api calls
|
// Remote api calls
|
||||||
Future<void> getProfileStatus() async {
|
Future<void> getProfileStatus() async {
|
||||||
UserModel user = await _authenticationService.getUser();
|
Map<String, dynamic> response =
|
||||||
|
await runBusyFuture<Map<String, dynamic>>(_getProfileStatus());
|
||||||
Map<String, dynamic> response = await runBusyFuture<Map<String, dynamic>>(
|
|
||||||
_apiService.getProfileStatus(user));
|
|
||||||
|
|
||||||
if (response['status'] == ResponseStatus.success && !response['data']) {
|
if (response['status'] == ResponseStatus.success && !response['data']) {
|
||||||
await replaceWithOnboarding();
|
await replaceWithOnboarding();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _getProfileStatus() async {
|
||||||
|
Map<String, dynamic> response = {};
|
||||||
|
UserModel user = await _authenticationService.getUser();
|
||||||
|
|
||||||
|
if (user.profileCompleted == null) {
|
||||||
|
if (await _statusChecker.checkConnection()) {
|
||||||
|
response = await _apiService.getProfileStatus(user);
|
||||||
|
} else {
|
||||||
|
response = {'data': false, 'status': ResponseStatus.success};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response = {'data': true, 'status': ResponseStatus.success};
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,11 @@ import 'package:flutter_timer_countdown/flutter_timer_countdown.dart';
|
||||||
import 'package:pinput/pinput.dart';
|
import 'package:pinput/pinput.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
import 'package:yimaru_app/ui/views/register/register_viewmodel.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/custom_cursor.dart';
|
import 'package:yimaru_app/ui/widgets/custom_cursor.dart';
|
||||||
|
|
||||||
import '../../../common/app_colors.dart';
|
import '../../../common/app_colors.dart';
|
||||||
import '../../../common/ui_helpers.dart';
|
import '../../../common/ui_helpers.dart';
|
||||||
import '../../../widgets/custom_elevated_button.dart';
|
import '../../../widgets/custom_elevated_button.dart';
|
||||||
import '../../../widgets/large_app_bar.dart';
|
|
||||||
import '../login_viewmodel.dart';
|
import '../login_viewmodel.dart';
|
||||||
import '../login_view.form.dart';
|
import '../login_view.form.dart';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -174,15 +174,14 @@ class LoginWithEmailScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: (viewModel.focusEmail &&
|
onTap: emailController.text.isNotEmpty &&
|
||||||
emailController.text.isNotEmpty) &&
|
passwordController.text.isNotEmpty
|
||||||
(viewModel.focusPassword && passwordController.text.isNotEmpty)
|
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
onTap: (viewModel.focusEmail && emailController.text.isNotEmpty) &&
|
|
||||||
(viewModel.focusPassword && passwordController.text.isNotEmpty)
|
|
||||||
? () async => await _login(viewModel)
|
? () async => await _login(viewModel)
|
||||||
: null,
|
: null,
|
||||||
|
backgroundColor: emailController.text.isNotEmpty &&
|
||||||
|
passwordController.text.isNotEmpty
|
||||||
|
? kcPrimaryColor
|
||||||
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
Widget _buildOptionTextDivider() => const OptionTextDivider();
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import '../login_view.form.dart';
|
||||||
|
|
||||||
class LoginWithPhoneNumberScreen extends ViewModelWidget<LoginViewModel> {
|
class LoginWithPhoneNumberScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
final TextEditingController phoneNumberController;
|
final TextEditingController phoneNumberController;
|
||||||
|
|
||||||
const LoginWithPhoneNumberScreen(
|
const LoginWithPhoneNumberScreen(
|
||||||
{super.key, required this.phoneNumberController});
|
{super.key, required this.phoneNumberController});
|
||||||
|
|
||||||
|
|
@ -68,10 +69,12 @@ class LoginWithPhoneNumberScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
Widget _buildSubTitleWrapper(LoginViewModel viewModel) => RegisterForAccount(
|
Widget _buildSubTitleWrapper(LoginViewModel viewModel) => RegisterForAccount(
|
||||||
onTap: () async => await viewModel.navigateToRegister(),
|
onTap: () async => await viewModel.navigateToRegister(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle() => const Text(
|
Widget _buildSubtitle() => const Text(
|
||||||
'Enter your phone number. We will send you a confirmation code there',
|
'Enter your phone number. We will send you a confirmation code there',
|
||||||
style: TextStyle(color: kcMediumGrey),
|
style: TextStyle(color: kcMediumGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildPhoneNumberWrapper(LoginViewModel viewModel) => Row(
|
Widget _buildPhoneNumberWrapper(LoginViewModel viewModel) => Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: _buildPhoneNumberChildren(viewModel),
|
children: _buildPhoneNumberChildren(viewModel),
|
||||||
|
|
@ -133,14 +136,12 @@ class LoginWithPhoneNumberScreen extends ViewModelWidget<LoginViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap:
|
onTap: phoneNumberController.text.isNotEmpty
|
||||||
viewModel.focusPhoneNumber && phoneNumberController.text.isNotEmpty
|
? () => viewModel.goTo(2)
|
||||||
? () => viewModel.goTo(2)
|
: null,
|
||||||
: null,
|
backgroundColor: phoneNumberController.text.isNotEmpty
|
||||||
backgroundColor:
|
? kcPrimaryColor
|
||||||
viewModel.focusPhoneNumber && phoneNumberController.text.isNotEmpty
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLoginWitPhoneNumberButton(LoginViewModel viewModel) =>
|
Widget _buildLoginWitPhoneNumberButton(LoginViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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/views/onboarding/screens/assessment/assessment_completion_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/assessment_failure_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/age_group_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/assessment_intro_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/birthday_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/assessment_result_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/challenge_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/first_assessment_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/country_region_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/fourth_assessment_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/educational_background_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/result_analysis_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/full_name_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/retake_assessment_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/gender_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/second_assessment_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/language_goal_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/start_lesson_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/learning_goal_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/assessment/third_assessment_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/occupation_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/age_group_form_screen.dart';
|
import 'package:yimaru_app/ui/views/onboarding/screens/topic_form_screen.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/challenge_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/country_region_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/educational_background_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/full_name_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/learning_goal_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/learning_reason_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/occupation_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/forms/topic_form_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/language_selector.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/welcome/first_welcome_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/welcome/second_welcome_screen.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/screens/welcome/third_welcome_screen.dart';
|
|
||||||
|
|
||||||
import '../../common/validators/form_validator.dart';
|
import '../../common/validators/form_validator.dart';
|
||||||
import 'onboarding_viewmodel.dart';
|
import 'onboarding_viewmodel.dart';
|
||||||
|
|
@ -35,7 +23,7 @@ import 'onboarding_view.form.dart';
|
||||||
FormTextField(name: 'fullName', validator: FormValidator.validateForm),
|
FormTextField(name: 'fullName', 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: 'learningReason', validator: FormValidator.validateForm),
|
FormTextField(name: 'languageGoal', validator: FormValidator.validateForm),
|
||||||
FormTextField(name: 'topic', validator: FormValidator.validateForm),
|
FormTextField(name: 'topic', validator: FormValidator.validateForm),
|
||||||
])
|
])
|
||||||
class OnboardingView extends StackedView<OnboardingViewModel>
|
class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
|
|
@ -70,8 +58,7 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
Widget _buildOnboardingScreensWrapper(OnboardingViewModel viewModel) =>
|
Widget _buildOnboardingScreensWrapper(OnboardingViewModel viewModel) =>
|
||||||
PopScope(
|
PopScope(
|
||||||
canPop: false,
|
canPop: false,
|
||||||
onPopInvokedWithResult: (value, data) => viewModel.pop(
|
onPopInvokedWithResult: (value, data) => viewModel.pop(),
|
||||||
language: viewModel.currentPage == 23 ? true : false),
|
|
||||||
child: _buildOnboardingScreens(viewModel));
|
child: _buildOnboardingScreens(viewModel));
|
||||||
|
|
||||||
Widget _buildOnboardingScreens(OnboardingViewModel viewModel) => IndexedStack(
|
Widget _buildOnboardingScreens(OnboardingViewModel viewModel) => IndexedStack(
|
||||||
|
|
@ -80,46 +67,31 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScreens() => [
|
List<Widget> _buildScreens() => [
|
||||||
_buildFirstWelcome(),
|
|
||||||
_buildSecondWelcome(),
|
|
||||||
_buildThirdWelcome(),
|
|
||||||
_buildFullNameForm(),
|
_buildFullNameForm(),
|
||||||
_buildEducationalBackgroundForm(),
|
_buildGenderForm(),
|
||||||
|
_buildBirthdayForm(),
|
||||||
_buildAgeGroupForm(),
|
_buildAgeGroupForm(),
|
||||||
|
_buildEducationalBackgroundForm(),
|
||||||
_buildOccupationForm(),
|
_buildOccupationForm(),
|
||||||
_buildCountryRegionForm(),
|
_buildCountryRegionForm(),
|
||||||
_buildLearningGoalForm(),
|
_buildLearningGoalForm(),
|
||||||
_buildLearningReasonForm(),
|
_buildLanguageGoalForm(),
|
||||||
_buildChallengeForm(),
|
_buildChallengeForm(),
|
||||||
_buildTopicForm(),
|
_buildTopicForm(),
|
||||||
_buildAssessmentIntro(),
|
|
||||||
_buildFirstAssessmentForm(),
|
|
||||||
_buildSecondAssessment(),
|
|
||||||
_buildThirdAssessment(),
|
|
||||||
_buildFourthAssessment(),
|
|
||||||
_buildAssessmentFailure(),
|
|
||||||
_buildRetakeAssessment(),
|
|
||||||
_buildResultAnalysis(),
|
|
||||||
_buildAssessmentCompletion(),
|
|
||||||
_buildAssessmentResult(),
|
|
||||||
_buildStartLesson(),
|
|
||||||
_buildLanguageSelector()
|
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildFirstWelcome() => const FirstWelcomeScreen();
|
|
||||||
|
|
||||||
Widget _buildSecondWelcome() => const SecondWelcomeScreen();
|
|
||||||
|
|
||||||
Widget _buildThirdWelcome() => const ThirdWelcomeScreen();
|
|
||||||
|
|
||||||
Widget _buildFullNameForm() =>
|
Widget _buildFullNameForm() =>
|
||||||
FullNameFormScreen(fullNameController: fullNameController);
|
FullNameFormScreen(fullNameController: fullNameController);
|
||||||
|
|
||||||
Widget _buildEducationalBackgroundForm() =>
|
Widget _buildGenderForm() => const GenderFormScreen();
|
||||||
const EducationalBackgroundFormScreen();
|
|
||||||
|
Widget _buildBirthdayForm() => const BirthdayFormScreen();
|
||||||
|
|
||||||
Widget _buildAgeGroupForm() => const AgeGroupFormScreen();
|
Widget _buildAgeGroupForm() => const AgeGroupFormScreen();
|
||||||
|
|
||||||
|
Widget _buildEducationalBackgroundForm() =>
|
||||||
|
const EducationalBackgroundFormScreen();
|
||||||
|
|
||||||
Widget _buildOccupationForm() =>
|
Widget _buildOccupationForm() =>
|
||||||
OccupationFormScreen(occupationController: occupationController);
|
OccupationFormScreen(occupationController: occupationController);
|
||||||
|
|
||||||
|
|
@ -127,36 +99,11 @@ class OnboardingView extends StackedView<OnboardingViewModel>
|
||||||
|
|
||||||
Widget _buildLearningGoalForm() => const LearningGoalFormScreen();
|
Widget _buildLearningGoalForm() => const LearningGoalFormScreen();
|
||||||
|
|
||||||
Widget _buildLearningReasonForm() => LearningReasonFormScreen(
|
Widget _buildLanguageGoalForm() =>
|
||||||
learningReasonController: learningReasonController);
|
LanguageGoalFormScreen(languageGoalController: languageGoalController);
|
||||||
|
|
||||||
Widget _buildChallengeForm() =>
|
Widget _buildChallengeForm() =>
|
||||||
ChallengeFormScreen(challengeController: challengeController);
|
ChallengeFormScreen(challengeController: challengeController);
|
||||||
|
|
||||||
Widget _buildTopicForm() => TopicFormScreen(topicController: topicController);
|
Widget _buildTopicForm() => TopicFormScreen(topicController: topicController);
|
||||||
|
|
||||||
Widget _buildAssessmentIntro() => const AssessmentIntroScreen();
|
|
||||||
|
|
||||||
Widget _buildFirstAssessmentForm() =>
|
|
||||||
FirstAssessmentFormScreen(answerController: answerController);
|
|
||||||
|
|
||||||
Widget _buildSecondAssessment() => const SecondAssessmentFormScreen();
|
|
||||||
|
|
||||||
Widget _buildThirdAssessment() => const ThirdAssessmentFormScreen();
|
|
||||||
|
|
||||||
Widget _buildFourthAssessment() => const FourthAssessmentFormScreen();
|
|
||||||
|
|
||||||
Widget _buildAssessmentFailure() => const AssessmentFailureScreen();
|
|
||||||
|
|
||||||
Widget _buildRetakeAssessment() => const RetakeAssessmentScreen();
|
|
||||||
|
|
||||||
Widget _buildResultAnalysis() => const ResultAnalysisScreen();
|
|
||||||
|
|
||||||
Widget _buildAssessmentCompletion() => const AssessmentCompletionScreen();
|
|
||||||
|
|
||||||
Widget _buildAssessmentResult() => const AssessmentResultScreen();
|
|
||||||
|
|
||||||
Widget _buildStartLesson() => const StartLessonScreen();
|
|
||||||
|
|
||||||
Widget _buildLanguageSelector() => const LanguageSelector();
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const String AnswerValueKey = 'answer';
|
||||||
const String FullNameValueKey = 'fullName';
|
const String FullNameValueKey = 'fullName';
|
||||||
const String ChallengeValueKey = 'challenge';
|
const String ChallengeValueKey = 'challenge';
|
||||||
const String OccupationValueKey = 'occupation';
|
const String OccupationValueKey = 'occupation';
|
||||||
const String LearningReasonValueKey = 'learningReason';
|
const String LanguageGoalValueKey = 'languageGoal';
|
||||||
const String TopicValueKey = 'topic';
|
const String TopicValueKey = 'topic';
|
||||||
|
|
||||||
final Map<String, TextEditingController> _OnboardingViewTextEditingControllers =
|
final Map<String, TextEditingController> _OnboardingViewTextEditingControllers =
|
||||||
|
|
@ -29,7 +29,7 @@ final Map<String, String? Function(String?)?> _OnboardingViewTextValidations = {
|
||||||
FullNameValueKey: FormValidator.validateForm,
|
FullNameValueKey: FormValidator.validateForm,
|
||||||
ChallengeValueKey: FormValidator.validateForm,
|
ChallengeValueKey: FormValidator.validateForm,
|
||||||
OccupationValueKey: FormValidator.validateForm,
|
OccupationValueKey: FormValidator.validateForm,
|
||||||
LearningReasonValueKey: FormValidator.validateForm,
|
LanguageGoalValueKey: FormValidator.validateForm,
|
||||||
TopicValueKey: FormValidator.validateForm,
|
TopicValueKey: FormValidator.validateForm,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -42,8 +42,8 @@ mixin $OnboardingView {
|
||||||
_getFormTextEditingController(ChallengeValueKey);
|
_getFormTextEditingController(ChallengeValueKey);
|
||||||
TextEditingController get occupationController =>
|
TextEditingController get occupationController =>
|
||||||
_getFormTextEditingController(OccupationValueKey);
|
_getFormTextEditingController(OccupationValueKey);
|
||||||
TextEditingController get learningReasonController =>
|
TextEditingController get languageGoalController =>
|
||||||
_getFormTextEditingController(LearningReasonValueKey);
|
_getFormTextEditingController(LanguageGoalValueKey);
|
||||||
TextEditingController get topicController =>
|
TextEditingController get topicController =>
|
||||||
_getFormTextEditingController(TopicValueKey);
|
_getFormTextEditingController(TopicValueKey);
|
||||||
|
|
||||||
|
|
@ -51,8 +51,8 @@ mixin $OnboardingView {
|
||||||
FocusNode get fullNameFocusNode => _getFormFocusNode(FullNameValueKey);
|
FocusNode get fullNameFocusNode => _getFormFocusNode(FullNameValueKey);
|
||||||
FocusNode get challengeFocusNode => _getFormFocusNode(ChallengeValueKey);
|
FocusNode get challengeFocusNode => _getFormFocusNode(ChallengeValueKey);
|
||||||
FocusNode get occupationFocusNode => _getFormFocusNode(OccupationValueKey);
|
FocusNode get occupationFocusNode => _getFormFocusNode(OccupationValueKey);
|
||||||
FocusNode get learningReasonFocusNode =>
|
FocusNode get languageGoalFocusNode =>
|
||||||
_getFormFocusNode(LearningReasonValueKey);
|
_getFormFocusNode(LanguageGoalValueKey);
|
||||||
FocusNode get topicFocusNode => _getFormFocusNode(TopicValueKey);
|
FocusNode get topicFocusNode => _getFormFocusNode(TopicValueKey);
|
||||||
|
|
||||||
TextEditingController _getFormTextEditingController(
|
TextEditingController _getFormTextEditingController(
|
||||||
|
|
@ -83,7 +83,7 @@ mixin $OnboardingView {
|
||||||
fullNameController.addListener(() => _updateFormData(model));
|
fullNameController.addListener(() => _updateFormData(model));
|
||||||
challengeController.addListener(() => _updateFormData(model));
|
challengeController.addListener(() => _updateFormData(model));
|
||||||
occupationController.addListener(() => _updateFormData(model));
|
occupationController.addListener(() => _updateFormData(model));
|
||||||
learningReasonController.addListener(() => _updateFormData(model));
|
languageGoalController.addListener(() => _updateFormData(model));
|
||||||
topicController.addListener(() => _updateFormData(model));
|
topicController.addListener(() => _updateFormData(model));
|
||||||
|
|
||||||
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
||||||
|
|
@ -100,7 +100,7 @@ mixin $OnboardingView {
|
||||||
fullNameController.addListener(() => _updateFormData(model));
|
fullNameController.addListener(() => _updateFormData(model));
|
||||||
challengeController.addListener(() => _updateFormData(model));
|
challengeController.addListener(() => _updateFormData(model));
|
||||||
occupationController.addListener(() => _updateFormData(model));
|
occupationController.addListener(() => _updateFormData(model));
|
||||||
learningReasonController.addListener(() => _updateFormData(model));
|
languageGoalController.addListener(() => _updateFormData(model));
|
||||||
topicController.addListener(() => _updateFormData(model));
|
topicController.addListener(() => _updateFormData(model));
|
||||||
|
|
||||||
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
_updateFormData(model, forceValidate: _autoTextFieldValidation);
|
||||||
|
|
@ -115,7 +115,7 @@ mixin $OnboardingView {
|
||||||
FullNameValueKey: fullNameController.text,
|
FullNameValueKey: fullNameController.text,
|
||||||
ChallengeValueKey: challengeController.text,
|
ChallengeValueKey: challengeController.text,
|
||||||
OccupationValueKey: occupationController.text,
|
OccupationValueKey: occupationController.text,
|
||||||
LearningReasonValueKey: learningReasonController.text,
|
LanguageGoalValueKey: languageGoalController.text,
|
||||||
TopicValueKey: topicController.text,
|
TopicValueKey: topicController.text,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -163,8 +163,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
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?;
|
||||||
String? get learningReasonValue =>
|
String? get languageGoalValue =>
|
||||||
this.formValueMap[LearningReasonValueKey] as String?;
|
this.formValueMap[LanguageGoalValueKey] as String?;
|
||||||
String? get topicValue => this.formValueMap[TopicValueKey] as String?;
|
String? get topicValue => this.formValueMap[TopicValueKey] as String?;
|
||||||
|
|
||||||
set answerValue(String? value) {
|
set answerValue(String? value) {
|
||||||
|
|
@ -210,14 +210,14 @@ extension ValueProperties on FormStateHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
set learningReasonValue(String? value) {
|
set languageGoalValue(String? value) {
|
||||||
this.setData(
|
this.setData(
|
||||||
this.formValueMap..addAll({LearningReasonValueKey: value}),
|
this.formValueMap..addAll({LanguageGoalValueKey: value}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (_OnboardingViewTextEditingControllers.containsKey(
|
if (_OnboardingViewTextEditingControllers.containsKey(
|
||||||
LearningReasonValueKey)) {
|
LanguageGoalValueKey)) {
|
||||||
_OnboardingViewTextEditingControllers[LearningReasonValueKey]?.text =
|
_OnboardingViewTextEditingControllers[LanguageGoalValueKey]?.text =
|
||||||
value ?? '';
|
value ?? '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -244,9 +244,9 @@ extension ValueProperties on FormStateHelper {
|
||||||
bool get hasOccupation =>
|
bool get hasOccupation =>
|
||||||
this.formValueMap.containsKey(OccupationValueKey) &&
|
this.formValueMap.containsKey(OccupationValueKey) &&
|
||||||
(occupationValue?.isNotEmpty ?? false);
|
(occupationValue?.isNotEmpty ?? false);
|
||||||
bool get hasLearningReason =>
|
bool get hasLanguageGoal =>
|
||||||
this.formValueMap.containsKey(LearningReasonValueKey) &&
|
this.formValueMap.containsKey(LanguageGoalValueKey) &&
|
||||||
(learningReasonValue?.isNotEmpty ?? false);
|
(languageGoalValue?.isNotEmpty ?? false);
|
||||||
bool get hasTopic =>
|
bool get hasTopic =>
|
||||||
this.formValueMap.containsKey(TopicValueKey) &&
|
this.formValueMap.containsKey(TopicValueKey) &&
|
||||||
(topicValue?.isNotEmpty ?? false);
|
(topicValue?.isNotEmpty ?? false);
|
||||||
|
|
@ -259,9 +259,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
this.fieldsValidationMessages[ChallengeValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[ChallengeValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasOccupationValidationMessage =>
|
bool get hasOccupationValidationMessage =>
|
||||||
this.fieldsValidationMessages[OccupationValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[OccupationValueKey]?.isNotEmpty ?? false;
|
||||||
bool get hasLearningReasonValidationMessage =>
|
bool get hasLanguageGoalValidationMessage =>
|
||||||
this.fieldsValidationMessages[LearningReasonValueKey]?.isNotEmpty ??
|
this.fieldsValidationMessages[LanguageGoalValueKey]?.isNotEmpty ?? false;
|
||||||
false;
|
|
||||||
bool get hasTopicValidationMessage =>
|
bool get hasTopicValidationMessage =>
|
||||||
this.fieldsValidationMessages[TopicValueKey]?.isNotEmpty ?? false;
|
this.fieldsValidationMessages[TopicValueKey]?.isNotEmpty ?? false;
|
||||||
|
|
||||||
|
|
@ -273,8 +272,8 @@ extension ValueProperties on FormStateHelper {
|
||||||
this.fieldsValidationMessages[ChallengeValueKey];
|
this.fieldsValidationMessages[ChallengeValueKey];
|
||||||
String? get occupationValidationMessage =>
|
String? get occupationValidationMessage =>
|
||||||
this.fieldsValidationMessages[OccupationValueKey];
|
this.fieldsValidationMessages[OccupationValueKey];
|
||||||
String? get learningReasonValidationMessage =>
|
String? get languageGoalValidationMessage =>
|
||||||
this.fieldsValidationMessages[LearningReasonValueKey];
|
this.fieldsValidationMessages[LanguageGoalValueKey];
|
||||||
String? get topicValidationMessage =>
|
String? get topicValidationMessage =>
|
||||||
this.fieldsValidationMessages[TopicValueKey];
|
this.fieldsValidationMessages[TopicValueKey];
|
||||||
}
|
}
|
||||||
|
|
@ -288,8 +287,8 @@ extension Methods on FormStateHelper {
|
||||||
this.fieldsValidationMessages[ChallengeValueKey] = validationMessage;
|
this.fieldsValidationMessages[ChallengeValueKey] = validationMessage;
|
||||||
setOccupationValidationMessage(String? validationMessage) =>
|
setOccupationValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[OccupationValueKey] = validationMessage;
|
this.fieldsValidationMessages[OccupationValueKey] = validationMessage;
|
||||||
setLearningReasonValidationMessage(String? validationMessage) =>
|
setLanguageGoalValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[LearningReasonValueKey] = validationMessage;
|
this.fieldsValidationMessages[LanguageGoalValueKey] = validationMessage;
|
||||||
setTopicValidationMessage(String? validationMessage) =>
|
setTopicValidationMessage(String? validationMessage) =>
|
||||||
this.fieldsValidationMessages[TopicValueKey] = validationMessage;
|
this.fieldsValidationMessages[TopicValueKey] = validationMessage;
|
||||||
|
|
||||||
|
|
@ -299,7 +298,7 @@ extension Methods on FormStateHelper {
|
||||||
fullNameValue = '';
|
fullNameValue = '';
|
||||||
challengeValue = '';
|
challengeValue = '';
|
||||||
occupationValue = '';
|
occupationValue = '';
|
||||||
learningReasonValue = '';
|
languageGoalValue = '';
|
||||||
topicValue = '';
|
topicValue = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,7 +309,7 @@ extension Methods on FormStateHelper {
|
||||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
||||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||||
LearningReasonValueKey: getValidationMessage(LearningReasonValueKey),
|
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
||||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
TopicValueKey: getValidationMessage(TopicValueKey),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -335,6 +334,6 @@ void updateValidationData(FormStateHelper model) =>
|
||||||
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
FullNameValueKey: getValidationMessage(FullNameValueKey),
|
||||||
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
ChallengeValueKey: getValidationMessage(ChallengeValueKey),
|
||||||
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
OccupationValueKey: getValidationMessage(OccupationValueKey),
|
||||||
LearningReasonValueKey: getValidationMessage(LearningReasonValueKey),
|
LanguageGoalValueKey: getValidationMessage(LanguageGoalValueKey),
|
||||||
TopicValueKey: getValidationMessage(TopicValueKey),
|
TopicValueKey: getValidationMessage(TopicValueKey),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:stacked/stacked.dart';
|
||||||
import 'package:stacked_services/stacked_services.dart';
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
import 'package:yimaru_app/app/app.router.dart';
|
import 'package:yimaru_app/app/app.router.dart';
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
|
import '../home/home_view.dart';
|
||||||
|
|
||||||
class OnboardingViewModel extends FormViewModel {
|
class OnboardingViewModel extends FormViewModel {
|
||||||
final _navigationService = locator<NavigationService>();
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
@ -34,6 +35,23 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
|
|
||||||
String? get selectedEducationalBackground => _selectedEducationalBackground;
|
String? get selectedEducationalBackground => _selectedEducationalBackground;
|
||||||
|
|
||||||
|
// Gender
|
||||||
|
final List<String> _genders = [
|
||||||
|
'Male',
|
||||||
|
'Female',
|
||||||
|
];
|
||||||
|
|
||||||
|
List<String> get genders => _genders;
|
||||||
|
|
||||||
|
String? _selectedGender;
|
||||||
|
|
||||||
|
String? get selectedGender => _selectedGender;
|
||||||
|
|
||||||
|
// Birthday
|
||||||
|
String? _selectedBirthday;
|
||||||
|
|
||||||
|
String? get selectedBirthday => _selectedBirthday;
|
||||||
|
|
||||||
// Age group
|
// Age group
|
||||||
final List<String> _ageGroups = [
|
final List<String> _ageGroups = [
|
||||||
'8-14',
|
'8-14',
|
||||||
|
|
@ -53,6 +71,36 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
|
|
||||||
bool get focusOccupation => _focusOccupation;
|
bool get focusOccupation => _focusOccupation;
|
||||||
|
|
||||||
|
// Country
|
||||||
|
String _selectedCountry = 'Ethiopia';
|
||||||
|
|
||||||
|
String get selectedCountry => _selectedCountry;
|
||||||
|
|
||||||
|
Future<List<String>> getCountries() async => ['Ethiopia'];
|
||||||
|
|
||||||
|
// Country
|
||||||
|
String _selectedRegion = 'Addis Ababa';
|
||||||
|
|
||||||
|
String get selectedRegion => _selectedRegion;
|
||||||
|
|
||||||
|
Future<List<String>> getRegions(String country) async =>
|
||||||
|
[ 'Afar',
|
||||||
|
'SNNPR',
|
||||||
|
'Amhara',
|
||||||
|
'Harari',
|
||||||
|
'Oromia',
|
||||||
|
'Sidama',
|
||||||
|
'Somali',
|
||||||
|
'Tigray',
|
||||||
|
'Gambela',
|
||||||
|
'Dire Dawa',
|
||||||
|
'Addis Ababa',
|
||||||
|
'Central Ethiopia',
|
||||||
|
'Benishangul-Gumuz',
|
||||||
|
'South West Ethiopia',
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
// Learning goal
|
// Learning goal
|
||||||
String? _selectedLearningGoal;
|
String? _selectedLearningGoal;
|
||||||
|
|
||||||
|
|
@ -79,19 +127,19 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
List<Map<String, dynamic>> get learningGoals => _learningGoals;
|
List<Map<String, dynamic>> get learningGoals => _learningGoals;
|
||||||
|
|
||||||
// Learning reason
|
// Learning reason
|
||||||
bool _showReasonTextBox = false;
|
bool _showLanguageGoalTextBox = false;
|
||||||
|
|
||||||
bool get showReasonTextBox => _showReasonTextBox;
|
bool get showLanguageGoalTextBox => _showLanguageGoalTextBox;
|
||||||
|
|
||||||
bool _focusLearningReason = false;
|
bool _focusLanguageGoal = false;
|
||||||
|
|
||||||
bool get focusLearningReason => _focusLearningReason;
|
bool get focusLanguageGoal => _focusLanguageGoal;
|
||||||
|
|
||||||
String? _selectedLearningReason;
|
String? _selectedLanguageGoal;
|
||||||
|
|
||||||
String? get selectedLearningReason => _selectedLearningReason;
|
String? get selectedLanguageGoal => _selectedLanguageGoal;
|
||||||
|
|
||||||
final List<String> _learningReasons = [
|
final List<String> _languageGoals = [
|
||||||
'Speak confidently at work or school',
|
'Speak confidently at work or school',
|
||||||
'Travel or handle daily situations',
|
'Travel or handle daily situations',
|
||||||
'Connect with family or friends',
|
'Connect with family or friends',
|
||||||
|
|
@ -99,7 +147,7 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
'Other'
|
'Other'
|
||||||
];
|
];
|
||||||
|
|
||||||
List<String> get learningReasons => _learningReasons;
|
List<String> get languageGoals => _languageGoals;
|
||||||
|
|
||||||
// Challenges
|
// Challenges
|
||||||
bool _showChallengeTextBox = false;
|
bool _showChallengeTextBox = false;
|
||||||
|
|
@ -147,53 +195,6 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
|
|
||||||
List<String> get topics => _topics;
|
List<String> get topics => _topics;
|
||||||
|
|
||||||
// First assessment
|
|
||||||
bool _focusFirstAssessment = false;
|
|
||||||
|
|
||||||
bool get focusFirstAssessment => _focusFirstAssessment;
|
|
||||||
|
|
||||||
// Second assessment
|
|
||||||
final List<String> _secondAnswers = [
|
|
||||||
'go',
|
|
||||||
'goes',
|
|
||||||
'went',
|
|
||||||
'going',
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> get secondAnswers => _secondAnswers;
|
|
||||||
|
|
||||||
String? _selectedA2Answer;
|
|
||||||
|
|
||||||
String? get selectedA2Answer => _selectedA2Answer;
|
|
||||||
|
|
||||||
// Third assessment
|
|
||||||
final List<String> _thirdAnswers = [
|
|
||||||
'reduce',
|
|
||||||
'grow',
|
|
||||||
'stop',
|
|
||||||
'hide',
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> get thirdAnswers => _thirdAnswers;
|
|
||||||
|
|
||||||
String? _selectedA3Answer;
|
|
||||||
|
|
||||||
String? get selectedA3Answer => _selectedA3Answer;
|
|
||||||
|
|
||||||
// Third assessment
|
|
||||||
final List<String> _fourthAnswers = [
|
|
||||||
'reduce',
|
|
||||||
'grow',
|
|
||||||
'stop',
|
|
||||||
'hide',
|
|
||||||
];
|
|
||||||
|
|
||||||
List<String> get fourthAnswers => _fourthAnswers;
|
|
||||||
|
|
||||||
String? _selectedA4Answer;
|
|
||||||
|
|
||||||
String? get selectedA4Answer => _selectedA4Answer;
|
|
||||||
|
|
||||||
// Languages
|
// Languages
|
||||||
final List<Map<String, dynamic>> _languages = [
|
final List<Map<String, dynamic>> _languages = [
|
||||||
{'code': 'አማ', 'language': 'አማርኛ'},
|
{'code': 'አማ', 'language': 'አማርኛ'},
|
||||||
|
|
@ -209,6 +210,11 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
|
|
||||||
Map<String, dynamic> get selectedLanguage => _selectedLanguage;
|
Map<String, dynamic> get selectedLanguage => _selectedLanguage;
|
||||||
|
|
||||||
|
// User data
|
||||||
|
final Map<String, dynamic> _userData = {};
|
||||||
|
|
||||||
|
Map<String, dynamic> get userData => _userData;
|
||||||
|
|
||||||
// Full name
|
// Full name
|
||||||
void setFullNameFocus() {
|
void setFullNameFocus() {
|
||||||
_focusFullName = true;
|
_focusFullName = true;
|
||||||
|
|
@ -216,21 +222,35 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Education background
|
// Education background
|
||||||
void setSelectedEducationalBackground(String title) {
|
void setSelectedEducationalBackground(String value) {
|
||||||
_selectedEducationalBackground = title;
|
_selectedEducationalBackground = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedEducationalBackground(String title) =>
|
bool isSelectedEducationalBackground(String value) =>
|
||||||
_selectedEducationalBackground == title;
|
_selectedEducationalBackground == value;
|
||||||
|
|
||||||
|
// Gender
|
||||||
|
void setSelectedGender(String gender) {
|
||||||
|
_selectedGender = gender;
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSelectedGender(String value) => _selectedGender == value;
|
||||||
|
|
||||||
|
// Birthday
|
||||||
|
void setBirthday(String value) {
|
||||||
|
_selectedBirthday = value;
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
// Age group
|
// Age group
|
||||||
void setSelectedAgeGroup(String title) {
|
void setSelectedAgeGroup(String value) {
|
||||||
_selectedAgeGroup = title;
|
_selectedAgeGroup = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedAgeGroup(String title) => _selectedAgeGroup == title;
|
bool isSelectedAgeGroup(String value) => _selectedAgeGroup == value;
|
||||||
|
|
||||||
// Occupation
|
// Occupation
|
||||||
void setOccupationFocus() {
|
void setOccupationFocus() {
|
||||||
|
|
@ -239,41 +259,45 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Country
|
// Country
|
||||||
Future<List<String>> getCountries() async => ['Ethiopia', 'Djibouti'];
|
void setSelectedCountry(String value) {
|
||||||
|
_selectedCountry = value;
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
// Region
|
// Region
|
||||||
Future<List<String>> getRegions(String country) async =>
|
void setSelectedRegion(String value) {
|
||||||
['Addis Ababa', 'Oromia'];
|
_selectedRegion = value;
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
|
||||||
// Learning goal
|
// Learning goal
|
||||||
void setSelectedLearningGoal(String title) {
|
void setSelectedLearningGoal(String value) {
|
||||||
_selectedLearningGoal = title;
|
_selectedLearningGoal = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedLearningGoal(String title) => _selectedLearningGoal == title;
|
bool isSelectedLearningGoal(String value) => _selectedLearningGoal == value;
|
||||||
|
|
||||||
// Learning reason
|
// Learning reason
|
||||||
void setLearningReasonFocus() {
|
void setLanguageGoalFocus() {
|
||||||
_focusLearningReason = true;
|
_focusLanguageGoal = true;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSelectedLearningReason(String title) {
|
void setSelectedLanguageGoal(String value) {
|
||||||
_selectedLearningReason = title;
|
_selectedLanguageGoal = value;
|
||||||
if (title.toLowerCase() == 'other') {
|
if (value.toLowerCase() == 'other') {
|
||||||
_showReasonTextBox = true;
|
_showLanguageGoalTextBox = true;
|
||||||
} else {
|
} else {
|
||||||
if (_showReasonTextBox) {
|
if (_showLanguageGoalTextBox) {
|
||||||
_showReasonTextBox = false;
|
_showLanguageGoalTextBox = false;
|
||||||
_focusLearningReason = false;
|
_focusLanguageGoal = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedLearningReason(String title) =>
|
bool isSelectedLanguageGoal(String value) => _selectedLanguageGoal == value;
|
||||||
_selectedLearningReason == title;
|
|
||||||
|
|
||||||
// Challenges
|
// Challenges
|
||||||
void setChallengesFocus() {
|
void setChallengesFocus() {
|
||||||
|
|
@ -281,9 +305,9 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSelectedChallenge(String title) {
|
void setSelectedChallenge(String value) {
|
||||||
_selectedChallenge = title;
|
_selectedChallenge = value;
|
||||||
if (title.toLowerCase() == 'other') {
|
if (value.toLowerCase() == 'other') {
|
||||||
_showChallengeTextBox = true;
|
_showChallengeTextBox = true;
|
||||||
} else {
|
} else {
|
||||||
if (_showChallengeTextBox) {
|
if (_showChallengeTextBox) {
|
||||||
|
|
@ -294,7 +318,7 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedChallenge(String title) => _selectedChallenge == title;
|
bool isSelectedChallenge(String value) => _selectedChallenge == value;
|
||||||
|
|
||||||
// Topics
|
// Topics
|
||||||
void setTopicsFocus() {
|
void setTopicsFocus() {
|
||||||
|
|
@ -302,9 +326,9 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSelectedTopic(String title) {
|
void setSelectedTopic(String value) {
|
||||||
_selectedTopic = title;
|
_selectedTopic = value;
|
||||||
if (title.toLowerCase() == 'other') {
|
if (value.toLowerCase() == 'other') {
|
||||||
_showTopicTextBox = true;
|
_showTopicTextBox = true;
|
||||||
} else {
|
} else {
|
||||||
if (_showTopicTextBox) {
|
if (_showTopicTextBox) {
|
||||||
|
|
@ -315,50 +339,37 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedTopic(String title) => _selectedTopic == title;
|
bool isSelectedTopic(String value) => _selectedTopic == value;
|
||||||
|
|
||||||
// First assessment
|
|
||||||
void setFirstAssessmentFocus() {
|
|
||||||
_focusFirstAssessment = true;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Second assessment
|
|
||||||
void setSelectedA2Answer(String title) {
|
|
||||||
_selectedA2Answer = title;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSelectedA2Answer(String title) => _selectedA2Answer == title;
|
|
||||||
|
|
||||||
// Third assessment
|
|
||||||
void setSelectedA3Answer(String title) {
|
|
||||||
_selectedA3Answer = title;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSelectedA3Answer(String title) => _selectedA3Answer == title;
|
|
||||||
|
|
||||||
// Fourth assessment
|
|
||||||
void setSelectedA4Answer(String title) {
|
|
||||||
_selectedA4Answer = title;
|
|
||||||
rebuildUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isSelectedA4Answer(String title) => _selectedA4Answer == title;
|
|
||||||
|
|
||||||
// Language
|
// Language
|
||||||
void setSelectedLanguage(Map<String, dynamic> title) {
|
void setSelectedLanguage(Map<String, dynamic> value) {
|
||||||
_selectedLanguage = title;
|
_selectedLanguage = value;
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSelectedLanguage(String title) =>
|
bool isSelectedLanguage(String value) =>
|
||||||
_selectedLanguage['language'] == title;
|
_selectedLanguage['language'] == value;
|
||||||
|
|
||||||
|
// Add user data
|
||||||
|
void addUserData(Map<String, dynamic> data) {
|
||||||
|
_userData.addAll(data);
|
||||||
|
print('User data : $_userData');
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearUserData() {
|
||||||
|
_userData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// Navigation
|
// Navigation
|
||||||
Future<void> navigateToHome() async =>
|
|
||||||
await _navigationService.navigateToHomeView();
|
Future<void> navigateToLanguage() async =>
|
||||||
|
await _navigationService.navigateToLanguageView();
|
||||||
|
|
||||||
|
Future<void> navigateToAssessment() async =>
|
||||||
|
await _navigationService.navigateToAssessmentView(data: _userData);
|
||||||
|
|
||||||
|
Future<void> replaceWithHome() async =>
|
||||||
|
await _navigationService.clearStackAndShowView(const HomeView());
|
||||||
|
|
||||||
void next({int? page}) async {
|
void next({int? page}) async {
|
||||||
if (page == null) {
|
if (page == null) {
|
||||||
|
|
@ -366,11 +377,6 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
_currentPage = _previousPage;
|
_currentPage = _previousPage;
|
||||||
} else {
|
} else {
|
||||||
_currentPage++;
|
_currentPage++;
|
||||||
if (_currentPage == 19) {
|
|
||||||
rebuildUi();
|
|
||||||
await Future.delayed(const Duration(seconds: 3));
|
|
||||||
_currentPage++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_previousPage = _currentPage;
|
_previousPage = _currentPage;
|
||||||
|
|
@ -379,14 +385,13 @@ class OnboardingViewModel extends FormViewModel {
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
void pop({bool language = false}) {
|
void pop() {
|
||||||
if (!language) {
|
if (_currentPage == 8) {
|
||||||
_currentPage--;
|
_navigationService.back();
|
||||||
} else {
|
} else {
|
||||||
_currentPage = _previousPage;
|
_currentPage--;
|
||||||
_previousPage = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rebuildUi();
|
rebuildUi();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,15 @@ import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
const AgeGroupFormScreen({super.key});
|
const AgeGroupFormScreen({super.key});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {'age_group': viewModel.selectedAgeGroup};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -34,6 +43,7 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(viewModel),
|
child: _buildBodyWrapper(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
|
|
@ -64,13 +74,11 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'Which age range are you in?',
|
'Which age range are you in?',
|
||||||
|
|
@ -123,6 +131,6 @@ class AgeGroupFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
onTap:
|
onTap:
|
||||||
viewModel.selectedAgeGroup != null ? () => viewModel.next() : null,
|
viewModel.selectedAgeGroup != null ? () => _next(viewModel) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
import 'package:flutter/material.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 '../../onboarding_view.form.dart';
|
|
||||||
|
|
||||||
class FirstAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
|
||||||
final TextEditingController answerController;
|
|
||||||
|
|
||||||
const FirstAssessmentFormScreen({super.key, required this.answerController});
|
|
||||||
|
|
||||||
@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(), _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(),
|
|
||||||
verticalSpaceLarge,
|
|
||||||
_buildFirstAssessmentFormField(viewModel),
|
|
||||||
if (viewModel.hasAnswerValidationMessage &&
|
|
||||||
viewModel.focusFirstAssessment)
|
|
||||||
verticalSpaceTiny,
|
|
||||||
if (viewModel.hasAnswerValidationMessage &&
|
|
||||||
viewModel.focusFirstAssessment)
|
|
||||||
_buildFirstAssessmentValidatorWrapper(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar() => const LargeAppBar(
|
|
||||||
showBackButton: false,
|
|
||||||
showLanguageSelection: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
|
||||||
'1. What is the plural of “book”?',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildFirstAssessmentFormField(OnboardingViewModel viewModel) =>
|
|
||||||
TextFormField(
|
|
||||||
controller: answerController,
|
|
||||||
onTap: viewModel.setFirstAssessmentFocus,
|
|
||||||
decoration: inputDecoration(
|
|
||||||
focus: viewModel.focusFirstAssessment,
|
|
||||||
filled: answerController.text.isNotEmpty),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildFirstAssessmentValidatorWrapper(OnboardingViewModel viewModel) =>
|
|
||||||
viewModel.hasAnswerValidationMessage
|
|
||||||
? _buildFirstAssessmentValidator(viewModel)
|
|
||||||
: Container();
|
|
||||||
|
|
||||||
Widget _buildFirstAssessmentValidator(OnboardingViewModel viewModel) => Text(
|
|
||||||
viewModel.answerValidationMessage!,
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 12,
|
|
||||||
color: Colors.red,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
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: answerController.text.isNotEmpty
|
|
||||||
? kcPrimaryColor
|
|
||||||
: viewModel.focusFirstAssessment && answerController.text.isNotEmpty
|
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
onTap: answerController.text.isNotEmpty
|
|
||||||
? () => viewModel.next()
|
|
||||||
: viewModel.focusFirstAssessment && answerController.text.isNotEmpty
|
|
||||||
? () => viewModel.next()
|
|
||||||
: null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
import 'package:flutter/material.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/custom_small_radio_button.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
|
||||||
|
|
||||||
class SecondAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
|
||||||
const SecondAssessmentFormScreen({super.key});
|
|
||||||
|
|
||||||
@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(), _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(),
|
|
||||||
verticalSpaceMedium,
|
|
||||||
_buildAnswers(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar() => const LargeAppBar(
|
|
||||||
showBackButton: false,
|
|
||||||
showLanguageSelection: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
|
||||||
'Q2. Choose the correct word to complete the sentence:\nI ____ to school yesterday. ',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAnswers(OnboardingViewModel viewModel) => ListView.builder(
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemCount: viewModel.secondAnswers.length,
|
|
||||||
itemBuilder: (context, index) => _buildAnswer(
|
|
||||||
title: viewModel.secondAnswers[index],
|
|
||||||
selected:
|
|
||||||
viewModel.isSelectedA2Answer(viewModel.secondAnswers[index]),
|
|
||||||
onTap: () =>
|
|
||||||
viewModel.setSelectedA2Answer(viewModel.secondAnswers[index]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildAnswer(
|
|
||||||
{required String title,
|
|
||||||
required bool selected,
|
|
||||||
required GestureTapCallback onTap}) =>
|
|
||||||
CustomSmallRadioButton(
|
|
||||||
title: title,
|
|
||||||
onTap: onTap,
|
|
||||||
selected: selected,
|
|
||||||
);
|
|
||||||
|
|
||||||
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,
|
|
||||||
onTap:
|
|
||||||
viewModel.selectedA2Answer != null ? () => viewModel.next() : null,
|
|
||||||
backgroundColor: viewModel.selectedA2Answer != null
|
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +1,28 @@
|
||||||
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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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/views/onboarding/onboarding_viewmodel.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class FourthAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../../../widgets/birthday_selector.dart';
|
||||||
const FourthAssessmentFormScreen({super.key});
|
|
||||||
|
class BirthdayFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
const BirthdayFormScreen({super.key});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'birth_day': DateFormat('yyyy-MM-dd')
|
||||||
|
.parseUTC(viewModel.selectedBirthday ?? DateTime.now().toString())
|
||||||
|
.toIso8601String()
|
||||||
|
};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
|
|
@ -25,7 +39,7 @@ class FourthAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
||||||
[_buildAppBar(), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
@ -53,45 +67,38 @@ class FourthAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
|
verticalSpaceSmall,
|
||||||
|
_buildSubTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAnswers(viewModel)
|
_buildBirthdayFormField(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar() => const LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
onPop: viewModel.pop,
|
||||||
showLanguageSelection: false,
|
showBackButton: true,
|
||||||
|
showLanguageSelection: true,
|
||||||
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'Q4. Choose the word that best matches the meaning of ‘meticulous’:',
|
'Pick your birthday?',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 25,
|
||||||
color: kcDarkGrey,
|
color: kcDarkGrey,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAnswers(OnboardingViewModel viewModel) => ListView.builder(
|
Widget _buildSubTitle() => const Text(
|
||||||
shrinkWrap: true,
|
'We’ll personalize your learning experience based on your birthday.',
|
||||||
itemCount: viewModel.fourthAnswers.length,
|
style: TextStyle(color: kcMediumGrey),
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) => _buildAnswer(
|
|
||||||
title: viewModel.fourthAnswers[index],
|
|
||||||
selected:
|
|
||||||
viewModel.isSelectedA4Answer(viewModel.fourthAnswers[index]),
|
|
||||||
onTap: () =>
|
|
||||||
viewModel.setSelectedA4Answer(viewModel.fourthAnswers[index]),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAnswer(
|
Widget _buildBirthdayFormField(OnboardingViewModel viewModel) =>
|
||||||
{required String title,
|
BirthdaySelector(
|
||||||
required bool selected,
|
birthday: viewModel.selectedBirthday,
|
||||||
required GestureTapCallback onTap}) =>
|
onSelected: (value) =>
|
||||||
CustomSmallRadioButton(
|
viewModel.setBirthday(DateFormat('yyyy-MM-dd').format(value)),
|
||||||
title: title,
|
|
||||||
onTap: onTap,
|
|
||||||
selected: selected,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
|
|
@ -105,10 +112,10 @@ class FourthAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap:
|
backgroundColor: viewModel.selectedBirthday != null
|
||||||
viewModel.selectedA4Answer != null ? () => viewModel.next() : null,
|
|
||||||
backgroundColor: viewModel.selectedA4Answer != null
|
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
|
onTap:
|
||||||
|
viewModel.selectedBirthday != null ? () => _next(viewModel) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -13,6 +13,18 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
const ChallengeFormScreen({super.key, required this.challengeController});
|
const ChallengeFormScreen({super.key, required this.challengeController});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'language_challange':
|
||||||
|
viewModel.selectedChallenge ?? challengeController.text,
|
||||||
|
};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -37,6 +49,7 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(viewModel),
|
child: _buildBodyWrapper(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
|
|
@ -77,13 +90,11 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'What challenge do you face most with English?',
|
'What challenge do you face most with English?',
|
||||||
|
|
@ -160,15 +171,14 @@ class ChallengeFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.selectedChallenge != null
|
onTap: viewModel.selectedChallenge != null
|
||||||
? viewModel.selectedChallenge?.toLowerCase() == 'other'
|
? viewModel.selectedChallenge?.toLowerCase() == 'other'
|
||||||
? viewModel.focusChallenge
|
? challengeController.text.isNotEmpty
|
||||||
? () => viewModel.next()
|
? () => _next(viewModel)
|
||||||
: null
|
: null
|
||||||
: () => viewModel.next()
|
: () => _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedChallenge != null
|
backgroundColor: viewModel.selectedChallenge != null
|
||||||
? viewModel.selectedChallenge?.toLowerCase() == 'other'
|
? viewModel.selectedChallenge?.toLowerCase() == 'other'
|
||||||
? viewModel.focusChallenge &&
|
? challengeController.text.isNotEmpty
|
||||||
challengeController.text.isNotEmpty
|
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1)
|
: kcPrimaryColor.withOpacity(0.1)
|
||||||
: kcPrimaryColor
|
: kcPrimaryColor
|
||||||
|
|
@ -10,6 +10,18 @@ import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
const CountryRegionFormScreen({super.key});
|
const CountryRegionFormScreen({super.key});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'country': viewModel.selectedCountry,
|
||||||
|
'region': viewModel.selectedRegion
|
||||||
|
};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -68,13 +80,11 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'Where are you from?',
|
'Where are you from?',
|
||||||
|
|
@ -92,19 +102,20 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
Widget _buildCountryDropDown(OnboardingViewModel viewModel) =>
|
Widget _buildCountryDropDown(OnboardingViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
CustomDropdownPicker(
|
||||||
onChanged: (value) {},
|
hint: 'Select country',
|
||||||
hint: 'Select country',
|
icon: _buildSearchIcon(),
|
||||||
icon: _buildSearchIcon(),
|
selectedItem: 'Ethiopia',
|
||||||
selectedItem: 'Ethiopia',
|
items: (value, props) => viewModel.getCountries(),
|
||||||
items: (value, props) => viewModel.getCountries(),
|
onChanged: (value) =>
|
||||||
);
|
viewModel.setSelectedCountry(value ?? 'Ethiopia'));
|
||||||
|
|
||||||
Widget _buildRegionDropDown(OnboardingViewModel viewModel) =>
|
Widget _buildRegionDropDown(OnboardingViewModel viewModel) =>
|
||||||
CustomDropdownPicker(
|
CustomDropdownPicker(
|
||||||
hint: 'Select region',
|
hint: 'Select region',
|
||||||
onChanged: (value) {},
|
|
||||||
icon: _buildSearchIcon(),
|
icon: _buildSearchIcon(),
|
||||||
selectedItem: 'Addis Ababa',
|
selectedItem: 'Addis Ababa',
|
||||||
|
onChanged: (value) =>
|
||||||
|
viewModel.setSelectedRegion(value ?? 'Addis Ababa'),
|
||||||
items: (value, props) => viewModel.getRegions('Addis Ababa'),
|
items: (value, props) => viewModel.getRegions('Addis Ababa'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -123,8 +134,8 @@ class CountryRegionFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
height: 55,
|
height: 55,
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
onTap: () => viewModel.next(),
|
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
|
onTap: () => _next(viewModel),
|
||||||
backgroundColor: kcPrimaryColor,
|
backgroundColor: kcPrimaryColor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +11,17 @@ class EducationalBackgroundFormScreen
|
||||||
extends ViewModelWidget<OnboardingViewModel> {
|
extends ViewModelWidget<OnboardingViewModel> {
|
||||||
const EducationalBackgroundFormScreen({super.key});
|
const EducationalBackgroundFormScreen({super.key});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'education_level': viewModel.selectedEducationalBackground
|
||||||
|
};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -66,13 +77,11 @@ class EducationalBackgroundFormScreen
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'What’s your current educational level?',
|
'What’s your current educational level?',
|
||||||
|
|
@ -124,7 +133,7 @@ class EducationalBackgroundFormScreen
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.selectedEducationalBackground != null
|
onTap: viewModel.selectedEducationalBackground != null
|
||||||
? () => viewModel.next()
|
? () => _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedEducationalBackground != null
|
backgroundColor: viewModel.selectedEducationalBackground != null
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
|
|
@ -1,18 +1,28 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/common/app_colors.dart';
|
import 'package:yimaru_app/ui/common/app_colors.dart';
|
||||||
|
import 'package:yimaru_app/ui/common/helper_functions.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.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/views/onboarding/onboarding_viewmodel.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';
|
import '../onboarding_view.form.dart';
|
||||||
|
|
||||||
class FullNameFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class FullNameFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
final TextEditingController fullNameController;
|
final TextEditingController fullNameController;
|
||||||
|
|
||||||
const FullNameFormScreen({super.key, required this.fullNameController});
|
const FullNameFormScreen({super.key, required this.fullNameController});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = splitFullName(fullNameController.text);
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -72,12 +82,10 @@ class FullNameFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
showBackButton: false,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'What should we call you? 😊',
|
'What should we call you? 😊',
|
||||||
|
|
@ -128,12 +136,10 @@ class FullNameFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.focusFullName && fullNameController.text.isNotEmpty
|
onTap:
|
||||||
? () => viewModel.next()
|
fullNameController.text.isNotEmpty ? () => _next(viewModel) : null,
|
||||||
: null,
|
backgroundColor: fullNameController.text.isNotEmpty
|
||||||
backgroundColor:
|
? kcPrimaryColor
|
||||||
viewModel.focusFullName && fullNameController.text.isNotEmpty
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -7,8 +7,17 @@ import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class ThirdAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class GenderFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
const ThirdAssessmentFormScreen({super.key});
|
const GenderFormScreen({super.key});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {'gender': viewModel.selectedGender};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
|
|
@ -25,7 +34,7 @@ class ThirdAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
||||||
[_buildAppBar(), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyWrapper(viewModel));
|
Expanded(child: _buildBodyWrapper(viewModel));
|
||||||
|
|
@ -53,37 +62,45 @@ class ThirdAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
|
verticalSpaceSmall,
|
||||||
|
_buildSubTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildAnswers(viewModel)
|
_buildAgeGroups(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar() => const LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: false,
|
onPop: viewModel.pop,
|
||||||
showLanguageSelection: false,
|
showBackButton: true,
|
||||||
|
showLanguageSelection: true,
|
||||||
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'Q3. Which word means the same as ‘expand’?',
|
'Choose your gender?',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 25,
|
||||||
color: kcDarkGrey,
|
color: kcDarkGrey,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAnswers(OnboardingViewModel viewModel) => ListView.builder(
|
Widget _buildSubTitle() => const Text(
|
||||||
|
'We’ll personalize your learning experience based on your gender.',
|
||||||
|
style: TextStyle(color: kcMediumGrey),
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildAgeGroups(OnboardingViewModel viewModel) => ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: viewModel.thirdAnswers.length,
|
itemCount: viewModel.genders.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildAnswer(
|
itemBuilder: (context, index) => _buildAgeGroup(
|
||||||
title: viewModel.thirdAnswers[index],
|
title: viewModel.genders[index],
|
||||||
selected: viewModel.isSelectedA3Answer(viewModel.thirdAnswers[index]),
|
selected: viewModel.isSelectedGender(viewModel.genders[index]),
|
||||||
onTap: () =>
|
onTap: () => viewModel.setSelectedGender(viewModel.genders[index]),
|
||||||
viewModel.setSelectedA3Answer(viewModel.thirdAnswers[index]),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildAnswer(
|
Widget _buildAgeGroup(
|
||||||
{required String title,
|
{required String title,
|
||||||
required bool selected,
|
required bool selected,
|
||||||
required GestureTapCallback onTap}) =>
|
required GestureTapCallback onTap}) =>
|
||||||
|
|
@ -104,10 +121,9 @@ class ThirdAssessmentFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: viewModel.selectedA3Answer != null
|
backgroundColor: viewModel.selectedGender != null
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
onTap:
|
onTap: viewModel.selectedGender != null ? () => _next(viewModel) : null,
|
||||||
viewModel.selectedA3Answer != null ? () => viewModel.next() : null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -8,11 +8,23 @@ import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_small_radio_button.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
class LearningReasonFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class LanguageGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
final TextEditingController learningReasonController;
|
final TextEditingController languageGoalController;
|
||||||
|
|
||||||
const LearningReasonFormScreen(
|
const LanguageGoalFormScreen(
|
||||||
{super.key, required this.learningReasonController});
|
{super.key, required this.languageGoalController});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'language_goal':
|
||||||
|
viewModel.selectedLanguageGoal ?? languageGoalController.text,
|
||||||
|
};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
|
|
@ -66,24 +78,24 @@ class LearningReasonFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
_buildSubTitle(),
|
_buildSubTitle(),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildReasons(viewModel),
|
_buildReasons(viewModel),
|
||||||
if (viewModel.showReasonTextBox) _buildReasonFormField(viewModel),
|
if (viewModel.showLanguageGoalTextBox) _buildReasonFormField(viewModel),
|
||||||
if (viewModel.showReasonTextBox &&
|
if (viewModel.showLanguageGoalTextBox &&
|
||||||
viewModel.hasLearningReasonValidationMessage &&
|
viewModel.hasLanguageGoalValidationMessage &&
|
||||||
viewModel.focusLearningReason)
|
viewModel.focusLanguageGoal)
|
||||||
verticalSpaceTiny,
|
verticalSpaceTiny,
|
||||||
if (viewModel.showReasonTextBox &&
|
if (viewModel.showLanguageGoalTextBox &&
|
||||||
viewModel.hasLearningReasonValidationMessage &&
|
viewModel.hasLanguageGoalValidationMessage &&
|
||||||
viewModel.focusLearningReason)
|
viewModel.focusLanguageGoal)
|
||||||
_buildReasonValidatorWrapper(viewModel),
|
_buildReasonValidatorWrapper(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(language: false));
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'What’s your main goal for improving your English?',
|
'What’s your main goal for improving your English?',
|
||||||
|
|
@ -104,18 +116,18 @@ class LearningReasonFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
Widget _buildReasons(OnboardingViewModel viewModel) => ListView.builder(
|
Widget _buildReasons(OnboardingViewModel viewModel) => ListView.builder(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
itemCount: viewModel.learningReasons.length,
|
itemCount: viewModel.languageGoals.length,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemBuilder: (context, index) => _buildLearningReason(
|
itemBuilder: (context, index) => _buildLanguageGoal(
|
||||||
title: viewModel.learningReasons[index],
|
title: viewModel.languageGoals[index],
|
||||||
selected: viewModel
|
selected:
|
||||||
.isSelectedLearningReason(viewModel.learningReasons[index]),
|
viewModel.isSelectedLanguageGoal(viewModel.languageGoals[index]),
|
||||||
onTap: () => viewModel
|
onTap: () =>
|
||||||
.setSelectedLearningReason(viewModel.learningReasons[index]),
|
viewModel.setSelectedLanguageGoal(viewModel.languageGoals[index]),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildLearningReason(
|
Widget _buildLanguageGoal(
|
||||||
{required String title,
|
{required String title,
|
||||||
required bool selected,
|
required bool selected,
|
||||||
required GestureTapCallback onTap}) =>
|
required GestureTapCallback onTap}) =>
|
||||||
|
|
@ -127,21 +139,21 @@ class LearningReasonFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
Widget _buildReasonFormField(OnboardingViewModel viewModel) => TextFormField(
|
Widget _buildReasonFormField(OnboardingViewModel viewModel) => TextFormField(
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
controller: learningReasonController,
|
controller: languageGoalController,
|
||||||
onTap: viewModel.setLearningReasonFocus,
|
onTap: viewModel.setLanguageGoalFocus,
|
||||||
decoration: inputDecoration(
|
decoration: inputDecoration(
|
||||||
focus: true,
|
focus: true,
|
||||||
hint: 'Write your goal…',
|
hint: 'Write your goal…',
|
||||||
filled: learningReasonController.text.isNotEmpty),
|
filled: languageGoalController.text.isNotEmpty),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildReasonValidatorWrapper(OnboardingViewModel viewModel) =>
|
Widget _buildReasonValidatorWrapper(OnboardingViewModel viewModel) =>
|
||||||
viewModel.hasLearningReasonValidationMessage
|
viewModel.hasLanguageGoalValidationMessage
|
||||||
? _buildReasonValidator(viewModel)
|
? _buildReasonValidator(viewModel)
|
||||||
: Container();
|
: Container();
|
||||||
|
|
||||||
Widget _buildReasonValidator(OnboardingViewModel viewModel) => Text(
|
Widget _buildReasonValidator(OnboardingViewModel viewModel) => Text(
|
||||||
viewModel.learningReasonValidationMessage!,
|
viewModel.languageGoalValidationMessage!,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
|
|
@ -160,17 +172,16 @@ class LearningReasonFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.selectedLearningReason != null
|
onTap: viewModel.selectedLanguageGoal != null
|
||||||
? viewModel.selectedLearningReason?.toLowerCase() == 'other'
|
? viewModel.selectedLanguageGoal?.toLowerCase() == 'other'
|
||||||
? viewModel.focusLearningReason
|
? languageGoalController.text.isNotEmpty
|
||||||
? () => viewModel.next()
|
? () => _next(viewModel)
|
||||||
: null
|
: null
|
||||||
: () => viewModel.next()
|
: () => _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedLearningReason != null
|
backgroundColor: viewModel.selectedLanguageGoal != null
|
||||||
? viewModel.selectedLearningReason?.toLowerCase() == 'other'
|
? viewModel.selectedLanguageGoal?.toLowerCase() == 'other'
|
||||||
? viewModel.focusLearningReason &&
|
? languageGoalController.text.isNotEmpty
|
||||||
learningReasonController.text.isNotEmpty
|
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1)
|
: kcPrimaryColor.withOpacity(0.1)
|
||||||
: kcPrimaryColor
|
: kcPrimaryColor
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
|
||||||
|
|
||||||
import '../../../common/app_colors.dart';
|
|
||||||
import '../../../common/ui_helpers.dart';
|
|
||||||
import '../../../widgets/custom_elevated_button.dart';
|
|
||||||
import '../../../widgets/custom_small_radio_button.dart';
|
|
||||||
import '../../../widgets/large_app_bar.dart';
|
|
||||||
|
|
||||||
class LanguageSelector extends ViewModelWidget<OnboardingViewModel> {
|
|
||||||
const LanguageSelector({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@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), _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) =>
|
|
||||||
[_buildColumnScroller(viewModel), _buildContinueButtonWrapper(viewModel)];
|
|
||||||
|
|
||||||
Widget _buildColumnScroller(OnboardingViewModel viewModel) =>
|
|
||||||
SingleChildScrollView(
|
|
||||||
child: _buildUpperColumn(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,
|
|
||||||
_buildLanguages(viewModel)
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
|
||||||
showBackButton: true,
|
|
||||||
onPop: viewModel.pop,
|
|
||||||
showLanguageSelection: true,
|
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
|
||||||
onTap: () => viewModel.pop(
|
|
||||||
language: true,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
|
||||||
'Choose your language',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 25,
|
|
||||||
color: kcDarkGrey,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildSubTitle() => const Text(
|
|
||||||
'You can switch languages anytime in Settings',
|
|
||||||
style: TextStyle(color: kcMediumGrey),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLanguages(OnboardingViewModel viewModel) => ListView.builder(
|
|
||||||
shrinkWrap: true,
|
|
||||||
itemCount: viewModel.languages.length,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index) => _buildLanguage(
|
|
||||||
title: viewModel.languages[index]['language'],
|
|
||||||
selected: viewModel
|
|
||||||
.isSelectedLanguage(viewModel.languages[index]['language']),
|
|
||||||
onTap: () =>
|
|
||||||
viewModel.setSelectedLanguage(viewModel.languages[index]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildLanguage(
|
|
||||||
{required String title,
|
|
||||||
required bool selected,
|
|
||||||
required GestureTapCallback onTap}) =>
|
|
||||||
CustomSmallRadioButton(
|
|
||||||
title: title,
|
|
||||||
onTap: onTap,
|
|
||||||
selected: selected,
|
|
||||||
);
|
|
||||||
|
|
||||||
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: kcPrimaryColor,
|
|
||||||
onTap: () => viewModel.pop(language: true),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -23,6 +23,17 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
return Icons.book;
|
return Icons.book;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'learning_goal': viewModel.selectedLearningGoal,
|
||||||
|
};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -47,6 +58,7 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: _buildBodyWrapper(viewModel),
|
child: _buildBodyWrapper(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
Widget _buildBodyWrapper(OnboardingViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildBody(viewModel),
|
child: _buildBody(viewModel),
|
||||||
|
|
@ -69,23 +81,21 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildUpperColumnChildren(OnboardingViewModel viewModel) => [
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(viewModel),
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildLearningGoals(viewModel)
|
_buildLearningGoals(viewModel)
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle(OnboardingViewModel viewModel) => Text(
|
||||||
'Hi Johnny, Choose your learning goal.',
|
'Hi ${viewModel.userData['first_name']}, Choose your learning goal.',
|
||||||
style: TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 25,
|
fontSize: 25,
|
||||||
color: kcDarkGrey,
|
color: kcDarkGrey,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|
@ -133,7 +143,7 @@ class LearningGoalFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.selectedLearningGoal != null
|
onTap: viewModel.selectedLearningGoal != null
|
||||||
? () => viewModel.next()
|
? () => _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedLearningGoal != null
|
backgroundColor: viewModel.selectedLearningGoal != null
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
|
|
@ -6,13 +6,22 @@ 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/large_app_bar.dart';
|
import 'package:yimaru_app/ui/widgets/large_app_bar.dart';
|
||||||
|
|
||||||
import '../../onboarding_view.form.dart';
|
import '../onboarding_view.form.dart';
|
||||||
|
|
||||||
class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
final TextEditingController occupationController;
|
final TextEditingController occupationController;
|
||||||
|
|
||||||
const OccupationFormScreen({super.key, required this.occupationController});
|
const OccupationFormScreen({super.key, required this.occupationController});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {'occupation': occupationController.text};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
viewModel.next();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -74,13 +83,11 @@ class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
showBackButton: true,
|
showBackButton: true,
|
||||||
onPop: viewModel.pop,
|
onPop: viewModel.pop,
|
||||||
showLanguageSelection: true,
|
showLanguageSelection: true,
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
onTap: () => viewModel.pop(
|
);
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'What’s your occupation?',
|
'What’s your occupation?',
|
||||||
|
|
@ -131,12 +138,11 @@ class OccupationFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.focusOccupation && occupationController.text.isNotEmpty
|
onTap: occupationController.text.isNotEmpty
|
||||||
? () => viewModel.next()
|
? () => _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor:
|
backgroundColor: occupationController.text.isNotEmpty
|
||||||
viewModel.focusOccupation && occupationController.text.isNotEmpty
|
? kcPrimaryColor
|
||||||
? kcPrimaryColor
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -13,6 +13,17 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
|
|
||||||
const TopicFormScreen({super.key, required this.topicController});
|
const TopicFormScreen({super.key, required this.topicController});
|
||||||
|
|
||||||
|
Future<void> _next(OnboardingViewModel viewModel) async {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'favoutite_topic': viewModel.selectedTopic ?? topicController.text,
|
||||||
|
};
|
||||||
|
viewModel.addUserData(data);
|
||||||
|
|
||||||
|
await viewModel.navigateToAssessment();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
@ -30,6 +41,13 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) =>
|
||||||
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
[_buildAppBar(viewModel), _buildExpandedBody(viewModel)];
|
||||||
|
|
||||||
|
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
||||||
|
showBackButton: true,
|
||||||
|
onPop: viewModel.pop,
|
||||||
|
showLanguageSelection: true,
|
||||||
|
onLanguage: () async => await viewModel.navigateToLanguage(),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
Widget _buildExpandedBody(OnboardingViewModel viewModel) =>
|
||||||
Expanded(child: _buildBodyScroller(viewModel));
|
Expanded(child: _buildBodyScroller(viewModel));
|
||||||
|
|
||||||
|
|
@ -77,15 +95,6 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildAppBar(OnboardingViewModel viewModel) => LargeAppBar(
|
|
||||||
showBackButton: true,
|
|
||||||
onPop: viewModel.pop,
|
|
||||||
showLanguageSelection: true,
|
|
||||||
onLanguage: () => viewModel.next(page: 23),
|
|
||||||
onTap: () => viewModel.pop(
|
|
||||||
language: false,
|
|
||||||
));
|
|
||||||
|
|
||||||
Widget _buildTitle() => const Text(
|
Widget _buildTitle() => const Text(
|
||||||
'Which topics interest you most?',
|
'Which topics interest you most?',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
|
@ -159,14 +168,14 @@ class TopicFormScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.selectedTopic != null
|
onTap: viewModel.selectedTopic != null
|
||||||
? viewModel.selectedTopic?.toLowerCase() == 'other'
|
? viewModel.selectedTopic?.toLowerCase() == 'other'
|
||||||
? viewModel.focusTopic
|
? topicController.text.isNotEmpty
|
||||||
? () => viewModel.next()
|
? () async => await _next(viewModel)
|
||||||
: null
|
: null
|
||||||
: () => viewModel.next()
|
: () async => await _next(viewModel)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.selectedTopic != null
|
backgroundColor: viewModel.selectedTopic != null
|
||||||
? viewModel.selectedTopic?.toLowerCase() == 'other'
|
? viewModel.selectedTopic?.toLowerCase() == 'other'
|
||||||
? viewModel.focusTopic && topicController.text.isNotEmpty
|
? topicController.text.isNotEmpty
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1)
|
: kcPrimaryColor.withOpacity(0.1)
|
||||||
: kcPrimaryColor
|
: kcPrimaryColor
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.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/birthday_selector.dart';
|
||||||
|
|
@ -323,7 +324,7 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
List<Widget> _buildBirthdayChildren(ProfileDetailViewModel viewModel) => [
|
List<Widget> _buildBirthdayChildren(ProfileDetailViewModel viewModel) => [
|
||||||
_buildBirthdayLabel(),
|
_buildBirthdayLabel(),
|
||||||
verticalSpaceSmall,
|
verticalSpaceSmall,
|
||||||
_buildBirthdayFormField(),
|
_buildBirthdayFormField(viewModel),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildBirthdayLabel() => CustomFormLabel(
|
Widget _buildBirthdayLabel() => CustomFormLabel(
|
||||||
|
|
@ -331,7 +332,12 @@ class ProfileDetailView extends StackedView<ProfileDetailViewModel>
|
||||||
style: style16DG600,
|
style: style16DG600,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBirthdayFormField() => const BirthdaySelector();
|
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(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import 'package:yimaru_app/services/authentication_service.dart';
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
import 'package:yimaru_app/ui/common/enmus.dart';
|
||||||
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
import 'package:yimaru_app/ui/common/ui_helpers.dart';
|
||||||
import 'package:yimaru_app/ui/views/home/home_view.dart';
|
import 'package:yimaru_app/ui/views/home/home_view.dart';
|
||||||
import 'package:yimaru_app/ui/views/login/login_view.dart';
|
|
||||||
|
|
||||||
import '../../../app/app.locator.dart';
|
import '../../../app/app.locator.dart';
|
||||||
import '../../../models/user_model.dart';
|
import '../../../models/user_model.dart';
|
||||||
|
|
@ -234,18 +233,20 @@ class RegisterViewModel extends FormViewModel {
|
||||||
Future<Map<String, dynamic>> _verifyOtp() async {
|
Future<Map<String, dynamic>> _verifyOtp() async {
|
||||||
Map<String, dynamic> response = await _apiService.verifyOtp(_userData);
|
Map<String, dynamic> response = await _apiService.verifyOtp(_userData);
|
||||||
if (response['status'] == ResponseStatus.success) {
|
if (response['status'] == ResponseStatus.success) {
|
||||||
// UserModel user = response['data'] as UserModel;
|
UserModel user = response['data'] as UserModel;
|
||||||
// Map<String, dynamic> data = {
|
Map<String, dynamic> data = {
|
||||||
// 'userId': user.userId,
|
'userId': user.userId,
|
||||||
// 'accessToken': user.accessToken,
|
'accessToken': user.accessToken,
|
||||||
// 'refreshToken': user.refreshToken
|
'refreshToken': user.refreshToken
|
||||||
// };
|
};
|
||||||
|
|
||||||
await _authenticationService.saveUserData({
|
// {
|
||||||
'userId': 10,
|
// 'userId': 10,
|
||||||
'accessToken': 'accessToken',
|
// 'accessToken': 'accessToken',
|
||||||
'refreshToken': 'refreshToken'
|
// 'refreshToken': 'refreshToken'
|
||||||
});
|
// }
|
||||||
|
|
||||||
|
await _authenticationService.saveUserData(data);
|
||||||
showSuccessToast(response['message']);
|
showSuccessToast(response['message']);
|
||||||
} else {
|
} else {
|
||||||
showErrorToast(response['message']);
|
showErrorToast(response['message']);
|
||||||
|
|
|
||||||
|
|
@ -227,29 +227,25 @@ class CreatePasswordScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
text: 'Sign Up',
|
text: 'Sign Up',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap:
|
onTap: passwordController.text.isNotEmpty &&
|
||||||
(viewModel.focusPassword && passwordController.text.isNotEmpty) &&
|
confirmPasswordController.text.isNotEmpty &&
|
||||||
(viewModel.focusConfirmPassword &&
|
viewModel.number &&
|
||||||
confirmPasswordController.text.isNotEmpty) &&
|
viewModel.length &&
|
||||||
viewModel.number &&
|
viewModel.specialChar &&
|
||||||
viewModel.length &&
|
viewModel.specialChar &&
|
||||||
viewModel.specialChar &&
|
viewModel.passwordMatch &&
|
||||||
viewModel.specialChar &&
|
viewModel.agree
|
||||||
viewModel.passwordMatch &&
|
? () async => await _signUp(viewModel)
|
||||||
viewModel.agree
|
: null,
|
||||||
? () async => await _signUp(viewModel)
|
backgroundColor: passwordController.text.isNotEmpty &&
|
||||||
: null,
|
confirmPasswordController.text.isNotEmpty &&
|
||||||
backgroundColor:
|
viewModel.number &&
|
||||||
(viewModel.focusPassword && passwordController.text.isNotEmpty) &&
|
viewModel.length &&
|
||||||
(viewModel.focusConfirmPassword &&
|
viewModel.specialChar &&
|
||||||
confirmPasswordController.text.isNotEmpty) &&
|
viewModel.specialChar &&
|
||||||
viewModel.number &&
|
viewModel.passwordMatch &&
|
||||||
viewModel.length &&
|
viewModel.agree
|
||||||
viewModel.specialChar &&
|
? kcPrimaryColor
|
||||||
viewModel.specialChar &&
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
viewModel.passwordMatch &&
|
|
||||||
viewModel.agree
|
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -119,13 +119,11 @@ class RegisterWithEmailScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap: viewModel.focusEmail &&
|
onTap: emailController.text.isNotEmpty &&
|
||||||
emailController.text.isNotEmpty &&
|
|
||||||
!viewModel.hasEmailValidationMessage
|
!viewModel.hasEmailValidationMessage
|
||||||
? () => _addUserData(viewModel)
|
? () => _addUserData(viewModel)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: viewModel.focusEmail &&
|
backgroundColor: emailController.text.isNotEmpty &&
|
||||||
emailController.text.isNotEmpty &&
|
|
||||||
!viewModel.hasEmailValidationMessage
|
!viewModel.hasEmailValidationMessage
|
||||||
? kcPrimaryColor
|
? kcPrimaryColor
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
|
|
|
||||||
|
|
@ -138,14 +138,12 @@ class RegisterWithPhoneNumberScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
onTap:
|
onTap: phoneNumberController.text.isNotEmpty
|
||||||
viewModel.focusPhoneNumber && phoneNumberController.text.isNotEmpty
|
? () => viewModel.goTo(page: 3, type: RegistrationType.phone)
|
||||||
? () => viewModel.goTo(page: 3, type: RegistrationType.phone)
|
: null,
|
||||||
: null,
|
backgroundColor: phoneNumberController.text.isNotEmpty
|
||||||
backgroundColor:
|
? kcPrimaryColor
|
||||||
viewModel.focusPhoneNumber && phoneNumberController.text.isNotEmpty
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
? kcPrimaryColor
|
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildRegisterWitPhoneNumberButton(RegisterViewModel viewModel) =>
|
Widget _buildRegisterWitPhoneNumberButton(RegisterViewModel viewModel) =>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_timer_countdown/flutter_timer_countdown.dart';
|
import 'package:flutter_timer_countdown/flutter_timer_countdown.dart';
|
||||||
import 'package:pinput/pinput.dart';
|
import 'package:pinput/pinput.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
import 'package:stacked/stacked.dart';
|
||||||
import 'package:yimaru_app/ui/common/enmus.dart';
|
|
||||||
|
|
||||||
import 'package:yimaru_app/ui/views/register/register_viewmodel.dart';
|
import 'package:yimaru_app/ui/views/register/register_viewmodel.dart';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_cursor.dart';
|
import 'package:yimaru_app/ui/widgets/custom_cursor.dart';
|
||||||
|
|
@ -164,15 +163,13 @@ class RegistrationOtpScreen extends ViewModelWidget<RegisterViewModel> {
|
||||||
text: 'Continue',
|
text: 'Continue',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
foregroundColor: kcWhite,
|
foregroundColor: kcWhite,
|
||||||
backgroundColor: viewModel.focusOtp &&
|
backgroundColor:
|
||||||
otpController.text.length == 6 &&
|
otpController.text.length == 6 && !viewModel.hasOtpValidationMessage
|
||||||
!viewModel.hasOtpValidationMessage
|
? kcPrimaryColor
|
||||||
? kcPrimaryColor
|
: kcPrimaryColor.withOpacity(0.1),
|
||||||
: kcPrimaryColor.withOpacity(0.1),
|
onTap:
|
||||||
onTap: viewModel.focusOtp &&
|
otpController.text.length == 6 && !viewModel.hasOtpValidationMessage
|
||||||
otpController.text.length == 6 &&
|
? () async => await _verifyOtp(viewModel)
|
||||||
!viewModel.hasOtpValidationMessage
|
: null,
|
||||||
? () async => await _verifyOtp(viewModel)
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@ import '../../common/app_colors.dart';
|
||||||
import 'startup_viewmodel.dart';
|
import 'startup_viewmodel.dart';
|
||||||
|
|
||||||
class StartupView extends StackedView<StartupViewModel> {
|
class StartupView extends StackedView<StartupViewModel> {
|
||||||
const StartupView({Key? key}) : super(key: key);
|
final String label;
|
||||||
|
const StartupView({Key? key, this.label = 'Loading'}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget builder(
|
Widget builder(
|
||||||
|
|
@ -70,7 +71,7 @@ class StartupView extends StackedView<StartupViewModel> {
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildLoadingText() =>
|
Widget _buildLoadingText() =>
|
||||||
const Text('Loading ...', style: TextStyle(color: kcWhite, fontSize: 16));
|
Text('$label ...', style: const TextStyle(color: kcWhite, fontSize: 16));
|
||||||
|
|
||||||
Widget _buildIndicatorWrapper() => SizedBox(
|
Widget _buildIndicatorWrapper() => SizedBox(
|
||||||
width: 16,
|
width: 16,
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,17 @@ class StartupViewModel extends BaseViewModel {
|
||||||
|
|
||||||
// Place anything here that needs to happen before we get into the application
|
// Place anything here that needs to happen before we get into the application
|
||||||
Future runStartupLogic() async {
|
Future runStartupLogic() async {
|
||||||
final response = await _authenticationService.userLoggedIn();
|
final loggedIn = await _authenticationService.userLoggedIn();
|
||||||
if (response) {
|
final firstTimeInstall = await _authenticationService.isFirstTimeInstall();
|
||||||
_navigationService.replaceWithHomeView();
|
|
||||||
|
if (firstTimeInstall) {
|
||||||
|
_navigationService.replaceWithWelcomeView();
|
||||||
} else {
|
} else {
|
||||||
_navigationService.replaceWithLoginView();
|
if (loggedIn) {
|
||||||
|
_navigationService.replaceWithHomeView();
|
||||||
|
} else {
|
||||||
|
_navigationService.replaceWithLoginView();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,26 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
|
||||||
|
|
||||||
class FirstWelcomeScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../welcome_viewmodel.dart';
|
||||||
|
|
||||||
|
class FirstWelcomeScreen extends ViewModelWidget<WelcomeViewModel> {
|
||||||
const FirstWelcomeScreen({super.key});
|
const FirstWelcomeScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, WelcomeViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(WelcomeViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Stack(
|
Widget _buildScaffold(WelcomeViewModel viewModel) => Stack(
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildScaffoldChildren(WelcomeViewModel viewModel) => [
|
||||||
_buildBackground(),
|
_buildBackground(),
|
||||||
_buildColumnWrapper(),
|
_buildColumnWrapper(),
|
||||||
_buildContinueButtonWrapper(viewModel)
|
_buildContinueButtonWrapper(viewModel)
|
||||||
|
|
@ -68,17 +69,17 @@ class FirstWelcomeScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Align(
|
Widget _buildContinueButtonWrapper(WelcomeViewModel viewModel) => Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: _buildButtonContainer(viewModel),
|
child: _buildButtonContainer(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonContainer(OnboardingViewModel viewModel) => Padding(
|
Widget _buildButtonContainer(WelcomeViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50, right: 50, left: 50),
|
padding: const EdgeInsets.only(bottom: 50, right: 50, left: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(WelcomeViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
|
|
@ -4,25 +4,26 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
|
||||||
|
|
||||||
class SecondWelcomeScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../welcome_viewmodel.dart';
|
||||||
|
|
||||||
|
class SecondWelcomeScreen extends ViewModelWidget<WelcomeViewModel> {
|
||||||
const SecondWelcomeScreen({super.key});
|
const SecondWelcomeScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, WelcomeViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(WelcomeViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Stack(
|
Widget _buildScaffold(WelcomeViewModel viewModel) => Stack(
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildScaffoldChildren(WelcomeViewModel viewModel) => [
|
||||||
_buildBackground(),
|
_buildBackground(),
|
||||||
_buildColumnWrapper(),
|
_buildColumnWrapper(),
|
||||||
_buildContinueButtonWrapper(viewModel)
|
_buildContinueButtonWrapper(viewModel)
|
||||||
|
|
@ -68,17 +69,17 @@ class SecondWelcomeScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Align(
|
Widget _buildContinueButtonWrapper(WelcomeViewModel viewModel) => Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: _buildButtonContainer(viewModel),
|
child: _buildButtonContainer(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonContainer(OnboardingViewModel viewModel) => Padding(
|
Widget _buildButtonContainer(WelcomeViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50, right: 50, left: 50),
|
padding: const EdgeInsets.only(bottom: 50, right: 50, left: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButton(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButton(WelcomeViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
|
|
@ -4,25 +4,27 @@ 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';
|
||||||
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
import 'package:yimaru_app/ui/widgets/custom_elevated_button.dart';
|
||||||
import 'package:yimaru_app/ui/views/onboarding/onboarding_viewmodel.dart';
|
|
||||||
|
|
||||||
class ThirdWelcomeScreen extends ViewModelWidget<OnboardingViewModel> {
|
import '../../../widgets/custom_circular_progress_indicator.dart';
|
||||||
|
import '../welcome_viewmodel.dart';
|
||||||
|
|
||||||
|
class ThirdWelcomeScreen extends ViewModelWidget<WelcomeViewModel> {
|
||||||
const ThirdWelcomeScreen({super.key});
|
const ThirdWelcomeScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, OnboardingViewModel viewModel) =>
|
Widget build(BuildContext context, WelcomeViewModel viewModel) =>
|
||||||
_buildScaffoldWrapper(viewModel);
|
_buildScaffoldWrapper(viewModel);
|
||||||
|
|
||||||
Widget _buildScaffoldWrapper(OnboardingViewModel viewModel) => Scaffold(
|
Widget _buildScaffoldWrapper(WelcomeViewModel viewModel) => Scaffold(
|
||||||
backgroundColor: kcBackgroundColor,
|
backgroundColor: kcBackgroundColor,
|
||||||
body: _buildScaffold(viewModel),
|
body: _buildScaffold(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildScaffold(OnboardingViewModel viewModel) => Stack(
|
Widget _buildScaffold(WelcomeViewModel viewModel) => Stack(
|
||||||
children: _buildScaffoldChildren(viewModel),
|
children: _buildScaffoldChildren(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildScaffoldChildren(OnboardingViewModel viewModel) => [
|
List<Widget> _buildScaffoldChildren(WelcomeViewModel viewModel) => [
|
||||||
_buildBackground(),
|
_buildBackground(),
|
||||||
_buildColumnWrapper(),
|
_buildColumnWrapper(),
|
||||||
_buildContinueButtonWrapper(viewModel)
|
_buildContinueButtonWrapper(viewModel)
|
||||||
|
|
@ -52,6 +54,7 @@ class ThirdWelcomeScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
verticalSpaceMedium,
|
verticalSpaceMedium,
|
||||||
_buildTitle(),
|
_buildTitle(),
|
||||||
];
|
];
|
||||||
|
|
||||||
Widget _buildIcon() => SvgPicture.asset(
|
Widget _buildIcon() => SvgPicture.asset(
|
||||||
'assets/icons/logo.svg',
|
'assets/icons/logo.svg',
|
||||||
height: 50,
|
height: 50,
|
||||||
|
|
@ -67,24 +70,30 @@ class ThirdWelcomeScreen extends ViewModelWidget<OnboardingViewModel> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButtonWrapper(OnboardingViewModel viewModel) => Align(
|
Widget _buildContinueButtonWrapper(WelcomeViewModel viewModel) => Align(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: _buildButtonContainer(viewModel),
|
child: _buildButtonContainer(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonContainer(OnboardingViewModel viewModel) => Padding(
|
Widget _buildButtonContainer(WelcomeViewModel viewModel) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 50, right: 50, left: 50),
|
padding: const EdgeInsets.only(bottom: 50, right: 50, left: 50),
|
||||||
child: _buildContinueButton(viewModel),
|
child: _buildContinueButtonState(viewModel),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContinueButton(OnboardingViewModel viewModel) =>
|
Widget _buildContinueButtonState(WelcomeViewModel viewModel) =>
|
||||||
|
viewModel.isBusy ? _buildIndicator() : _buildContinueButton(viewModel);
|
||||||
|
|
||||||
|
Widget _buildIndicator() =>
|
||||||
|
const CustomCircularProgressIndicator(color: kcWhite);
|
||||||
|
|
||||||
|
Widget _buildContinueButton(WelcomeViewModel viewModel) =>
|
||||||
CustomElevatedButton(
|
CustomElevatedButton(
|
||||||
height: 55,
|
height: 55,
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
text: 'Start Learning',
|
text: 'Start Learning',
|
||||||
backgroundColor: kcWhite,
|
backgroundColor: kcWhite,
|
||||||
trailingIcon: Icons.arrow_forward,
|
|
||||||
onTap: () => viewModel.next(),
|
|
||||||
foregroundColor: kcPrimaryColor,
|
foregroundColor: kcPrimaryColor,
|
||||||
|
trailingIcon: Icons.arrow_forward,
|
||||||
|
onTap: () async => await viewModel.setFirstTimeInstall(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
|
||||||
|
import 'screens/first_welcome_screen.dart';
|
||||||
|
import 'screens/second_welcome_screen.dart';
|
||||||
|
import 'screens/third_welcome_screen.dart';
|
||||||
|
import 'welcome_viewmodel.dart';
|
||||||
|
|
||||||
|
class WelcomeView extends StackedView<WelcomeViewModel> {
|
||||||
|
const WelcomeView({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
WelcomeViewModel viewModelBuilder(BuildContext context) => WelcomeViewModel();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget builder(
|
||||||
|
BuildContext context,
|
||||||
|
WelcomeViewModel viewModel,
|
||||||
|
Widget? child,
|
||||||
|
) =>
|
||||||
|
_buildWelcomeScreens(viewModel);
|
||||||
|
|
||||||
|
Widget _buildWelcomeScreens(WelcomeViewModel viewModel) => IndexedStack(
|
||||||
|
index: viewModel.currentPage,
|
||||||
|
children: _buildScreens(),
|
||||||
|
);
|
||||||
|
|
||||||
|
List<Widget> _buildScreens() =>
|
||||||
|
[_buildFirstWelcome(), _buildSecondWelcome(), _buildThirdWelcome()];
|
||||||
|
|
||||||
|
Widget _buildFirstWelcome() => const FirstWelcomeScreen();
|
||||||
|
|
||||||
|
Widget _buildSecondWelcome() => const SecondWelcomeScreen();
|
||||||
|
|
||||||
|
Widget _buildThirdWelcome() => const ThirdWelcomeScreen();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import 'package:stacked/stacked.dart';
|
||||||
|
import 'package:stacked_services/stacked_services.dart';
|
||||||
|
import 'package:yimaru_app/app/app.router.dart';
|
||||||
|
import 'package:yimaru_app/services/authentication_service.dart';
|
||||||
|
|
||||||
|
import '../../../app/app.locator.dart';
|
||||||
|
|
||||||
|
class WelcomeViewModel extends BaseViewModel {
|
||||||
|
final _navigationService = locator<NavigationService>();
|
||||||
|
|
||||||
|
final _authenticationService = locator<AuthenticationService>();
|
||||||
|
|
||||||
|
int _currentPage = 0;
|
||||||
|
|
||||||
|
int get currentPage => _currentPage;
|
||||||
|
|
||||||
|
Future<void> setFirstTimeInstall() async {
|
||||||
|
await runBusyFuture(_setFirstTimeInstall());
|
||||||
|
}
|
||||||
|
|
||||||
|
// First time install
|
||||||
|
Future<void> _setFirstTimeInstall() async {
|
||||||
|
await _authenticationService.setFirstTimeInstall(false);
|
||||||
|
await navigateToLogin();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Navigation
|
||||||
|
Future<void> navigateToLogin() async =>
|
||||||
|
await _navigationService.navigateToLoginView();
|
||||||
|
|
||||||
|
void next() {
|
||||||
|
_currentPage++;
|
||||||
|
rebuildUi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:stacked/stacked.dart';
|
|
||||||
import 'package:yimaru_app/ui/views/profile_detail/profile_detail_viewmodel.dart';
|
|
||||||
import '../common/app_colors.dart';
|
import '../common/app_colors.dart';
|
||||||
import '../common/ui_helpers.dart';
|
import '../common/ui_helpers.dart';
|
||||||
import 'package:omni_datetime_picker/omni_datetime_picker.dart';
|
import 'package:omni_datetime_picker/omni_datetime_picker.dart';
|
||||||
|
|
||||||
class BirthdaySelector extends ViewModelWidget<ProfileDetailViewModel> {
|
class BirthdaySelector extends StatelessWidget {
|
||||||
const BirthdaySelector({super.key});
|
final String? birthday;
|
||||||
|
final void Function(DateTime)? onSelected;
|
||||||
|
|
||||||
DateTime _initialDate(ProfileDetailViewModel viewModel) {
|
const BirthdaySelector({super.key, this.birthday, this.onSelected});
|
||||||
|
|
||||||
|
DateTime _initialDate() {
|
||||||
try {
|
try {
|
||||||
final parsedDate = format.parse(viewModel.selectedBirthday ?? '');
|
final parsedDate = format.parse(birthday ?? '');
|
||||||
return parsedDate.isAfter(DateTime.now()) ? DateTime.now() : parsedDate;
|
return parsedDate.isAfter(DateTime.now()) ? DateTime.now() : parsedDate;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
return DateTime.now();
|
return DateTime.now();
|
||||||
|
|
@ -19,8 +20,8 @@ class BirthdaySelector extends ViewModelWidget<ProfileDetailViewModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pickDateTime(
|
Future<void> _pickDateTime(
|
||||||
{required BuildContext context,
|
BuildContext context,
|
||||||
required ProfileDetailViewModel viewModel}) async {
|
) async {
|
||||||
DateTime? dateTime = await showOmniDateTimePicker(
|
DateTime? dateTime = await showOmniDateTimePicker(
|
||||||
context: context,
|
context: context,
|
||||||
is24HourMode: false,
|
is24HourMode: false,
|
||||||
|
|
@ -28,10 +29,10 @@ class BirthdaySelector extends ViewModelWidget<ProfileDetailViewModel> {
|
||||||
lastDate: DateTime.now(),
|
lastDate: DateTime.now(),
|
||||||
firstDate: DateTime(1900),
|
firstDate: DateTime(1900),
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
|
initialDate: _initialDate(),
|
||||||
titleSeparator: const Divider(),
|
titleSeparator: const Divider(),
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
type: OmniDateTimePickerType.date,
|
type: OmniDateTimePickerType.date,
|
||||||
initialDate: _initialDate(viewModel),
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
||||||
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 24),
|
insetPadding: const EdgeInsets.symmetric(horizontal: 40, vertical: 24),
|
||||||
title: const Text('Birthday', style: TextStyle(fontSize: 16)),
|
title: const Text('Birthday', style: TextStyle(fontSize: 16)),
|
||||||
|
|
@ -42,56 +43,55 @@ class BirthdaySelector extends ViewModelWidget<ProfileDetailViewModel> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (dateTime != null) {
|
if (dateTime != null) {
|
||||||
String formattedDateTime = DateFormat('d MMM, yyyy').format(dateTime);
|
// String formattedDateTime = DateFormat('d MMM, yyyy').format(dateTime);
|
||||||
|
|
||||||
viewModel.setBirthday(DateFormat('d MMM, yyyy').format(dateTime));
|
if (onSelected != null) {
|
||||||
//onChanged(formattedDateTime);
|
onSelected!(dateTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, ProfileDetailViewModel viewModel) =>
|
Widget build(
|
||||||
_buildButtonWrapper(context: context, viewModel: viewModel);
|
BuildContext context,
|
||||||
|
) =>
|
||||||
|
_buildButtonWrapper(
|
||||||
|
context,
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildButtonWrapper(
|
Widget _buildButtonWrapper(BuildContext context) => Container(
|
||||||
{required BuildContext context,
|
|
||||||
required ProfileDetailViewModel viewModel}) =>
|
|
||||||
Container(
|
|
||||||
height: 50,
|
height: 50,
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
margin: const EdgeInsets.only(bottom: 15),
|
margin: const EdgeInsets.only(bottom: 15),
|
||||||
child: _buildContainerWrapper(context: context, viewModel: viewModel),
|
child: _buildContainerWrapper(context),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContainerWrapper(
|
Widget _buildContainerWrapper(BuildContext context) => GestureDetector(
|
||||||
{required BuildContext context,
|
onTap: () async => await _pickDateTime(
|
||||||
required ProfileDetailViewModel viewModel}) =>
|
context,
|
||||||
GestureDetector(
|
),
|
||||||
onTap: () async =>
|
child: _buildContainer(),
|
||||||
await _pickDateTime(context: context, viewModel: viewModel),
|
|
||||||
child: _buildContainer(viewModel),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildContainer(ProfileDetailViewModel viewModel) => Container(
|
Widget _buildContainer() => Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
color: kcPrimaryColor.withOpacity(0.1),
|
color: kcPrimaryColor.withOpacity(0.1),
|
||||||
border: Border.all(color: kcPrimaryColor),
|
border: Border.all(color: kcPrimaryColor),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||||
child: _buildButtonRowWrapper(viewModel),
|
child: _buildButtonRowWrapper(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildButtonRowWrapper(ProfileDetailViewModel viewModel) => Row(
|
Widget _buildButtonRowWrapper() => Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: _buildButtonRowChildren(viewModel),
|
children: _buildButtonRowChildren(),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildButtonRowChildren(ProfileDetailViewModel viewModel) =>
|
List<Widget> _buildButtonRowChildren() => [_buildText(), _buildIcon()];
|
||||||
[_buildText(viewModel), _buildIcon()];
|
|
||||||
|
|
||||||
Widget _buildText(ProfileDetailViewModel viewModel) => Text(
|
Widget _buildText() => Text(
|
||||||
viewModel.selectedBirthday ?? 'Pick birthday',
|
birthday ?? 'Pick birthday',
|
||||||
style: const TextStyle(color: kcDarkGrey),
|
style: const TextStyle(color: kcDarkGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../common/app_colors.dart';
|
|
||||||
|
|
||||||
class CustomCircularProgressIndicator extends StatelessWidget {
|
class CustomCircularProgressIndicator extends StatelessWidget {
|
||||||
final Color color;
|
final Color color;
|
||||||
const CustomCircularProgressIndicator({super.key, required this.color});
|
const CustomCircularProgressIndicator({super.key, required this.color});
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,15 @@ class CustomSmallRadioButton extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
List<Widget> _buildButtonRowChildren() =>
|
List<Widget> _buildButtonRowChildren() =>
|
||||||
[_buildText(), if (selected) _buildIcon()];
|
[_buildTextWrapper(), if (selected) _buildIcon()];
|
||||||
|
|
||||||
|
Widget _buildTextWrapper() => Expanded(
|
||||||
|
child: _buildText(),
|
||||||
|
);
|
||||||
|
|
||||||
Widget _buildText() => Text(
|
Widget _buildText() => Text(
|
||||||
title,
|
title,
|
||||||
|
maxLines: 2,
|
||||||
style: const TextStyle(color: kcDarkGrey),
|
style: const TextStyle(color: kcDarkGrey),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,12 @@ import 'package:yimaru_app/ui/widgets/language_button.dart';
|
||||||
|
|
||||||
class LargeAppBar extends StatelessWidget {
|
class LargeAppBar extends StatelessWidget {
|
||||||
final bool showBackButton;
|
final bool showBackButton;
|
||||||
final GestureTapCallback? onTap;
|
|
||||||
final GestureTapCallback? onPop;
|
final GestureTapCallback? onPop;
|
||||||
final bool showLanguageSelection;
|
final bool showLanguageSelection;
|
||||||
final GestureTapCallback? onLanguage;
|
final GestureTapCallback? onLanguage;
|
||||||
|
|
||||||
const LargeAppBar(
|
const LargeAppBar(
|
||||||
{super.key,
|
{super.key,
|
||||||
this.onTap,
|
|
||||||
this.onPop,
|
this.onPop,
|
||||||
this.onLanguage,
|
this.onLanguage,
|
||||||
required this.showBackButton,
|
required this.showBackButton,
|
||||||
|
|
@ -48,16 +46,16 @@ class LargeAppBar extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildBackButton() => BackButton(
|
Widget _buildBackButton() => BackButton(
|
||||||
onPressed: onTap,
|
onPressed: onPop,
|
||||||
style:
|
style:
|
||||||
const ButtonStyle(foregroundColor: WidgetStatePropertyAll(kcWhite)),
|
const ButtonStyle(foregroundColor: WidgetStatePropertyAll(kcWhite)),
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildRightButton() => Align(
|
Widget _buildRightButton() => Align(
|
||||||
alignment: Alignment.bottomRight,
|
alignment: Alignment.bottomRight,
|
||||||
child: showLanguageSelection
|
child: showLanguageSelection ? _buildLanguageSelector() : Container()
|
||||||
? _buildLanguageSelector()
|
// _buildCloseButton()
|
||||||
: _buildCloseButton());
|
);
|
||||||
|
|
||||||
Widget _buildLanguageSelector() => LanguageButton(
|
Widget _buildLanguageSelector() => LanguageButton(
|
||||||
language: 'EN',
|
language: 'EN',
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,14 @@
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import battery_plus
|
||||||
|
import connectivity_plus
|
||||||
import flutter_secure_storage_darwin
|
import flutter_secure_storage_darwin
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
BatteryPlusMacosPlugin.register(with: registry.registrar(forPlugin: "BatteryPlusMacosPlugin"))
|
||||||
|
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
|
||||||
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
|
FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.0"
|
version: "2.13.0"
|
||||||
|
battery_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: battery_plus
|
||||||
|
sha256: ad16fcb55b7384be6b4bbc763d5e2031ac7ea62b2d9b6b661490c7b9741155bf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
battery_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: battery_plus_platform_interface
|
||||||
|
sha256: e8342c0f32de4b1dfd0223114b6785e48e579bfc398da9471c9179b907fa4910
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
bloc:
|
bloc:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -153,6 +169,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.1"
|
version: "1.19.1"
|
||||||
|
connectivity_plus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: connectivity_plus
|
||||||
|
sha256: "33bae12a398f841c6cda09d1064212957265869104c478e5ad51e2fb26c3973c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
connectivity_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: connectivity_plus_platform_interface
|
||||||
|
sha256: "42657c1715d48b167930d5f34d00222ac100475f73d10162ddf43e714932f204"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -185,6 +217,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.6"
|
version: "2.3.6"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.11"
|
||||||
dio:
|
dio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -464,6 +504,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
in_app_update:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: in_app_update
|
||||||
|
sha256: "9924a3efe592e1c0ec89dda3683b3cfec3d4cd02d908e6de00c24b759038ddb1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.5"
|
||||||
|
internet_connection_checker_plus:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: internet_connection_checker_plus
|
||||||
|
sha256: ef43530f24de6309f99802358f8a543ea1f2babc153effc84a75133751716892
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.9.1+2"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -608,6 +664,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
nm:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nm
|
||||||
|
sha256: "2c9aae4127bdc8993206464fcc063611e0e36e72018696cd9631023a31b24254"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.0"
|
||||||
omni_datetime_picker:
|
omni_datetime_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -861,6 +925,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.2"
|
version: "1.4.2"
|
||||||
|
storage_info:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: storage_info
|
||||||
|
sha256: adbf5fd1a7c2ca977dd828573820db0a0a16f4aa317e0ab72e9b3282eb5bbe42
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -933,6 +1005,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.1"
|
||||||
|
upower:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: upower
|
||||||
|
sha256: cf042403154751180affa1d15614db7fa50234bc2373cd21c3db666c38543ebf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.0"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,11 @@ dependencies:
|
||||||
iconsax: ^0.0.8
|
iconsax: ^0.0.8
|
||||||
flutter_svg: ^2.2.3
|
flutter_svg: ^2.2.3
|
||||||
stacked_shared: any
|
stacked_shared: any
|
||||||
|
battery_plus: ^7.0.0
|
||||||
|
storage_info: ^1.0.0
|
||||||
flutter_html: ^3.0.0
|
flutter_html: ^3.0.0
|
||||||
email_validator: any
|
email_validator: any
|
||||||
|
in_app_update: ^4.2.5
|
||||||
toastification: ^3.0.3
|
toastification: ^3.0.3
|
||||||
dropdown_search: ^6.0.2
|
dropdown_search: ^6.0.2
|
||||||
json_annotation: ^4.9.0
|
json_annotation: ^4.9.0
|
||||||
|
|
@ -26,6 +29,7 @@ dependencies:
|
||||||
json_serializable: ^6.8.0
|
json_serializable: ^6.8.0
|
||||||
flutter_secure_storage: ^10.0.0
|
flutter_secure_storage: ^10.0.0
|
||||||
flutter_timer_countdown: ^1.0.7
|
flutter_timer_countdown: ^1.0.7
|
||||||
|
internet_connection_checker_plus: ^2.9.1+2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import 'package:yimaru_app/services/authentication_service.dart';
|
||||||
import 'package:yimaru_app/services/api_service.dart';
|
import 'package:yimaru_app/services/api_service.dart';
|
||||||
import 'package:yimaru_app/services/secure_storage_service.dart';
|
import 'package:yimaru_app/services/secure_storage_service.dart';
|
||||||
import 'package:yimaru_app/services/dio_service.dart';
|
import 'package:yimaru_app/services/dio_service.dart';
|
||||||
|
import 'package:yimaru_app/services/status_checker_service.dart';
|
||||||
// @stacked-import
|
// @stacked-import
|
||||||
|
|
||||||
import 'test_helpers.mocks.dart';
|
import 'test_helpers.mocks.dart';
|
||||||
|
|
@ -20,6 +21,7 @@ import 'test_helpers.mocks.dart';
|
||||||
MockSpec<ApiService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<ApiService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<SecureStorageService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<SecureStorageService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
MockSpec<DioService>(onMissingStub: OnMissingStub.returnDefault),
|
MockSpec<DioService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
|
MockSpec<StatusCheckerService>(onMissingStub: OnMissingStub.returnDefault),
|
||||||
// @stacked-mock-spec
|
// @stacked-mock-spec
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
@ -31,6 +33,7 @@ void registerServices() {
|
||||||
getAndRegisterApiService();
|
getAndRegisterApiService();
|
||||||
getAndRegisterSecureStorageService();
|
getAndRegisterSecureStorageService();
|
||||||
getAndRegisterDioService();
|
getAndRegisterDioService();
|
||||||
|
getAndRegisterStatusCheckerService();
|
||||||
// @stacked-mock-register
|
// @stacked-mock-register
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -115,6 +118,13 @@ MockDioService getAndRegisterDioService() {
|
||||||
locator.registerSingleton<DioService>(service);
|
locator.registerSingleton<DioService>(service);
|
||||||
return service;
|
return service;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MockStatusCheckerService getAndRegisterStatusCheckerService() {
|
||||||
|
_removeRegistrationIfExists<StatusCheckerService>();
|
||||||
|
final service = MockStatusCheckerService();
|
||||||
|
locator.registerSingleton<StatusCheckerService>(service);
|
||||||
|
return service;
|
||||||
|
}
|
||||||
// @stacked-mock-create
|
// @stacked-mock-create
|
||||||
|
|
||||||
void _removeRegistrationIfExists<T extends Object>() {
|
void _removeRegistrationIfExists<T extends Object>() {
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,21 @@
|
||||||
// Do not manually edit this file.
|
// Do not manually edit this file.
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
import 'dart:async' as _i6;
|
import 'dart:async' as _i8;
|
||||||
import 'dart:ui' as _i7;
|
import 'dart:ui' as _i9;
|
||||||
|
|
||||||
import 'package:flutter/material.dart' as _i5;
|
import 'package:dio/dio.dart' as _i3;
|
||||||
|
import 'package:flutter/material.dart' as _i7;
|
||||||
import 'package:mockito/mockito.dart' as _i1;
|
import 'package:mockito/mockito.dart' as _i1;
|
||||||
import 'package:mockito/src/dummies.dart' as _i4;
|
import 'package:mockito/src/dummies.dart' as _i6;
|
||||||
import 'package:stacked_services/stacked_services.dart' as _i3;
|
import 'package:stacked_services/stacked_services.dart' as _i5;
|
||||||
|
import 'package:yimaru_app/models/assessment.dart' as _i12;
|
||||||
import 'package:yimaru_app/models/user_model.dart' as _i2;
|
import 'package:yimaru_app/models/user_model.dart' as _i2;
|
||||||
import 'package:yimaru_app/services/api_service.dart' as _i9;
|
import 'package:yimaru_app/services/api_service.dart' as _i11;
|
||||||
import 'package:yimaru_app/services/authentication_service.dart' as _i8;
|
import 'package:yimaru_app/services/authentication_service.dart' as _i10;
|
||||||
import 'package:yimaru_app/services/dio_service.dart' as _i11;
|
import 'package:yimaru_app/services/dio_service.dart' as _i13;
|
||||||
import 'package:yimaru_app/services/secure_storage_service.dart' as _i10;
|
import 'package:yimaru_app/services/secure_storage_service.dart' as _i4;
|
||||||
|
import 'package:yimaru_app/services/status_checker_service.dart' as _i14;
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: avoid_redundant_argument_values
|
// ignore_for_file: avoid_redundant_argument_values
|
||||||
|
|
@ -39,18 +42,39 @@ class _FakeUserModel_0 extends _i1.SmartFake implements _i2.UserModel {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _FakeDio_1 extends _i1.SmartFake implements _i3.Dio {
|
||||||
|
_FakeDio_1(
|
||||||
|
Object parent,
|
||||||
|
Invocation parentInvocation,
|
||||||
|
) : super(
|
||||||
|
parent,
|
||||||
|
parentInvocation,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FakeSecureStorageService_2 extends _i1.SmartFake
|
||||||
|
implements _i4.SecureStorageService {
|
||||||
|
_FakeSecureStorageService_2(
|
||||||
|
Object parent,
|
||||||
|
Invocation parentInvocation,
|
||||||
|
) : super(
|
||||||
|
parent,
|
||||||
|
parentInvocation,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// A class which mocks [NavigationService].
|
/// A class which mocks [NavigationService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
class MockNavigationService extends _i1.Mock implements _i5.NavigationService {
|
||||||
@override
|
@override
|
||||||
String get previousRoute => (super.noSuchMethod(
|
String get previousRoute => (super.noSuchMethod(
|
||||||
Invocation.getter(#previousRoute),
|
Invocation.getter(#previousRoute),
|
||||||
returnValue: _i4.dummyValue<String>(
|
returnValue: _i6.dummyValue<String>(
|
||||||
this,
|
this,
|
||||||
Invocation.getter(#previousRoute),
|
Invocation.getter(#previousRoute),
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: _i4.dummyValue<String>(
|
returnValueForMissingStub: _i6.dummyValue<String>(
|
||||||
this,
|
this,
|
||||||
Invocation.getter(#previousRoute),
|
Invocation.getter(#previousRoute),
|
||||||
),
|
),
|
||||||
|
|
@ -59,25 +83,25 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
@override
|
@override
|
||||||
String get currentRoute => (super.noSuchMethod(
|
String get currentRoute => (super.noSuchMethod(
|
||||||
Invocation.getter(#currentRoute),
|
Invocation.getter(#currentRoute),
|
||||||
returnValue: _i4.dummyValue<String>(
|
returnValue: _i6.dummyValue<String>(
|
||||||
this,
|
this,
|
||||||
Invocation.getter(#currentRoute),
|
Invocation.getter(#currentRoute),
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: _i4.dummyValue<String>(
|
returnValueForMissingStub: _i6.dummyValue<String>(
|
||||||
this,
|
this,
|
||||||
Invocation.getter(#currentRoute),
|
Invocation.getter(#currentRoute),
|
||||||
),
|
),
|
||||||
) as String);
|
) as String);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i5.GlobalKey<_i5.NavigatorState>? nestedNavigationKey(int? index) =>
|
_i7.GlobalKey<_i7.NavigatorState>? nestedNavigationKey(int? index) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#nestedNavigationKey,
|
#nestedNavigationKey,
|
||||||
[index],
|
[index],
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i5.GlobalKey<_i5.NavigatorState>?);
|
) as _i7.GlobalKey<_i7.NavigatorState>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void config({
|
void config({
|
||||||
|
|
@ -86,7 +110,7 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
bool? defaultOpaqueRoute,
|
bool? defaultOpaqueRoute,
|
||||||
Duration? defaultDurationTransition,
|
Duration? defaultDurationTransition,
|
||||||
bool? defaultGlobalState,
|
bool? defaultGlobalState,
|
||||||
_i3.Transition? defaultTransitionStyle,
|
_i5.Transition? defaultTransitionStyle,
|
||||||
String? defaultTransition,
|
String? defaultTransition,
|
||||||
}) =>
|
}) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
|
|
@ -107,18 +131,18 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? navigateWithTransition<T>(
|
_i8.Future<T?>? navigateWithTransition<T>(
|
||||||
_i5.Widget? page, {
|
_i7.Widget? page, {
|
||||||
bool? opaque,
|
bool? opaque,
|
||||||
String? transition = r'',
|
String? transition = r'',
|
||||||
Duration? duration,
|
Duration? duration,
|
||||||
bool? popGesture,
|
bool? popGesture,
|
||||||
int? id,
|
int? id,
|
||||||
_i5.Curve? curve,
|
_i7.Curve? curve,
|
||||||
bool? fullscreenDialog = false,
|
bool? fullscreenDialog = false,
|
||||||
bool? preventDuplicates = true,
|
bool? preventDuplicates = true,
|
||||||
_i3.Transition? transitionClass,
|
_i5.Transition? transitionClass,
|
||||||
_i3.Transition? transitionStyle,
|
_i5.Transition? transitionStyle,
|
||||||
String? routeName,
|
String? routeName,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
|
@ -140,21 +164,21 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? replaceWithTransition<T>(
|
_i8.Future<T?>? replaceWithTransition<T>(
|
||||||
_i5.Widget? page, {
|
_i7.Widget? page, {
|
||||||
bool? opaque,
|
bool? opaque,
|
||||||
String? transition = r'',
|
String? transition = r'',
|
||||||
Duration? duration,
|
Duration? duration,
|
||||||
bool? popGesture,
|
bool? popGesture,
|
||||||
int? id,
|
int? id,
|
||||||
_i5.Curve? curve,
|
_i7.Curve? curve,
|
||||||
bool? fullscreenDialog = false,
|
bool? fullscreenDialog = false,
|
||||||
bool? preventDuplicates = true,
|
bool? preventDuplicates = true,
|
||||||
_i3.Transition? transitionClass,
|
_i5.Transition? transitionClass,
|
||||||
_i3.Transition? transitionStyle,
|
_i5.Transition? transitionStyle,
|
||||||
String? routeName,
|
String? routeName,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
|
|
@ -176,7 +200,7 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool back<T>({
|
bool back<T>({
|
||||||
|
|
@ -198,7 +222,7 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void popUntil(
|
void popUntil(
|
||||||
_i5.RoutePredicate? predicate, {
|
_i7.RoutePredicate? predicate, {
|
||||||
int? id,
|
int? id,
|
||||||
}) =>
|
}) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
|
|
@ -220,13 +244,13 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? navigateTo<T>(
|
_i8.Future<T?>? navigateTo<T>(
|
||||||
String? routeName, {
|
String? routeName, {
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
bool? preventDuplicates = true,
|
bool? preventDuplicates = true,
|
||||||
Map<String, String>? parameters,
|
Map<String, String>? parameters,
|
||||||
_i5.RouteTransitionsBuilder? transition,
|
_i7.RouteTransitionsBuilder? transition,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -241,21 +265,21 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? navigateToView<T>(
|
_i8.Future<T?>? navigateToView<T>(
|
||||||
_i5.Widget? view, {
|
_i7.Widget? view, {
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
bool? opaque,
|
bool? opaque,
|
||||||
_i5.Curve? curve,
|
_i7.Curve? curve,
|
||||||
Duration? duration,
|
Duration? duration,
|
||||||
bool? fullscreenDialog = false,
|
bool? fullscreenDialog = false,
|
||||||
bool? popGesture,
|
bool? popGesture,
|
||||||
bool? preventDuplicates = true,
|
bool? preventDuplicates = true,
|
||||||
_i3.Transition? transition,
|
_i5.Transition? transition,
|
||||||
_i3.Transition? transitionStyle,
|
_i5.Transition? transitionStyle,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -275,16 +299,16 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? replaceWith<T>(
|
_i8.Future<T?>? replaceWith<T>(
|
||||||
String? routeName, {
|
String? routeName, {
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
bool? preventDuplicates = true,
|
bool? preventDuplicates = true,
|
||||||
Map<String, String>? parameters,
|
Map<String, String>? parameters,
|
||||||
_i5.RouteTransitionsBuilder? transition,
|
_i7.RouteTransitionsBuilder? transition,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -299,10 +323,10 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? clearStackAndShow<T>(
|
_i8.Future<T?>? clearStackAndShow<T>(
|
||||||
String? routeName, {
|
String? routeName, {
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
|
|
@ -319,11 +343,11 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? clearStackAndShowView<T>(
|
_i8.Future<T?>? clearStackAndShowView<T>(
|
||||||
_i5.Widget? view, {
|
_i7.Widget? view, {
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
}) =>
|
}) =>
|
||||||
|
|
@ -337,10 +361,10 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? clearTillFirstAndShow<T>(
|
_i8.Future<T?>? clearTillFirstAndShow<T>(
|
||||||
String? routeName, {
|
String? routeName, {
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
|
|
@ -359,11 +383,11 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? clearTillFirstAndShowView<T>(
|
_i8.Future<T?>? clearTillFirstAndShowView<T>(
|
||||||
_i5.Widget? view, {
|
_i7.Widget? view, {
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
}) =>
|
}) =>
|
||||||
|
|
@ -377,12 +401,12 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<T?>? pushNamedAndRemoveUntil<T>(
|
_i8.Future<T?>? pushNamedAndRemoveUntil<T>(
|
||||||
String? routeName, {
|
String? routeName, {
|
||||||
_i5.RoutePredicate? predicate,
|
_i7.RoutePredicate? predicate,
|
||||||
dynamic arguments,
|
dynamic arguments,
|
||||||
int? id,
|
int? id,
|
||||||
}) =>
|
}) =>
|
||||||
|
|
@ -397,16 +421,16 @@ class MockNavigationService extends _i1.Mock implements _i3.NavigationService {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValueForMissingStub: null,
|
returnValueForMissingStub: null,
|
||||||
) as _i6.Future<T?>?);
|
) as _i8.Future<T?>?);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A class which mocks [BottomSheetService].
|
/// A class which mocks [BottomSheetService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockBottomSheetService extends _i1.Mock
|
class MockBottomSheetService extends _i1.Mock
|
||||||
implements _i3.BottomSheetService {
|
implements _i5.BottomSheetService {
|
||||||
@override
|
@override
|
||||||
void setCustomSheetBuilders(Map<dynamic, _i3.SheetBuilder>? builders) =>
|
void setCustomSheetBuilders(Map<dynamic, _i5.SheetBuilder>? builders) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#setCustomSheetBuilders,
|
#setCustomSheetBuilders,
|
||||||
|
|
@ -416,7 +440,7 @@ class MockBottomSheetService extends _i1.Mock
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<_i3.SheetResponse<dynamic>?> showBottomSheet({
|
_i8.Future<_i5.SheetResponse<dynamic>?> showBottomSheet({
|
||||||
required String? title,
|
required String? title,
|
||||||
String? description,
|
String? description,
|
||||||
String? confirmButtonTitle = r'Ok',
|
String? confirmButtonTitle = r'Ok',
|
||||||
|
|
@ -449,13 +473,13 @@ class MockBottomSheetService extends _i1.Mock
|
||||||
#elevation: elevation,
|
#elevation: elevation,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<_i3.SheetResponse<dynamic>?>.value(),
|
returnValue: _i8.Future<_i5.SheetResponse<dynamic>?>.value(),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<_i3.SheetResponse<dynamic>?>.value(),
|
_i8.Future<_i5.SheetResponse<dynamic>?>.value(),
|
||||||
) as _i6.Future<_i3.SheetResponse<dynamic>?>);
|
) as _i8.Future<_i5.SheetResponse<dynamic>?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<_i3.SheetResponse<T>?> showCustomSheet<T, R>({
|
_i8.Future<_i5.SheetResponse<T>?> showCustomSheet<T, R>({
|
||||||
dynamic variant,
|
dynamic variant,
|
||||||
String? title,
|
String? title,
|
||||||
String? description,
|
String? description,
|
||||||
|
|
@ -468,7 +492,7 @@ class MockBottomSheetService extends _i1.Mock
|
||||||
bool? showIconInAdditionalButton = false,
|
bool? showIconInAdditionalButton = false,
|
||||||
String? additionalButtonTitle,
|
String? additionalButtonTitle,
|
||||||
bool? takesInput = false,
|
bool? takesInput = false,
|
||||||
_i7.Color? barrierColor = const _i7.Color(2315255808),
|
_i9.Color? barrierColor = const _i9.Color(2315255808),
|
||||||
double? elevation = 1.0,
|
double? elevation = 1.0,
|
||||||
bool? barrierDismissible = true,
|
bool? barrierDismissible = true,
|
||||||
bool? isScrollControlled = false,
|
bool? isScrollControlled = false,
|
||||||
|
|
@ -512,12 +536,12 @@ class MockBottomSheetService extends _i1.Mock
|
||||||
#useRootNavigator: useRootNavigator,
|
#useRootNavigator: useRootNavigator,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<_i3.SheetResponse<T>?>.value(),
|
returnValue: _i8.Future<_i5.SheetResponse<T>?>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<_i3.SheetResponse<T>?>.value(),
|
returnValueForMissingStub: _i8.Future<_i5.SheetResponse<T>?>.value(),
|
||||||
) as _i6.Future<_i3.SheetResponse<T>?>);
|
) as _i8.Future<_i5.SheetResponse<T>?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void completeSheet(_i3.SheetResponse<dynamic>? response) =>
|
void completeSheet(_i5.SheetResponse<dynamic>? response) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#completeSheet,
|
#completeSheet,
|
||||||
|
|
@ -530,10 +554,10 @@ class MockBottomSheetService extends _i1.Mock
|
||||||
/// A class which mocks [DialogService].
|
/// A class which mocks [DialogService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
class MockDialogService extends _i1.Mock implements _i5.DialogService {
|
||||||
@override
|
@override
|
||||||
void registerCustomDialogBuilders(
|
void registerCustomDialogBuilders(
|
||||||
Map<dynamic, _i3.DialogBuilder>? builders) =>
|
Map<dynamic, _i5.DialogBuilder>? builders) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#registerCustomDialogBuilders,
|
#registerCustomDialogBuilders,
|
||||||
|
|
@ -545,10 +569,10 @@ class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
||||||
@override
|
@override
|
||||||
void registerCustomDialogBuilder({
|
void registerCustomDialogBuilder({
|
||||||
required dynamic variant,
|
required dynamic variant,
|
||||||
required _i5.Widget Function(
|
required _i7.Widget Function(
|
||||||
_i5.BuildContext,
|
_i7.BuildContext,
|
||||||
_i3.DialogRequest<dynamic>,
|
_i5.DialogRequest<dynamic>,
|
||||||
dynamic Function(_i3.DialogResponse<dynamic>),
|
dynamic Function(_i5.DialogResponse<dynamic>),
|
||||||
)? builder,
|
)? builder,
|
||||||
}) =>
|
}) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
|
|
@ -564,17 +588,17 @@ class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<_i3.DialogResponse<dynamic>?> showDialog({
|
_i8.Future<_i5.DialogResponse<dynamic>?> showDialog({
|
||||||
String? title,
|
String? title,
|
||||||
String? description,
|
String? description,
|
||||||
String? cancelTitle,
|
String? cancelTitle,
|
||||||
_i7.Color? cancelTitleColor,
|
_i9.Color? cancelTitleColor,
|
||||||
String? buttonTitle = r'Ok',
|
String? buttonTitle = r'Ok',
|
||||||
_i7.Color? buttonTitleColor,
|
_i9.Color? buttonTitleColor,
|
||||||
bool? barrierDismissible = false,
|
bool? barrierDismissible = false,
|
||||||
_i5.RouteSettings? routeSettings,
|
_i7.RouteSettings? routeSettings,
|
||||||
_i5.GlobalKey<_i5.NavigatorState>? navigatorKey,
|
_i7.GlobalKey<_i7.NavigatorState>? navigatorKey,
|
||||||
_i3.DialogPlatform? dialogPlatform,
|
_i5.DialogPlatform? dialogPlatform,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -593,13 +617,13 @@ class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
||||||
#dialogPlatform: dialogPlatform,
|
#dialogPlatform: dialogPlatform,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<_i3.DialogResponse<dynamic>?>.value(),
|
returnValue: _i8.Future<_i5.DialogResponse<dynamic>?>.value(),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<_i3.DialogResponse<dynamic>?>.value(),
|
_i8.Future<_i5.DialogResponse<dynamic>?>.value(),
|
||||||
) as _i6.Future<_i3.DialogResponse<dynamic>?>);
|
) as _i8.Future<_i5.DialogResponse<dynamic>?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<_i3.DialogResponse<T>?> showCustomDialog<T, R>({
|
_i8.Future<_i5.DialogResponse<T>?> showCustomDialog<T, R>({
|
||||||
dynamic variant,
|
dynamic variant,
|
||||||
String? title,
|
String? title,
|
||||||
String? description,
|
String? description,
|
||||||
|
|
@ -612,13 +636,13 @@ class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
||||||
bool? showIconInAdditionalButton = false,
|
bool? showIconInAdditionalButton = false,
|
||||||
String? additionalButtonTitle,
|
String? additionalButtonTitle,
|
||||||
bool? takesInput = false,
|
bool? takesInput = false,
|
||||||
_i7.Color? barrierColor = const _i7.Color(2315255808),
|
_i9.Color? barrierColor = const _i9.Color(2315255808),
|
||||||
bool? barrierDismissible = false,
|
bool? barrierDismissible = false,
|
||||||
String? barrierLabel = r'',
|
String? barrierLabel = r'',
|
||||||
bool? useSafeArea = true,
|
bool? useSafeArea = true,
|
||||||
_i5.RouteSettings? routeSettings,
|
_i7.RouteSettings? routeSettings,
|
||||||
_i5.GlobalKey<_i5.NavigatorState>? navigatorKey,
|
_i7.GlobalKey<_i7.NavigatorState>? navigatorKey,
|
||||||
_i5.RouteTransitionsBuilder? transitionBuilder,
|
_i7.RouteTransitionsBuilder? transitionBuilder,
|
||||||
dynamic customData,
|
dynamic customData,
|
||||||
R? data,
|
R? data,
|
||||||
}) =>
|
}) =>
|
||||||
|
|
@ -650,21 +674,21 @@ class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
||||||
#data: data,
|
#data: data,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<_i3.DialogResponse<T>?>.value(),
|
returnValue: _i8.Future<_i5.DialogResponse<T>?>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<_i3.DialogResponse<T>?>.value(),
|
returnValueForMissingStub: _i8.Future<_i5.DialogResponse<T>?>.value(),
|
||||||
) as _i6.Future<_i3.DialogResponse<T>?>);
|
) as _i8.Future<_i5.DialogResponse<T>?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<_i3.DialogResponse<dynamic>?> showConfirmationDialog({
|
_i8.Future<_i5.DialogResponse<dynamic>?> showConfirmationDialog({
|
||||||
String? title,
|
String? title,
|
||||||
String? description,
|
String? description,
|
||||||
String? cancelTitle = r'Cancel',
|
String? cancelTitle = r'Cancel',
|
||||||
_i7.Color? cancelTitleColor,
|
_i9.Color? cancelTitleColor,
|
||||||
String? confirmationTitle = r'Ok',
|
String? confirmationTitle = r'Ok',
|
||||||
_i7.Color? confirmationTitleColor,
|
_i9.Color? confirmationTitleColor,
|
||||||
bool? barrierDismissible = false,
|
bool? barrierDismissible = false,
|
||||||
_i5.RouteSettings? routeSettings,
|
_i7.RouteSettings? routeSettings,
|
||||||
_i3.DialogPlatform? dialogPlatform,
|
_i5.DialogPlatform? dialogPlatform,
|
||||||
}) =>
|
}) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
|
|
@ -682,13 +706,13 @@ class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
||||||
#dialogPlatform: dialogPlatform,
|
#dialogPlatform: dialogPlatform,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<_i3.DialogResponse<dynamic>?>.value(),
|
returnValue: _i8.Future<_i5.DialogResponse<dynamic>?>.value(),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<_i3.DialogResponse<dynamic>?>.value(),
|
_i8.Future<_i5.DialogResponse<dynamic>?>.value(),
|
||||||
) as _i6.Future<_i3.DialogResponse<dynamic>?>);
|
) as _i8.Future<_i5.DialogResponse<dynamic>?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void completeDialog(_i3.DialogResponse<dynamic>? response) =>
|
void completeDialog(_i5.DialogResponse<dynamic>? response) =>
|
||||||
super.noSuchMethod(
|
super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#completeDialog,
|
#completeDialog,
|
||||||
|
|
@ -702,35 +726,113 @@ class MockDialogService extends _i1.Mock implements _i3.DialogService {
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockAuthenticationService extends _i1.Mock
|
class MockAuthenticationService extends _i1.Mock
|
||||||
implements _i8.AuthenticationService {
|
implements _i10.AuthenticationService {
|
||||||
@override
|
@override
|
||||||
_i6.Future<bool> userLoggedIn() => (super.noSuchMethod(
|
_i8.Future<bool> userLoggedIn() => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#userLoggedIn,
|
#userLoggedIn,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<bool>.value(false),
|
returnValue: _i8.Future<bool>.value(false),
|
||||||
returnValueForMissingStub: _i6.Future<bool>.value(false),
|
returnValueForMissingStub: _i8.Future<bool>.value(false),
|
||||||
) as _i6.Future<bool>);
|
) as _i8.Future<bool>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<void> saveUserData(Map<String, dynamic>? data) =>
|
_i8.Future<String?> getAccessToken() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#getAccessToken,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<String?>.value(),
|
||||||
|
returnValueForMissingStub: _i8.Future<String?>.value(),
|
||||||
|
) as _i8.Future<String?>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<String?> getRefreshToken() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#getRefreshToken,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<String?>.value(),
|
||||||
|
returnValueForMissingStub: _i8.Future<String?>.value(),
|
||||||
|
) as _i8.Future<String?>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<int?> getUserId() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#getUserId,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<int?>.value(),
|
||||||
|
returnValueForMissingStub: _i8.Future<int?>.value(),
|
||||||
|
) as _i8.Future<int?>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<void> saveTokens({
|
||||||
|
required String? access,
|
||||||
|
required String? refresh,
|
||||||
|
}) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#saveTokens,
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
#access: access,
|
||||||
|
#refresh: refresh,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<void>.value(),
|
||||||
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
|
) as _i8.Future<void>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<void> saveUserData(Map<String, dynamic>? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#saveUserData,
|
#saveUserData,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<void>.value(),
|
returnValue: _i8.Future<void>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<void>.value(),
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
) as _i6.Future<void>);
|
) as _i8.Future<void>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<_i2.UserModel> getUser() => (super.noSuchMethod(
|
_i8.Future<void> saveProfileCompleted(bool? value) => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#saveProfileCompleted,
|
||||||
|
[value],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<void>.value(),
|
||||||
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
|
) as _i8.Future<void>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<bool> isFirstTimeInstall() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#isFirstTimeInstall,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<bool>.value(false),
|
||||||
|
returnValueForMissingStub: _i8.Future<bool>.value(false),
|
||||||
|
) as _i8.Future<bool>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<void> setFirstTimeInstall(bool? value) => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#setFirstTimeInstall,
|
||||||
|
[value],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<void>.value(),
|
||||||
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
|
) as _i8.Future<void>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<_i2.UserModel> getUser() => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getUser,
|
#getUser,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<_i2.UserModel>.value(_FakeUserModel_0(
|
returnValue: _i8.Future<_i2.UserModel>.value(_FakeUserModel_0(
|
||||||
this,
|
this,
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getUser,
|
#getUser,
|
||||||
|
|
@ -738,143 +840,175 @@ class MockAuthenticationService extends _i1.Mock
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<_i2.UserModel>.value(_FakeUserModel_0(
|
_i8.Future<_i2.UserModel>.value(_FakeUserModel_0(
|
||||||
this,
|
this,
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getUser,
|
#getUser,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
) as _i6.Future<_i2.UserModel>);
|
) as _i8.Future<_i2.UserModel>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<void> logOut() => (super.noSuchMethod(
|
_i8.Future<void> logOut() => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#logOut,
|
#logOut,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<void>.value(),
|
returnValue: _i8.Future<void>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<void>.value(),
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
) as _i6.Future<void>);
|
) as _i8.Future<void>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A class which mocks [ApiService].
|
/// A class which mocks [ApiService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockApiService extends _i1.Mock implements _i9.ApiService {
|
class MockApiService extends _i1.Mock implements _i11.ApiService {
|
||||||
@override
|
@override
|
||||||
_i6.Future<Map<String, dynamic>> register(Map<String, dynamic>? data) =>
|
_i8.Future<Map<String, dynamic>> register(Map<String, dynamic>? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#register,
|
#register,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
) as _i6.Future<Map<String, dynamic>>);
|
) as _i8.Future<Map<String, dynamic>>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<Map<String, dynamic>> login(Map<String, dynamic>? data) =>
|
_i8.Future<Map<String, dynamic>> login(Map<String, dynamic>? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#login,
|
#login,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
) as _i6.Future<Map<String, dynamic>>);
|
) as _i8.Future<Map<String, dynamic>>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<Map<String, dynamic>> verifyOtp(Map<String, dynamic>? data) =>
|
_i8.Future<Map<String, dynamic>> verifyOtp(Map<String, dynamic>? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#verifyOtp,
|
#verifyOtp,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
) as _i6.Future<Map<String, dynamic>>);
|
) as _i8.Future<Map<String, dynamic>>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<Map<String, dynamic>> resendOtp(Map<String, dynamic>? data) =>
|
_i8.Future<Map<String, dynamic>> resendOtp(Map<String, dynamic>? data) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#resendOtp,
|
#resendOtp,
|
||||||
[data],
|
[data],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
) as _i6.Future<Map<String, dynamic>>);
|
) as _i8.Future<Map<String, dynamic>>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<Map<String, dynamic>> getProfileStatus(_i2.UserModel? user) =>
|
_i8.Future<Map<String, dynamic>> getProfileStatus(_i2.UserModel? user) =>
|
||||||
(super.noSuchMethod(
|
(super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getProfileStatus,
|
#getProfileStatus,
|
||||||
[user],
|
[user],
|
||||||
),
|
),
|
||||||
returnValue:
|
returnValue:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
returnValueForMissingStub:
|
returnValueForMissingStub:
|
||||||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
) as _i6.Future<Map<String, dynamic>>);
|
) as _i8.Future<Map<String, dynamic>>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<Map<String, dynamic>> updateProfile({
|
||||||
|
required _i2.UserModel? user,
|
||||||
|
required Map<String, dynamic>? data,
|
||||||
|
}) =>
|
||||||
|
(super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#updateProfile,
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
#user: user,
|
||||||
|
#data: data,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
returnValue:
|
||||||
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
|
returnValueForMissingStub:
|
||||||
|
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||||
|
) as _i8.Future<Map<String, dynamic>>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<List<_i12.Assessment>> getAssessments() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#getAssessments,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue:
|
||||||
|
_i8.Future<List<_i12.Assessment>>.value(<_i12.Assessment>[]),
|
||||||
|
returnValueForMissingStub:
|
||||||
|
_i8.Future<List<_i12.Assessment>>.value(<_i12.Assessment>[]),
|
||||||
|
) as _i8.Future<List<_i12.Assessment>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A class which mocks [SecureStorageService].
|
/// A class which mocks [SecureStorageService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockSecureStorageService extends _i1.Mock
|
class MockSecureStorageService extends _i1.Mock
|
||||||
implements _i10.SecureStorageService {
|
implements _i4.SecureStorageService {
|
||||||
@override
|
@override
|
||||||
_i6.Future<void> clear() => (super.noSuchMethod(
|
_i8.Future<void> clear() => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#clear,
|
#clear,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<void>.value(),
|
returnValue: _i8.Future<void>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<void>.value(),
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
) as _i6.Future<void>);
|
) as _i8.Future<void>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<bool?> getBool(String? key) => (super.noSuchMethod(
|
_i8.Future<bool?> getBool(String? key) => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getBool,
|
#getBool,
|
||||||
[key],
|
[key],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<bool?>.value(),
|
returnValue: _i8.Future<bool?>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<bool?>.value(),
|
returnValueForMissingStub: _i8.Future<bool?>.value(),
|
||||||
) as _i6.Future<bool?>);
|
) as _i8.Future<bool?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<String?> getString(String? key) => (super.noSuchMethod(
|
_i8.Future<String?> getString(String? key) => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getString,
|
#getString,
|
||||||
[key],
|
[key],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<String?>.value(),
|
returnValue: _i8.Future<String?>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<String?>.value(),
|
returnValueForMissingStub: _i8.Future<String?>.value(),
|
||||||
) as _i6.Future<String?>);
|
) as _i8.Future<String?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<int?> getInt(String? key) => (super.noSuchMethod(
|
_i8.Future<int?> getInt(String? key) => (super.noSuchMethod(
|
||||||
Invocation.method(
|
Invocation.method(
|
||||||
#getInt,
|
#getInt,
|
||||||
[key],
|
[key],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<int?>.value(),
|
returnValue: _i8.Future<int?>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<int?>.value(),
|
returnValueForMissingStub: _i8.Future<int?>.value(),
|
||||||
) as _i6.Future<int?>);
|
) as _i8.Future<int?>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<void> setString(
|
_i8.Future<void> setString(
|
||||||
String? key,
|
String? key,
|
||||||
String? value,
|
String? value,
|
||||||
) =>
|
) =>
|
||||||
|
|
@ -886,12 +1020,12 @@ class MockSecureStorageService extends _i1.Mock
|
||||||
value,
|
value,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<void>.value(),
|
returnValue: _i8.Future<void>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<void>.value(),
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
) as _i6.Future<void>);
|
) as _i8.Future<void>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<void> setInt(
|
_i8.Future<void> setInt(
|
||||||
String? key,
|
String? key,
|
||||||
int? value,
|
int? value,
|
||||||
) =>
|
) =>
|
||||||
|
|
@ -903,12 +1037,12 @@ class MockSecureStorageService extends _i1.Mock
|
||||||
value,
|
value,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<void>.value(),
|
returnValue: _i8.Future<void>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<void>.value(),
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
) as _i6.Future<void>);
|
) as _i8.Future<void>);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_i6.Future<void> setBool(
|
_i8.Future<void> setBool(
|
||||||
String? key,
|
String? key,
|
||||||
bool? value,
|
bool? value,
|
||||||
) =>
|
) =>
|
||||||
|
|
@ -920,12 +1054,101 @@ class MockSecureStorageService extends _i1.Mock
|
||||||
value,
|
value,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
returnValue: _i6.Future<void>.value(),
|
returnValue: _i8.Future<void>.value(),
|
||||||
returnValueForMissingStub: _i6.Future<void>.value(),
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
) as _i6.Future<void>);
|
) as _i8.Future<void>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A class which mocks [DioService].
|
/// A class which mocks [DioService].
|
||||||
///
|
///
|
||||||
/// See the documentation for Mockito's code generation for more information.
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
class MockDioService extends _i1.Mock implements _i11.DioService {}
|
class MockDioService extends _i1.Mock implements _i13.DioService {
|
||||||
|
@override
|
||||||
|
_i3.Dio get dio => (super.noSuchMethod(
|
||||||
|
Invocation.getter(#dio),
|
||||||
|
returnValue: _FakeDio_1(
|
||||||
|
this,
|
||||||
|
Invocation.getter(#dio),
|
||||||
|
),
|
||||||
|
returnValueForMissingStub: _FakeDio_1(
|
||||||
|
this,
|
||||||
|
Invocation.getter(#dio),
|
||||||
|
),
|
||||||
|
) as _i3.Dio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A class which mocks [StatusCheckerService].
|
||||||
|
///
|
||||||
|
/// See the documentation for Mockito's code generation for more information.
|
||||||
|
class MockStatusCheckerService extends _i1.Mock
|
||||||
|
implements _i14.StatusCheckerService {
|
||||||
|
@override
|
||||||
|
_i4.SecureStorageService get storage => (super.noSuchMethod(
|
||||||
|
Invocation.getter(#storage),
|
||||||
|
returnValue: _FakeSecureStorageService_2(
|
||||||
|
this,
|
||||||
|
Invocation.getter(#storage),
|
||||||
|
),
|
||||||
|
returnValueForMissingStub: _FakeSecureStorageService_2(
|
||||||
|
this,
|
||||||
|
Invocation.getter(#storage),
|
||||||
|
),
|
||||||
|
) as _i4.SecureStorageService);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get previousConnection => (super.noSuchMethod(
|
||||||
|
Invocation.getter(#previousConnection),
|
||||||
|
returnValue: false,
|
||||||
|
returnValueForMissingStub: false,
|
||||||
|
) as bool);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<int> getBatteryLevel() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#getBatteryLevel,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<int>.value(0),
|
||||||
|
returnValueForMissingStub: _i8.Future<int>.value(0),
|
||||||
|
) as _i8.Future<int>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<bool> userAuthenticated() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#userAuthenticated,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<bool>.value(false),
|
||||||
|
returnValueForMissingStub: _i8.Future<bool>.value(false),
|
||||||
|
) as _i8.Future<bool>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<bool> checkConnection() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#checkConnection,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<bool>.value(false),
|
||||||
|
returnValueForMissingStub: _i8.Future<bool>.value(false),
|
||||||
|
) as _i8.Future<bool>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<int> getAvailableStorage() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#getAvailableStorage,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<int>.value(0),
|
||||||
|
returnValueForMissingStub: _i8.Future<int>.value(0),
|
||||||
|
) as _i8.Future<int>);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_i8.Future<void> checkAndUpdate() => (super.noSuchMethod(
|
||||||
|
Invocation.method(
|
||||||
|
#checkAndUpdate,
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
returnValue: _i8.Future<void>.value(),
|
||||||
|
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||||
|
) as _i8.Future<void>);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
|
|
||||||
|
import '../helpers/test_helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('StatusCheckerServiceTest -', () {
|
||||||
|
setUp(() => registerServices());
|
||||||
|
tearDown(() => locator.reset());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
|
|
||||||
|
import '../helpers/test_helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('AssessmentViewModel Tests -', () {
|
||||||
|
setUp(() => registerServices());
|
||||||
|
tearDown(() => locator.reset());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:yimaru_app/app/app.locator.dart';
|
||||||
|
|
||||||
|
import '../helpers/test_helpers.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('WelcomeViewModel Tests -', () {
|
||||||
|
setUp(() => registerServices());
|
||||||
|
tearDown(() => locator.reset());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -6,9 +6,15 @@
|
||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <battery_plus/battery_plus_windows_plugin.h>
|
||||||
|
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
|
||||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
BatteryPlusWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin"));
|
||||||
|
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
|
||||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
battery_plus
|
||||||
|
connectivity_plus
|
||||||
flutter_secure_storage_windows
|
flutter_secure_storage_windows
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user