From 1713a8957a147f081b4213a84d20dd803f6f4198 Mon Sep 17 00:00:00 2001 From: BisratHailu Date: Wed, 21 Jan 2026 09:53:14 +0300 Subject: [PATCH] fix(auth): Fix token refresh --- .../android/app/src/main/AndroidManifest.xml | 3 +- .../reports/problems/problems-report.html | 663 ++++++++++++++++++ StudioProjects/yimaru_app/lib/app/app.dart | 6 + .../yimaru_app/lib/app/app.locator.dart | 2 + .../yimaru_app/lib/app/app.router.dart | 211 +++++- StudioProjects/yimaru_app/lib/main.dart | 2 +- .../yimaru_app/lib/models/assessment.dart | 20 + .../yimaru_app/lib/models/assessment.g.dart | 22 + .../yimaru_app/lib/models/option.dart | 17 + .../yimaru_app/lib/models/option.g.dart | 17 + .../yimaru_app/lib/models/question.dart | 36 + .../yimaru_app/lib/models/question.g.dart | 27 + .../yimaru_app/lib/models/user_model.dart | 8 +- .../yimaru_app/lib/models/user_model.g.dart | 2 + .../yimaru_app/lib/services/api_service.dart | 81 ++- .../lib/services/authentication_service.dart | 37 +- .../yimaru_app/lib/services/dio_service.dart | 180 ++++- .../lib/services/status_checker_service.dart | 88 +++ .../lib/ui/common/app_constants.dart | 8 +- .../yimaru_app/lib/ui/common/enmus.dart | 3 + .../lib/ui/common/helper_functions.dart | 17 + .../yimaru_app/lib/ui/common/ui_helpers.dart | 6 +- .../ui/views/assessment/assessment_view.dart | 71 ++ .../assessment/assessment_viewmodel.dart | 252 +++++++ .../assessment_completion_screen.dart | 28 +- .../screens}/assessment_failure_screen.dart | 47 +- .../screens/assessment_form_screen.dart | 169 +++++ .../screens}/assessment_intro_screen.dart | 52 +- .../screens/assessment_loading_screen.dart | 37 + .../screens}/assessment_result_screen.dart | 55 +- .../screens}/result_analysis_screen.dart | 31 +- .../screens}/retake_assessment_screen.dart | 45 +- .../screens}/start_lesson_screen.dart | 55 +- .../lib/ui/views/home/home_view.dart | 27 +- .../lib/ui/views/home/home_viewmodel.dart | 30 +- .../views/login/screens/login_otp_screen.dart | 2 - .../screens/login_with_email_screen.dart | 13 +- .../login_with_phone_number_screen.dart | 17 +- .../ui/views/onboarding/onboarding_view.dart | 105 +-- .../onboarding/onboarding_view.form.dart | 55 +- .../onboarding/onboarding_viewmodel.dart | 275 ++++---- .../{forms => }/age_group_form_screen.dart | 24 +- .../first_assessment_form_screen.dart | 128 ---- .../second_assessment_form_screen.dart | 113 --- ..._screen.dart => birthday_form_screen.dart} | 71 +- .../{forms => }/challenge_form_screen.dart | 34 +- .../country_region_form_screen.dart | 41 +- .../educational_background_form_screen.dart | 25 +- .../{forms => }/full_name_form_screen.dart | 34 +- ...rm_screen.dart => gender_form_screen.dart} | 56 +- ...en.dart => language_goal_form_screen.dart} | 87 ++- .../onboarding/screens/language_selector.dart | 128 ---- .../learning_goal_form_screen.dart | 34 +- .../{forms => }/occupation_form_screen.dart | 34 +- .../{forms => }/topic_form_screen.dart | 35 +- .../profile_detail/profile_detail_view.dart | 10 +- .../ui/views/register/register_viewmodel.dart | 25 +- .../screens/create_password_screen.dart | 44 +- .../screens/register_with_email_screen.dart | 6 +- .../register_with_phone_number_screen.dart | 14 +- .../screens/registration_otp_screen.dart | 19 +- .../lib/ui/views/startup/startup_view.dart | 5 +- .../ui/views/startup/startup_viewmodel.dart | 14 +- .../screens}/first_welcome_screen.dart | 19 +- .../screens}/second_welcome_screen.dart | 19 +- .../screens}/third_welcome_screen.dart | 33 +- .../lib/ui/views/welcome/welcome_view.dart | 36 + .../ui/views/welcome/welcome_viewmodel.dart | 35 + .../lib/ui/widgets/birthday_selector.dart | 68 +- .../custom_circular_progress_indicator.dart | 2 - .../ui/widgets/custom_small_radio_button.dart | 7 +- .../lib/ui/widgets/large_app_bar.dart | 10 +- .../Flutter/GeneratedPluginRegistrant.swift | 4 + StudioProjects/yimaru_app/pubspec.lock | 80 +++ StudioProjects/yimaru_app/pubspec.yaml | 4 + .../yimaru_app/test/helpers/test_helpers.dart | 10 + .../test/helpers/test_helpers.mocks.dart | 557 ++++++++++----- .../services/status_checker_service_test.dart | 11 + .../viewmodels/assessment_viewmodel_test.dart | 11 + .../viewmodels/welcome_viewmodel_test.dart | 11 + .../flutter/generated_plugin_registrant.cc | 6 + .../windows/flutter/generated_plugins.cmake | 2 + 82 files changed, 3357 insertions(+), 1371 deletions(-) create mode 100644 StudioProjects/yimaru_app/android/build/reports/problems/problems-report.html create mode 100644 StudioProjects/yimaru_app/lib/models/assessment.dart create mode 100644 StudioProjects/yimaru_app/lib/models/assessment.g.dart create mode 100644 StudioProjects/yimaru_app/lib/models/option.dart create mode 100644 StudioProjects/yimaru_app/lib/models/option.g.dart create mode 100644 StudioProjects/yimaru_app/lib/models/question.dart create mode 100644 StudioProjects/yimaru_app/lib/models/question.g.dart create mode 100644 StudioProjects/yimaru_app/lib/services/status_checker_service.dart create mode 100644 StudioProjects/yimaru_app/lib/ui/common/helper_functions.dart create mode 100644 StudioProjects/yimaru_app/lib/ui/views/assessment/assessment_view.dart create mode 100644 StudioProjects/yimaru_app/lib/ui/views/assessment/assessment_viewmodel.dart rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/assessment => assessment/screens}/assessment_completion_screen.dart (73%) rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/assessment => assessment/screens}/assessment_failure_screen.dart (69%) create mode 100644 StudioProjects/yimaru_app/lib/ui/views/assessment/screens/assessment_form_screen.dart rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/assessment => assessment/screens}/assessment_intro_screen.dart (65%) create mode 100644 StudioProjects/yimaru_app/lib/ui/views/assessment/screens/assessment_loading_screen.dart rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/assessment => assessment/screens}/assessment_result_screen.dart (67%) rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/assessment => assessment/screens}/result_analysis_screen.dart (67%) rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/assessment => assessment/screens}/retake_assessment_screen.dart (70%) rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/assessment => assessment/screens}/start_lesson_screen.dart (62%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/age_group_form_screen.dart (89%) delete mode 100644 StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/assessment/first_assessment_form_screen.dart delete mode 100644 StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/assessment/second_assessment_form_screen.dart rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{assessment/fourth_assessment_form_screen.dart => birthday_form_screen.dart} (63%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/challenge_form_screen.dart (89%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/country_region_form_screen.dart (82%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/educational_background_form_screen.dart (90%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/full_name_form_screen.dart (85%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{assessment/third_assessment_form_screen.dart => gender_form_screen.dart} (66%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms/learning_reason_form_screen.dart => language_goal_form_screen.dart} (68%) delete mode 100644 StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/language_selector.dart rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/learning_goal_form_screen.dart (86%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/occupation_form_screen.dart (86%) rename StudioProjects/yimaru_app/lib/ui/views/onboarding/screens/{forms => }/topic_form_screen.dart (89%) rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/welcome => welcome/screens}/first_welcome_screen.dart (77%) rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/welcome => welcome/screens}/second_welcome_screen.dart (77%) rename StudioProjects/yimaru_app/lib/ui/views/{onboarding/screens/welcome => welcome/screens}/third_welcome_screen.dart (68%) create mode 100644 StudioProjects/yimaru_app/lib/ui/views/welcome/welcome_view.dart create mode 100644 StudioProjects/yimaru_app/lib/ui/views/welcome/welcome_viewmodel.dart create mode 100644 StudioProjects/yimaru_app/test/services/status_checker_service_test.dart create mode 100644 StudioProjects/yimaru_app/test/viewmodels/assessment_viewmodel_test.dart create mode 100644 StudioProjects/yimaru_app/test/viewmodels/welcome_viewmodel_test.dart diff --git a/StudioProjects/yimaru_app/android/app/src/main/AndroidManifest.xml b/StudioProjects/yimaru_app/android/app/src/main/AndroidManifest.xml index cd0a3f9..a7e20a5 100644 --- a/StudioProjects/yimaru_app/android/app/src/main/AndroidManifest.xml +++ b/StudioProjects/yimaru_app/android/app/src/main/AndroidManifest.xml @@ -3,7 +3,8 @@ + android:icon="@mipmap/ic_launcher" + android:usesCleartextTraffic="true"> + + + + + + + + + + + + Gradle Configuration Cache + + + +
+ +
+ Loading... +
+ + + + + + diff --git a/StudioProjects/yimaru_app/lib/app/app.dart b/StudioProjects/yimaru_app/lib/app/app.dart index a8ba819..32e28cd 100644 --- a/StudioProjects/yimaru_app/lib/app/app.dart +++ b/StudioProjects/yimaru_app/lib/app/app.dart @@ -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/secure_storage_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 @StackedApp( @@ -50,6 +53,8 @@ import 'package:yimaru_app/services/dio_service.dart'; MaterialRoute(page: LearnView), MaterialRoute(page: LearnLevelView), MaterialRoute(page: LearnModuleView), + MaterialRoute(page: WelcomeView), + MaterialRoute(page: AssessmentView), // @stacked-route ], dependencies: [ @@ -60,6 +65,7 @@ import 'package:yimaru_app/services/dio_service.dart'; LazySingleton(classType: ApiService), LazySingleton(classType: SecureStorageService), LazySingleton(classType: DioService), + LazySingleton(classType: StatusCheckerService), // @stacked-service ], bottomsheets: [ diff --git a/StudioProjects/yimaru_app/lib/app/app.locator.dart b/StudioProjects/yimaru_app/lib/app/app.locator.dart index 471c929..4319ba3 100644 --- a/StudioProjects/yimaru_app/lib/app/app.locator.dart +++ b/StudioProjects/yimaru_app/lib/app/app.locator.dart @@ -15,6 +15,7 @@ import '../services/api_service.dart'; import '../services/authentication_service.dart'; import '../services/dio_service.dart'; import '../services/secure_storage_service.dart'; +import '../services/status_checker_service.dart'; final locator = StackedLocator.instance; @@ -34,4 +35,5 @@ Future setupLocator({ locator.registerLazySingleton(() => ApiService()); locator.registerLazySingleton(() => SecureStorageService()); locator.registerLazySingleton(() => DioService()); + locator.registerLazySingleton(() => StatusCheckerService()); } diff --git a/StudioProjects/yimaru_app/lib/app/app.router.dart b/StudioProjects/yimaru_app/lib/app/app.router.dart index f2872b4..0e07180 100644 --- a/StudioProjects/yimaru_app/lib/app/app.router.dart +++ b/StudioProjects/yimaru_app/lib/app/app.router.dart @@ -5,12 +5,13 @@ // ************************************************************************** // 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: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' 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' as _i13; 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; import 'package:yimaru_app/ui/views/terms_and_conditions/terms_and_conditions_view.dart' as _i16; +import 'package:yimaru_app/ui/views/welcome/welcome_view.dart' as _i22; class Routes { static const homeView = '/home-view'; @@ -79,6 +81,10 @@ class Routes { static const learnModuleView = '/learn-module-view'; + static const welcomeView = '/welcome-view'; + + static const assessmentView = '/assessment-view'; + static const all = { homeView, onboardingView, @@ -100,6 +106,8 @@ class Routes { learnView, learnLevelView, learnModuleView, + welcomeView, + assessmentView, }; } @@ -185,129 +193,154 @@ class StackedRouter extends _i1.RouterBase { Routes.learnModuleView, page: _i21.LearnModuleView, ), + _i1.RouteDef( + Routes.welcomeView, + page: _i22.WelcomeView, + ), + _i1.RouteDef( + Routes.assessmentView, + page: _i23.AssessmentView, + ), ]; final _pagesMap = { _i2.HomeView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i2.HomeView(), settings: data, ); }, _i3.OnboardingView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i3.OnboardingView(), settings: data, ); }, _i4.StartupView: (data) { - return _i22.MaterialPageRoute( - builder: (context) => const _i4.StartupView(), + final args = data.getArgs( + orElse: () => const StartupViewArguments(), + ); + return _i24.MaterialPageRoute( + builder: (context) => _i4.StartupView(key: args.key, label: args.label), settings: data, ); }, _i5.ProfileView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i5.ProfileView(), settings: data, ); }, _i6.ProfileDetailView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i6.ProfileDetailView(), settings: data, ); }, _i7.DownloadsView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i7.DownloadsView(), settings: data, ); }, _i8.ProgressView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i8.ProgressView(), settings: data, ); }, _i9.OngoingProgressView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i9.OngoingProgressView(), settings: data, ); }, _i10.AccountPrivacyView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i10.AccountPrivacyView(), settings: data, ); }, _i11.SupportView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i11.SupportView(), settings: data, ); }, _i12.TelegramSupportView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i12.TelegramSupportView(), settings: data, ); }, _i13.CallSupportView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i13.CallSupportView(), settings: data, ); }, _i14.LanguageView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i14.LanguageView(), settings: data, ); }, _i15.PrivacyPolicyView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i15.PrivacyPolicyView(), settings: data, ); }, _i16.TermsAndConditionsView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i16.TermsAndConditionsView(), settings: data, ); }, _i17.RegisterView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i17.RegisterView(), settings: data, ); }, _i18.LoginView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i18.LoginView(), settings: data, ); }, _i19.LearnView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i19.LearnView(), settings: data, ); }, _i20.LearnLevelView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i20.LearnLevelView(), settings: data, ); }, _i21.LearnModuleView: (data) { - return _i22.MaterialPageRoute( + return _i24.MaterialPageRoute( builder: (context) => const _i21.LearnModuleView(), settings: data, ); }, + _i22.WelcomeView: (data) { + return _i24.MaterialPageRoute( + builder: (context) => const _i22.WelcomeView(), + settings: data, + ); + }, + _i23.AssessmentView: (data) { + final args = data.getArgs(nullOk: false); + return _i24.MaterialPageRoute( + builder: (context) => + _i23.AssessmentView(key: args.key, data: args.data), + settings: data, + ); + }, }; @override @@ -317,7 +350,61 @@ class StackedRouter extends _i1.RouterBase { Map 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 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 navigateToHomeView([ int? routerId, bool preventDuplicates = true, @@ -346,14 +433,17 @@ extension NavigatorStateExtension on _i23.NavigationService { transition: transition); } - Future navigateToStartupView([ + Future navigateToStartupView({ + _i24.Key? key, + String label = 'Loading', int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return navigateTo(Routes.startupView, + arguments: StartupViewArguments(key: key, label: label), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -598,6 +688,37 @@ extension NavigatorStateExtension on _i23.NavigationService { transition: transition); } + Future navigateToWelcomeView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return navigateTo(Routes.welcomeView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future navigateToAssessmentView({ + _i24.Key? key, + required Map data, + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return navigateTo(Routes.assessmentView, + arguments: AssessmentViewArguments(key: key, data: data), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + Future replaceWithHomeView([ int? routerId, bool preventDuplicates = true, @@ -626,14 +747,17 @@ extension NavigatorStateExtension on _i23.NavigationService { transition: transition); } - Future replaceWithStartupView([ + Future replaceWithStartupView({ + _i24.Key? key, + String label = 'Loading', int? routerId, bool preventDuplicates = true, Map? parameters, Widget Function(BuildContext, Animation, Animation, Widget)? transition, - ]) async { + }) async { return replaceWith(Routes.startupView, + arguments: StartupViewArguments(key: key, label: label), id: routerId, preventDuplicates: preventDuplicates, parameters: parameters, @@ -877,4 +1001,35 @@ extension NavigatorStateExtension on _i23.NavigationService { parameters: parameters, transition: transition); } + + Future replaceWithWelcomeView([ + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + ]) async { + return replaceWith(Routes.welcomeView, + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } + + Future replaceWithAssessmentView({ + _i24.Key? key, + required Map data, + int? routerId, + bool preventDuplicates = true, + Map? parameters, + Widget Function(BuildContext, Animation, Animation, Widget)? + transition, + }) async { + return replaceWith(Routes.assessmentView, + arguments: AssessmentViewArguments(key: key, data: data), + id: routerId, + preventDuplicates: preventDuplicates, + parameters: parameters, + transition: transition); + } } diff --git a/StudioProjects/yimaru_app/lib/main.dart b/StudioProjects/yimaru_app/lib/main.dart index ad534c7..c3f54fc 100644 --- a/StudioProjects/yimaru_app/lib/main.dart +++ b/StudioProjects/yimaru_app/lib/main.dart @@ -27,8 +27,8 @@ class MainApp extends StatelessWidget { Widget _buildMaterialApp() => MaterialApp( initialRoute: Routes.startupView, theme: ThemeData(fontFamily: 'Aeonik'), - onGenerateRoute: StackedRouter().onGenerateRoute, navigatorKey: StackedService.navigatorKey, + onGenerateRoute: StackedRouter().onGenerateRoute, navigatorObservers: [StackedService.routeObserver], ); } diff --git a/StudioProjects/yimaru_app/lib/models/assessment.dart b/StudioProjects/yimaru_app/lib/models/assessment.dart new file mode 100644 index 0000000..e1cc5e5 --- /dev/null +++ b/StudioProjects/yimaru_app/lib/models/assessment.dart @@ -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