diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 6561fcc..1dc40a9 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,4 +1,11 @@ + + + + + setupLocator({ locator.registerLazySingleton(() => SecureStorageService()); locator.registerLazySingleton(() => DioService()); locator.registerLazySingleton(() => StatusCheckerService()); + locator.registerLazySingleton(() => PermissionHandlerService()); locator.registerLazySingleton(() => ImagePickerService()); } diff --git a/lib/services/authentication_service.dart b/lib/services/authentication_service.dart index 369e1cc..d2e8693 100644 --- a/lib/services/authentication_service.dart +++ b/lib/services/authentication_service.dart @@ -1,10 +1,15 @@ +import 'package:stacked/stacked.dart'; import 'package:yimaru_app/app/app.locator.dart'; import 'package:yimaru_app/models/user_model.dart'; import 'package:yimaru_app/services/secure_storage_service.dart'; -class AuthenticationService { +class AuthenticationService with ListenableServiceMixin { final _secureService = locator(); + AuthenticationService() { + listenToReactiveValues([_user]); + } + UserModel? _user; UserModel? get user => _user; @@ -35,11 +40,12 @@ class AuthenticationService { Future saveUserName(Map data) async { await _secureService.setString('firstName', data['firstName']); _user = UserModel( - firstName: await _secureService.getString('firstName'), - userId: _user?.userId, - accessToken: _user?.accessToken, - refreshToken: _user?.refreshToken, - profileCompleted: _user?.profileCompleted); + userId: _user?.userId, + accessToken: _user?.accessToken, + refreshToken: _user?.refreshToken, + profileCompleted: _user?.profileCompleted, + firstName: await _secureService.getString('firstName'), + ); } Future saveBasicUserData(Map data) async { @@ -69,7 +75,19 @@ class AuthenticationService { profileCompleted: await _secureService.getBool('profileCompleted')); } - Future saveProfileImage() async {} + Future saveProfileImage(String image) async { + await _secureService.setString('profileImage', image); + _user = UserModel( + userId: _user?.userId, + firstName: _user?.firstName, + accessToken: _user?.accessToken, + refreshToken: _user?.refreshToken, + profileCompleted: _user?.profileCompleted, + profileImage: await _secureService.getString('profileImage'), + ); + + notifyListeners(); + } Future saveFullName(Map data) async { await _secureService.setBool('profileCompleted', true); diff --git a/lib/services/dio_service.dart b/lib/services/dio_service.dart index 3760b28..a78abb4 100644 --- a/lib/services/dio_service.dart +++ b/lib/services/dio_service.dart @@ -139,14 +139,6 @@ class DioService { final response = await _refreshDio.post( '$baseUrl/$kRefreshTokenUrl', data: data, - options: Options( - followRedirects: false, - validateStatus: (status) => true, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - }, - ), ); await _authenticationService.saveTokens( @@ -156,8 +148,9 @@ class DioService { return true; } catch (e) { - await _authenticationService.logOut(); - await _navigationService.replaceWithLoginView(); + print('Token refresh exception ${e.toString()}'); + // await _authenticationService.logOut(); + // await _navigationService.replaceWithLoginView(); return false; } } diff --git a/lib/services/image_picker_service.dart b/lib/services/image_picker_service.dart index 058cde1..0940be6 100644 --- a/lib/services/image_picker_service.dart +++ b/lib/services/image_picker_service.dart @@ -1 +1,56 @@ -class ImagePickerService {} +import 'package:image_picker/image_picker.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:yimaru_app/services/permission_handler_service.dart'; + +import '../app/app.locator.dart'; +import '../ui/common/ui_helpers.dart'; + +class ImagePickerService { + final _permissionHandler = locator(); + + final ImagePicker _picker = ImagePicker(); + + Future gallery() async { + try { + PermissionStatus status = + await _permissionHandler.requestPermission(Permission.mediaLibrary); + + if (status == PermissionStatus.granted) { + final XFile? pickedFile = await _picker.pickImage( + source: ImageSource.gallery, maxWidth: 600, maxHeight: 600); + + if (pickedFile == null) { + showErrorToast('Please select a picture'); + return null; + } else { + return pickedFile.path; + } + } + return null; + } catch (e) { + return null; + } + } + + Future camera() async { + try { + PermissionStatus status = + await _permissionHandler.requestPermission(Permission.camera); + + if (status == PermissionStatus.granted) { + final XFile? pickedFile = await _picker.pickImage( + source: ImageSource.camera, maxWidth: 600, maxHeight: 600); + + if (pickedFile == null) { + showErrorToast('Please take a picture'); + return null; + } else { + return pickedFile.path; + } + } + return null; + } catch (e) { + return null; + } + } +} diff --git a/lib/services/permission_handler_service.dart b/lib/services/permission_handler_service.dart new file mode 100644 index 0000000..4322c80 --- /dev/null +++ b/lib/services/permission_handler_service.dart @@ -0,0 +1,31 @@ +import 'package:permission_handler/permission_handler.dart'; + +import '../ui/common/ui_helpers.dart'; + +class PermissionHandlerService { + Future requestPermission( + Permission requestedPermission) async { + if (requestedPermission == Permission.camera) { + return await request(Permission.camera); + } + if (requestedPermission == Permission.storage) { + return await request(Permission.storage); + } + if (requestedPermission == Permission.mediaLibrary) { + return await request(Permission.mediaLibrary); + } + return PermissionStatus.denied; + } + + Future request(Permission permission) async { + if (await permission.isDenied) { + final PermissionStatus status = await permission.request(); + + if (status.isDenied || status.isPermanentlyDenied) { + showErrorToast('Permission Denied'); + } + return status; + } + return PermissionStatus.granted; + } +} diff --git a/lib/ui/common/enmus.dart b/lib/ui/common/enmus.dart index a289b0a..412c299 100644 --- a/lib/ui/common/enmus.dart +++ b/lib/ui/common/enmus.dart @@ -8,3 +8,6 @@ enum ProgressStatuses { pending, started, completed } // Levels enum ProficiencyLevels { a1, a2, b1, b2, none } + +// State object +enum StateObjects{profileImage} diff --git a/lib/ui/common/ui_helpers.dart b/lib/ui/common/ui_helpers.dart index 1e6b738..dcf3812 100644 --- a/lib/ui/common/ui_helpers.dart +++ b/lib/ui/common/ui_helpers.dart @@ -177,6 +177,12 @@ TextStyle style18P600 = const TextStyle( fontWeight: FontWeight.w600, ); +TextStyle style18W600 = const TextStyle( + fontSize: 18, + color: kcWhite, + fontWeight: FontWeight.w600, +); + TextStyle style12R700 = const TextStyle( fontSize: 12, color: Colors.red, diff --git a/lib/ui/views/assessment/assessment_viewmodel.dart b/lib/ui/views/assessment/assessment_viewmodel.dart index 5ca21d9..483cc9c 100644 --- a/lib/ui/views/assessment/assessment_viewmodel.dart +++ b/lib/ui/views/assessment/assessment_viewmodel.dart @@ -171,11 +171,6 @@ class AssessmentViewModel extends BaseViewModel { // Complete profile - Future saveProfileCompleted() async { - Map data = {'firstName': _userData['firstName']}; - await _authenticationService.saveFullName(data); - } - Future completeProfile() async => await runBusyFuture>(_completeProfile()); @@ -185,7 +180,6 @@ class AssessmentViewModel extends BaseViewModel { await _apiService.updateProfile(data: _userData, user: user); if (response['status'] == ResponseStatus.success) { showSuccessToast(response['message']); - await saveProfileCompleted(); await replaceWithHome(); } else { showErrorToast(response['message']); diff --git a/lib/ui/views/home/home_view.dart b/lib/ui/views/home/home_view.dart index ecf2308..ce8a1e9 100644 --- a/lib/ui/views/home/home_view.dart +++ b/lib/ui/views/home/home_view.dart @@ -27,9 +27,7 @@ class HomeView extends StackedView { _buildScaffoldWrapper(viewModel); Widget _buildScaffoldWrapper(HomeViewModel viewModel) => viewModel.isBusy - ? const StartupView( - label: 'Checking user info', - ) + ? const StartupView(label: 'Checking user info') : _buildScaffold(viewModel); Widget _buildScaffold(HomeViewModel viewModel) => Scaffold( diff --git a/lib/ui/views/home/home_viewmodel.dart b/lib/ui/views/home/home_viewmodel.dart index bd43cdb..d1ad455 100644 --- a/lib/ui/views/home/home_viewmodel.dart +++ b/lib/ui/views/home/home_viewmodel.dart @@ -93,18 +93,10 @@ class HomeViewModel extends BaseViewModel { return response; } - Future getProfileStatus() async { - Map response = - await runBusyFuture>(_getProfileStatus()); - if (response['status'] == ResponseStatus.success && !response['data']) { - await replaceWithOnboarding(); - } else if (response['status'] == ResponseStatus.success && - response['data']) { - await saveProfileStatus(response['data']); - } - } + Future getProfileStatus() async => + await runBusyFuture(_getProfileStatus()); - Future> _getProfileStatus() async { + Future _getProfileStatus() async { Map response = {}; UserModel? user = await _authenticationService.getUser(); @@ -118,6 +110,11 @@ class HomeViewModel extends BaseViewModel { response = {'data': true, 'status': ResponseStatus.success}; } - return response; + if (response['status'] == ResponseStatus.success && !response['data']) { + await replaceWithOnboarding(); + } else if (response['status'] == ResponseStatus.success && + response['data']) { + await saveProfileStatus(response['data']); + } } } diff --git a/lib/ui/views/learn/learn_viewmodel.dart b/lib/ui/views/learn/learn_viewmodel.dart index 83260d1..af91edc 100644 --- a/lib/ui/views/learn/learn_viewmodel.dart +++ b/lib/ui/views/learn/learn_viewmodel.dart @@ -7,13 +7,16 @@ import 'package:yimaru_app/ui/common/enmus.dart'; import '../../../app/app.locator.dart'; -class LearnViewModel extends BaseViewModel { +class LearnViewModel extends ReactiveViewModel { final _navigationService = locator(); final _authenticationService = locator(); - late final UserModel? _user = _authenticationService.user; + @override + List get listenableServices => + [_authenticationService]; - UserModel? get user => _user; + // Current user + UserModel? get user => _authenticationService.user; final List> _learnLevels = [ { diff --git a/lib/ui/views/profile/profile_view.dart b/lib/ui/views/profile/profile_view.dart index 909bd3c..cfaad64 100644 --- a/lib/ui/views/profile/profile_view.dart +++ b/lib/ui/views/profile/profile_view.dart @@ -1,17 +1,37 @@ 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/enmus.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart'; +import 'package:yimaru_app/ui/widgets/custom_circular_progress_indicator.dart'; import 'package:yimaru_app/ui/widgets/profile_card.dart'; import 'package:yimaru_app/ui/widgets/profile_image.dart'; import 'package:yimaru_app/ui/widgets/view_profile_button.dart'; import '../../widgets/custom_elevated_button.dart'; +import '../../widgets/image_picker_option.dart'; import 'profile_viewmodel.dart'; class ProfileView extends StackedView { const ProfileView({Key? key}) : super(key: key); + Future _showImagePicker( + {required BuildContext context, + required ProfileViewModel viewModel}) async => + await showDialog( + context: context, + builder: (context) => + _showImagePickerDialog(context: context, viewModel: viewModel), + ); + + AlertDialog _showImagePickerDialog( + {required BuildContext context, + required ProfileViewModel viewModel}) => + AlertDialog( + backgroundColor: Colors.transparent, + content: _buildImagePicker(context: context, viewModel: viewModel), + ); + @override ProfileViewModel viewModelBuilder( BuildContext context, @@ -24,30 +44,45 @@ class ProfileView extends StackedView { ProfileViewModel viewModel, Widget? child, ) => - _buildScaffoldWrapper(viewModel); + _buildScaffoldWrapper(context: context, viewModel: viewModel); - Widget _buildScaffoldWrapper(ProfileViewModel viewModel) => Scaffold( + Widget _buildScaffoldWrapper( + {required BuildContext context, + required ProfileViewModel viewModel}) => + Scaffold( backgroundColor: kcBackgroundColor, - body: _buildScaffold(viewModel), + body: _buildScaffold(context: context, viewModel: viewModel), ); - Widget _buildScaffold(ProfileViewModel viewModel) => - SafeArea(child: _buildBodyWrapper(viewModel)); + Widget _buildScaffold( + {required BuildContext context, + required ProfileViewModel viewModel}) => + SafeArea( + child: _buildBodyWrapper(context: context, viewModel: viewModel)); - Widget _buildBodyWrapper(ProfileViewModel viewModel) => SingleChildScrollView( - child: _buildBody(viewModel), + Widget _buildBodyWrapper( + {required BuildContext context, + required ProfileViewModel viewModel}) => + SingleChildScrollView( + child: _buildBody(context: context, viewModel: viewModel), ); - Widget _buildBody(ProfileViewModel viewModel) => Padding( + Widget _buildBody( + {required BuildContext context, + required ProfileViewModel viewModel}) => + Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: _buildColumn(viewModel), + child: _buildColumn(context: context, viewModel: viewModel), ); - Widget _buildColumn(ProfileViewModel viewModel) => Column( + Widget _buildColumn( + {required BuildContext context, + required ProfileViewModel viewModel}) => + Column( children: [ verticalSpaceMedium, _buildNotificationIconWrapper(), - _buildProfileSection(viewModel), + _buildProfileSection(context: context, viewModel: viewModel), verticalSpaceSmall, _buildViewProfileButton(viewModel), verticalSpaceLarge, @@ -66,20 +101,42 @@ class ProfileView extends StackedView { color: kcDarkGrey, ); - Widget _buildProfileSection(ProfileViewModel viewModel) => Column( + Widget _buildProfileSection( + {required BuildContext context, + required ProfileViewModel viewModel}) => + Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, - children: _buildProfileSectionChildren(viewModel), + children: _buildProfileSectionChildren( + context: context, viewModel: viewModel), ); - List _buildProfileSectionChildren(ProfileViewModel viewModel) => [ - _buildProfileImage(viewModel), + List _buildProfileSectionChildren( + {required BuildContext context, + required ProfileViewModel viewModel}) => + [ + _buildProfileImage(context: context, viewModel: viewModel), verticalSpaceSmall, _buildProfileName(viewModel), ]; - Widget _buildProfileImage(ProfileViewModel viewModel) => ProfileImage( + + Widget _buildProfileImage( + {required BuildContext context, + required ProfileViewModel viewModel}) => + ProfileImage( profileImage: viewModel.user?.profileImage, + loading: viewModel.busy(StateObjects.profileImage) ? true:false, + onTap: () async => + await _showImagePicker(context: context, viewModel: viewModel), + ); + + Widget _buildImagePicker( + {required BuildContext context, + required ProfileViewModel viewModel}) => + ImagePickerOption( + onCameraTap: () async => await viewModel.openCamera(), + onGalleryTap: () async => await viewModel.openGallery(), ); Widget _buildProfileName(ProfileViewModel viewModel) => Text( diff --git a/lib/ui/views/profile/profile_viewmodel.dart b/lib/ui/views/profile/profile_viewmodel.dart index 72f037b..b4deac6 100644 --- a/lib/ui/views/profile/profile_viewmodel.dart +++ b/lib/ui/views/profile/profile_viewmodel.dart @@ -1,25 +1,58 @@ 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/image_picker_service.dart'; +import 'package:yimaru_app/ui/common/enmus.dart'; import '../../../app/app.locator.dart'; import '../../../models/user_model.dart'; import '../../../services/authentication_service.dart'; -class ProfileViewModel extends BaseViewModel { +class ProfileViewModel extends ReactiveViewModel { final _navigationService = locator(); + final _imagePickerService = locator(); + final _authenticationService = locator(); - late final UserModel? _user = _authenticationService.user; + @override + List get listenableServices => + [_authenticationService]; - UserModel? get user => _user; + // Current user + UserModel? get user => _authenticationService.user; + // Image picker + Future openCamera() async => runBusyFuture(_openCamera(),busyObject: StateObjects.profileImage); + + Future _openCamera()async{ + String? image = await _imagePickerService.camera(); + if (image != null) { + await _authenticationService.saveProfileImage(image); + } + pop(); + } + + Future openGallery() async => runBusyFuture(_openGallery(),busyObject: StateObjects.profileImage); + + + Future _openGallery() async { + String? image = await _imagePickerService.gallery(); + if (image != null) { + await _authenticationService.saveProfileImage(image); + } + pop(); + } + + // Logout Future logOut() async { await _authenticationService.logOut(); await _navigationService.replaceWithLoginView(); } + // Navigation + void pop() => _navigationService.back(); + Future navigateToProfileDetail() async => await _navigationService.navigateToProfileDetailView(); diff --git a/lib/ui/widgets/custom_large_radio_button.dart b/lib/ui/widgets/custom_large_radio_button.dart index 8a7bbd7..1193070 100644 --- a/lib/ui/widgets/custom_large_radio_button.dart +++ b/lib/ui/widgets/custom_large_radio_button.dart @@ -82,5 +82,5 @@ class CustomLargeRadioButton extends StatelessWidget { Widget _buildSelectedCheckBox() => Checkbox( value: selected, activeColor: kcPrimaryColor, - onChanged: (value) => onTap); + onChanged: onTap != null ? (value) => onTap!() : null); } diff --git a/lib/ui/widgets/image_picker_option.dart b/lib/ui/widgets/image_picker_option.dart new file mode 100644 index 0000000..aaaef04 --- /dev/null +++ b/lib/ui/widgets/image_picker_option.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:yimaru_app/ui/common/app_colors.dart'; +import 'package:yimaru_app/ui/common/ui_helpers.dart'; + +class ImagePickerOption extends StatelessWidget { + final GestureTapCallback? onCameraTap; + final GestureTapCallback? onGalleryTap; + + const ImagePickerOption({super.key, this.onCameraTap, this.onGalleryTap}); + + @override + Widget build(BuildContext context) => _buildContainer(); + + Widget _buildContainer() => Container( + height: 200, + decoration: const BoxDecoration( + color: kcBackgroundColor, + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(32.0)), + ), + child: _buildCameraOptionWrapper(), + ); + + Widget _buildCameraOptionWrapper() => Center( + child: _buildCameraOption(), + ); + + Widget _buildCameraOption() => Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: _buildCameraOptionChildren(), + ); + + List _buildCameraOptionChildren() => + [_buildCameraButton(), _buildGalleryButton()]; + + Widget _buildCameraButton() => GestureDetector( + onTap: onCameraTap, + child: _buildCamera(), + ); + + Widget _buildCamera() => Column( + mainAxisSize: MainAxisSize.min, + children: _buildCameraChildren(), + ); + + List _buildCameraChildren() => + [_buildCameraIcon(), verticalSpaceTiny, _buildCameraTitle()]; + + Widget _buildCameraIcon() => const Icon( + Icons.camera_alt_rounded, + size: 60, + color: kcPrimaryColor, + ); + + Widget _buildCameraTitle() => Text( + 'Camera', + style: style18P600, + ); + + Widget _buildGalleryButton() => GestureDetector( + onTap: onGalleryTap, + child: _buildGallery(), + ); + Widget _buildGallery() => Column( + mainAxisSize: MainAxisSize.min, + children: _buildGalleryChildren(), + ); + + Widget _buildGalleryIcon() => const Icon( + Icons.photo, + size: 60, + color: kcPrimaryColor, + ); + + Widget _buildGalleryText() => Text( + 'Gallery', + style: style18P600, + ); + + List _buildGalleryChildren() => + [_buildGalleryIcon(), verticalSpaceTiny, _buildGalleryText()]; +} diff --git a/lib/ui/widgets/learn_app_bar.dart b/lib/ui/widgets/learn_app_bar.dart index 252cb63..e84af8b 100644 --- a/lib/ui/widgets/learn_app_bar.dart +++ b/lib/ui/widgets/learn_app_bar.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:yimaru_app/ui/common/ui_helpers.dart'; @@ -39,7 +41,9 @@ class LearnAppBar extends StatelessWidget { radius: 25, backgroundColor: kcPrimaryColor, backgroundImage: profileImage != null - ? CachedNetworkImageProvider(profileImage!) + ? FileImage( + File(profileImage!), + ) : null, child: _buildImageBuilder(), ); diff --git a/lib/ui/widgets/profile_image.dart b/lib/ui/widgets/profile_image.dart index 7453547..db9ecf5 100644 --- a/lib/ui/widgets/profile_image.dart +++ b/lib/ui/widgets/profile_image.dart @@ -1,17 +1,26 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:yimaru_app/ui/common/app_colors.dart'; class ProfileImage extends StatelessWidget { + final bool loading; final String? profileImage; - const ProfileImage({super.key, required this.profileImage}); + final GestureTapCallback? onTap; + + const ProfileImage( + {super.key, + this.onTap, + this.loading = false, + required this.profileImage}); @override Widget build(BuildContext context) => _buildSizedBox(); Widget _buildSizedBox() => SizedBox( - height: 125, width: 125, + height: 125, child: _buildStack(), ); @@ -27,14 +36,21 @@ class ProfileImage extends StatelessWidget { Widget _buildProfileImage() => CircleAvatar( radius: 50, backgroundColor: kcPrimaryColor, - backgroundImage: profileImage != null - ? CachedNetworkImageProvider(profileImage!) - : null, + backgroundImage: loading + ? null + : profileImage != null + ? FileImage( + File(profileImage!), + ) + : null, child: _buildImageBuilder(), ); - Widget? _buildImageBuilder() => - profileImage == null ? _buildPersonIcon() : null; + Widget? _buildImageBuilder() => loading + ? null + : profileImage == null + ? _buildPersonIcon() + : null; Widget _buildPersonIcon() => const Icon( Icons.person, @@ -44,6 +60,11 @@ class ProfileImage extends StatelessWidget { Widget _buildCameraButtonWrapper() => Align( alignment: Alignment.bottomCenter, + child: _buildCameraTapDetector(), + ); + + Widget _buildCameraTapDetector() => GestureDetector( + onTap: onTap, child: _buildCameraButton(), ); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index d0e7f79..85a2413 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,9 +6,13 @@ #include "generated_plugin_registrant.h" +#include #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index b29e9ba..62e3ed5 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux flutter_secure_storage_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index a9f61f7..6b29984 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,12 +7,14 @@ import Foundation import battery_plus import connectivity_plus +import file_selector_macos import flutter_secure_storage_darwin import sqflite_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { BatteryPlusMacosPlugin.register(with: registry.registrar(forPlugin: "BatteryPlusMacosPlugin")) ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) FlutterSecureStorageDarwinPlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStorageDarwinPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 29c3534..82c6e02 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -225,6 +225,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "701dcfc06da0882883a2657c445103380e53e647060ad8d9dfb710c100996608" + url: "https://pub.dev" + source: hosted + version: "0.3.5+1" crypto: dependency: transitive description: @@ -321,6 +329,38 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" + url: "https://pub.dev" + source: hosted + version: "0.9.4" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" + url: "https://pub.dev" + source: hosted + version: "0.9.5" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" + url: "https://pub.dev" + source: hosted + version: "0.9.3+5" fixnum: dependency: transitive description: @@ -366,6 +406,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 + url: "https://pub.dev" + source: hosted + version: "2.0.33" flutter_secure_storage: dependency: "direct main" description: @@ -552,6 +600,70 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "297e42bd236c4ac4b091d4277292159b3280545e030cae2be3d503f9ecf7e6a1" + url: "https://pub.dev" + source: hosted + version: "0.8.13+12" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "956c16a42c0c708f914021666ffcd8265dde36e673c9fa68c81f7d085d9774ad" + url: "https://pub.dev" + source: hosted + version: "0.8.13+3" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" + url: "https://pub.dev" + source: hosted + version: "2.11.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae + url: "https://pub.dev" + source: hosted + version: "0.2.2" in_app_update: dependency: "direct main" description: @@ -832,6 +944,54 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0+3" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: bc917da36261b00137bbc8896bf1482169cd76f866282368948f032c8c1caae1 + url: "https://pub.dev" + source: hosted + version: "12.0.1" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: "1e3bc410ca1bf84662104b100eb126e066cb55791b7451307f9708d4007350e6" + url: "https://pub.dev" + source: hosted + version: "13.0.1" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: f000131e755c54cf4d84a5d8bd6e4149e262cc31c5a8b1d698de1ac85fa41023 + url: "https://pub.dev" + source: hosted + version: "9.4.7" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" + url: "https://pub.dev" + source: hosted + version: "0.1.3+5" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 + url: "https://pub.dev" + source: hosted + version: "4.3.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" petitparser: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8f9fb5c..a88784d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,6 +16,7 @@ dependencies: iconsax: ^0.0.8 flutter_svg: ^2.2.3 stacked_shared: any + image_picker: ^1.2.1 battery_plus: ^7.0.0 storage_info: ^1.0.0 flutter_html: ^3.0.0 @@ -27,6 +28,7 @@ dependencies: stacked_services: ^1.1.0 omni_datetime_picker: any json_serializable: ^6.8.0 + permission_handler: ^12.0.1 cached_network_image: ^3.4.1 flutter_secure_storage: ^10.0.0 flutter_timer_countdown: ^1.0.7 diff --git a/test/helpers/test_helpers.dart b/test/helpers/test_helpers.dart new file mode 100644 index 0000000..84e880c --- /dev/null +++ b/test/helpers/test_helpers.dart @@ -0,0 +1,155 @@ +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:yimaru_app/app/app.locator.dart'; +import 'package:stacked_services/stacked_services.dart'; +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/services/permission_handler_service.dart'; +import 'package:yimaru_app/services/image_picker_service.dart'; +// @stacked-import + +import 'test_helpers.mocks.dart'; + +@GenerateMocks( + [], + customMocks: [ + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), + MockSpec( + onMissingStub: OnMissingStub.returnDefault), + MockSpec(onMissingStub: OnMissingStub.returnDefault), +// @stacked-mock-spec + ], +) +void registerServices() { + getAndRegisterNavigationService(); + getAndRegisterBottomSheetService(); + getAndRegisterDialogService(); + getAndRegisterAuthenticationService(); + getAndRegisterApiService(); + getAndRegisterSecureStorageService(); + getAndRegisterDioService(); + getAndRegisterStatusCheckerService(); + getAndRegisterPermissionHandlerService(); + getAndRegisterImagePickerService(); +// @stacked-mock-register +} + +MockNavigationService getAndRegisterNavigationService() { + _removeRegistrationIfExists(); + final service = MockNavigationService(); + locator.registerSingleton(service); + return service; +} + +MockBottomSheetService getAndRegisterBottomSheetService({ + SheetResponse? showCustomSheetResponse, +}) { + _removeRegistrationIfExists(); + final service = MockBottomSheetService(); + + when( + service.showCustomSheet( + enableDrag: anyNamed('enableDrag'), + enterBottomSheetDuration: anyNamed('enterBottomSheetDuration'), + exitBottomSheetDuration: anyNamed('exitBottomSheetDuration'), + ignoreSafeArea: anyNamed('ignoreSafeArea'), + isScrollControlled: anyNamed('isScrollControlled'), + barrierDismissible: anyNamed('barrierDismissible'), + additionalButtonTitle: anyNamed('additionalButtonTitle'), + variant: anyNamed('variant'), + title: anyNamed('title'), + hasImage: anyNamed('hasImage'), + imageUrl: anyNamed('imageUrl'), + showIconInMainButton: anyNamed('showIconInMainButton'), + mainButtonTitle: anyNamed('mainButtonTitle'), + showIconInSecondaryButton: anyNamed('showIconInSecondaryButton'), + secondaryButtonTitle: anyNamed('secondaryButtonTitle'), + showIconInAdditionalButton: anyNamed('showIconInAdditionalButton'), + takesInput: anyNamed('takesInput'), + barrierColor: anyNamed('barrierColor'), + barrierLabel: anyNamed('barrierLabel'), + customData: anyNamed('customData'), + data: anyNamed('data'), + description: anyNamed('description'), + ), + ).thenAnswer( + (realInvocation) => + Future.value(showCustomSheetResponse ?? SheetResponse()), + ); + + locator.registerSingleton(service); + return service; +} + +MockDialogService getAndRegisterDialogService() { + _removeRegistrationIfExists(); + final service = MockDialogService(); + locator.registerSingleton(service); + return service; +} + +MockAuthenticationService getAndRegisterAuthenticationService() { + _removeRegistrationIfExists(); + final service = MockAuthenticationService(); + locator.registerSingleton(service); + return service; +} + +MockApiService getAndRegisterApiService() { + _removeRegistrationIfExists(); + final service = MockApiService(); + locator.registerSingleton(service); + return service; +} + +MockSecureStorageService getAndRegisterSecureStorageService() { + _removeRegistrationIfExists(); + final service = MockSecureStorageService(); + locator.registerSingleton(service); + return service; +} + +MockDioService getAndRegisterDioService() { + _removeRegistrationIfExists(); + final service = MockDioService(); + locator.registerSingleton(service); + return service; +} + +MockStatusCheckerService getAndRegisterStatusCheckerService() { + _removeRegistrationIfExists(); + final service = MockStatusCheckerService(); + locator.registerSingleton(service); + return service; +} + +MockPermissionHandlerService getAndRegisterPermissionHandlerService() { + _removeRegistrationIfExists(); + final service = MockPermissionHandlerService(); + locator.registerSingleton(service); + return service; +} + +MockImagePickerService getAndRegisterImagePickerService() { + _removeRegistrationIfExists(); + final service = MockImagePickerService(); + locator.registerSingleton(service); + return service; +} +// @stacked-mock-create + +void _removeRegistrationIfExists() { + if (locator.isRegistered()) { + locator.unregister(); + } +} diff --git a/test/helpers/test_helpers.mocks.dart b/test/helpers/test_helpers.mocks.dart new file mode 100644 index 0000000..edb1e4a --- /dev/null +++ b/test/helpers/test_helpers.mocks.dart @@ -0,0 +1,1238 @@ +// Mocks generated by Mockito 5.4.4 from annotations +// in yimaru_app/test/helpers/test_helpers.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i7; +import 'dart:ui' as _i8; + +import 'package:dio/dio.dart' as _i2; +import 'package:flutter/material.dart' as _i6; +import 'package:mockito/mockito.dart' as _i1; +import 'package:mockito/src/dummies.dart' as _i5; +import 'package:permission_handler/permission_handler.dart' as _i16; +import 'package:stacked_services/stacked_services.dart' as _i4; +import 'package:yimaru_app/models/assessment.dart' as _i12; +import 'package:yimaru_app/models/user_model.dart' as _i10; +import 'package:yimaru_app/services/api_service.dart' as _i11; +import 'package:yimaru_app/services/authentication_service.dart' as _i9; +import 'package:yimaru_app/services/dio_service.dart' as _i13; +import 'package:yimaru_app/services/image_picker_service.dart' as _i17; +import 'package:yimaru_app/services/permission_handler_service.dart' as _i15; +import 'package:yimaru_app/services/secure_storage_service.dart' as _i3; +import 'package:yimaru_app/services/status_checker_service.dart' as _i14; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +class _FakeDio_0 extends _i1.SmartFake implements _i2.Dio { + _FakeDio_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeSecureStorageService_1 extends _i1.SmartFake + implements _i3.SecureStorageService { + _FakeSecureStorageService_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +/// A class which mocks [NavigationService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockNavigationService extends _i1.Mock implements _i4.NavigationService { + @override + String get previousRoute => (super.noSuchMethod( + Invocation.getter(#previousRoute), + returnValue: _i5.dummyValue( + this, + Invocation.getter(#previousRoute), + ), + returnValueForMissingStub: _i5.dummyValue( + this, + Invocation.getter(#previousRoute), + ), + ) as String); + + @override + String get currentRoute => (super.noSuchMethod( + Invocation.getter(#currentRoute), + returnValue: _i5.dummyValue( + this, + Invocation.getter(#currentRoute), + ), + returnValueForMissingStub: _i5.dummyValue( + this, + Invocation.getter(#currentRoute), + ), + ) as String); + + @override + _i6.GlobalKey<_i6.NavigatorState>? nestedNavigationKey(int? index) => + (super.noSuchMethod( + Invocation.method( + #nestedNavigationKey, + [index], + ), + returnValueForMissingStub: null, + ) as _i6.GlobalKey<_i6.NavigatorState>?); + + @override + void config({ + bool? enableLog, + bool? defaultPopGesture, + bool? defaultOpaqueRoute, + Duration? defaultDurationTransition, + bool? defaultGlobalState, + _i4.Transition? defaultTransitionStyle, + String? defaultTransition, + }) => + super.noSuchMethod( + Invocation.method( + #config, + [], + { + #enableLog: enableLog, + #defaultPopGesture: defaultPopGesture, + #defaultOpaqueRoute: defaultOpaqueRoute, + #defaultDurationTransition: defaultDurationTransition, + #defaultGlobalState: defaultGlobalState, + #defaultTransitionStyle: defaultTransitionStyle, + #defaultTransition: defaultTransition, + }, + ), + returnValueForMissingStub: null, + ); + + @override + _i7.Future? navigateWithTransition( + _i6.Widget? page, { + bool? opaque, + String? transition = r'', + Duration? duration, + bool? popGesture, + int? id, + _i6.Curve? curve, + bool? fullscreenDialog = false, + bool? preventDuplicates = true, + _i4.Transition? transitionClass, + _i4.Transition? transitionStyle, + String? routeName, + }) => + (super.noSuchMethod( + Invocation.method( + #navigateWithTransition, + [page], + { + #opaque: opaque, + #transition: transition, + #duration: duration, + #popGesture: popGesture, + #id: id, + #curve: curve, + #fullscreenDialog: fullscreenDialog, + #preventDuplicates: preventDuplicates, + #transitionClass: transitionClass, + #transitionStyle: transitionStyle, + #routeName: routeName, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? replaceWithTransition( + _i6.Widget? page, { + bool? opaque, + String? transition = r'', + Duration? duration, + bool? popGesture, + int? id, + _i6.Curve? curve, + bool? fullscreenDialog = false, + bool? preventDuplicates = true, + _i4.Transition? transitionClass, + _i4.Transition? transitionStyle, + String? routeName, + }) => + (super.noSuchMethod( + Invocation.method( + #replaceWithTransition, + [page], + { + #opaque: opaque, + #transition: transition, + #duration: duration, + #popGesture: popGesture, + #id: id, + #curve: curve, + #fullscreenDialog: fullscreenDialog, + #preventDuplicates: preventDuplicates, + #transitionClass: transitionClass, + #transitionStyle: transitionStyle, + #routeName: routeName, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + bool back({ + dynamic result, + int? id, + }) => + (super.noSuchMethod( + Invocation.method( + #back, + [], + { + #result: result, + #id: id, + }, + ), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + + @override + void popUntil( + _i6.RoutePredicate? predicate, { + int? id, + }) => + super.noSuchMethod( + Invocation.method( + #popUntil, + [predicate], + {#id: id}, + ), + returnValueForMissingStub: null, + ); + + @override + void popRepeated(int? popTimes) => super.noSuchMethod( + Invocation.method( + #popRepeated, + [popTimes], + ), + returnValueForMissingStub: null, + ); + + @override + _i7.Future? navigateTo( + String? routeName, { + dynamic arguments, + int? id, + bool? preventDuplicates = true, + Map? parameters, + _i6.RouteTransitionsBuilder? transition, + }) => + (super.noSuchMethod( + Invocation.method( + #navigateTo, + [routeName], + { + #arguments: arguments, + #id: id, + #preventDuplicates: preventDuplicates, + #parameters: parameters, + #transition: transition, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? navigateToView( + _i6.Widget? view, { + dynamic arguments, + int? id, + bool? opaque, + _i6.Curve? curve, + Duration? duration, + bool? fullscreenDialog = false, + bool? popGesture, + bool? preventDuplicates = true, + _i4.Transition? transition, + _i4.Transition? transitionStyle, + }) => + (super.noSuchMethod( + Invocation.method( + #navigateToView, + [view], + { + #arguments: arguments, + #id: id, + #opaque: opaque, + #curve: curve, + #duration: duration, + #fullscreenDialog: fullscreenDialog, + #popGesture: popGesture, + #preventDuplicates: preventDuplicates, + #transition: transition, + #transitionStyle: transitionStyle, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? replaceWith( + String? routeName, { + dynamic arguments, + int? id, + bool? preventDuplicates = true, + Map? parameters, + _i6.RouteTransitionsBuilder? transition, + }) => + (super.noSuchMethod( + Invocation.method( + #replaceWith, + [routeName], + { + #arguments: arguments, + #id: id, + #preventDuplicates: preventDuplicates, + #parameters: parameters, + #transition: transition, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? clearStackAndShow( + String? routeName, { + dynamic arguments, + int? id, + Map? parameters, + }) => + (super.noSuchMethod( + Invocation.method( + #clearStackAndShow, + [routeName], + { + #arguments: arguments, + #id: id, + #parameters: parameters, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? clearStackAndShowView( + _i6.Widget? view, { + dynamic arguments, + int? id, + }) => + (super.noSuchMethod( + Invocation.method( + #clearStackAndShowView, + [view], + { + #arguments: arguments, + #id: id, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? clearTillFirstAndShow( + String? routeName, { + dynamic arguments, + int? id, + bool? preventDuplicates = true, + Map? parameters, + }) => + (super.noSuchMethod( + Invocation.method( + #clearTillFirstAndShow, + [routeName], + { + #arguments: arguments, + #id: id, + #preventDuplicates: preventDuplicates, + #parameters: parameters, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? clearTillFirstAndShowView( + _i6.Widget? view, { + dynamic arguments, + int? id, + }) => + (super.noSuchMethod( + Invocation.method( + #clearTillFirstAndShowView, + [view], + { + #arguments: arguments, + #id: id, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); + + @override + _i7.Future? pushNamedAndRemoveUntil( + String? routeName, { + _i6.RoutePredicate? predicate, + dynamic arguments, + int? id, + }) => + (super.noSuchMethod( + Invocation.method( + #pushNamedAndRemoveUntil, + [routeName], + { + #predicate: predicate, + #arguments: arguments, + #id: id, + }, + ), + returnValueForMissingStub: null, + ) as _i7.Future?); +} + +/// A class which mocks [BottomSheetService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockBottomSheetService extends _i1.Mock + implements _i4.BottomSheetService { + @override + void setCustomSheetBuilders(Map? builders) => + super.noSuchMethod( + Invocation.method( + #setCustomSheetBuilders, + [builders], + ), + returnValueForMissingStub: null, + ); + + @override + _i7.Future<_i4.SheetResponse?> showBottomSheet({ + required String? title, + String? description, + String? confirmButtonTitle = r'Ok', + String? cancelButtonTitle, + bool? enableDrag = true, + bool? barrierDismissible = true, + bool? isScrollControlled = false, + Duration? exitBottomSheetDuration, + Duration? enterBottomSheetDuration, + bool? ignoreSafeArea, + bool? useRootNavigator = false, + double? elevation = 1.0, + }) => + (super.noSuchMethod( + Invocation.method( + #showBottomSheet, + [], + { + #title: title, + #description: description, + #confirmButtonTitle: confirmButtonTitle, + #cancelButtonTitle: cancelButtonTitle, + #enableDrag: enableDrag, + #barrierDismissible: barrierDismissible, + #isScrollControlled: isScrollControlled, + #exitBottomSheetDuration: exitBottomSheetDuration, + #enterBottomSheetDuration: enterBottomSheetDuration, + #ignoreSafeArea: ignoreSafeArea, + #useRootNavigator: useRootNavigator, + #elevation: elevation, + }, + ), + returnValue: _i7.Future<_i4.SheetResponse?>.value(), + returnValueForMissingStub: + _i7.Future<_i4.SheetResponse?>.value(), + ) as _i7.Future<_i4.SheetResponse?>); + + @override + _i7.Future<_i4.SheetResponse?> showCustomSheet({ + dynamic variant, + String? title, + String? description, + bool? hasImage = false, + String? imageUrl, + bool? showIconInMainButton = false, + String? mainButtonTitle, + bool? showIconInSecondaryButton = false, + String? secondaryButtonTitle, + bool? showIconInAdditionalButton = false, + String? additionalButtonTitle, + bool? takesInput = false, + _i8.Color? barrierColor = const _i8.Color(2315255808), + double? elevation = 1.0, + bool? barrierDismissible = true, + bool? isScrollControlled = false, + String? barrierLabel = r'', + dynamic customData, + R? data, + bool? enableDrag = true, + Duration? exitBottomSheetDuration, + Duration? enterBottomSheetDuration, + bool? ignoreSafeArea, + bool? useRootNavigator = false, + }) => + (super.noSuchMethod( + Invocation.method( + #showCustomSheet, + [], + { + #variant: variant, + #title: title, + #description: description, + #hasImage: hasImage, + #imageUrl: imageUrl, + #showIconInMainButton: showIconInMainButton, + #mainButtonTitle: mainButtonTitle, + #showIconInSecondaryButton: showIconInSecondaryButton, + #secondaryButtonTitle: secondaryButtonTitle, + #showIconInAdditionalButton: showIconInAdditionalButton, + #additionalButtonTitle: additionalButtonTitle, + #takesInput: takesInput, + #barrierColor: barrierColor, + #elevation: elevation, + #barrierDismissible: barrierDismissible, + #isScrollControlled: isScrollControlled, + #barrierLabel: barrierLabel, + #customData: customData, + #data: data, + #enableDrag: enableDrag, + #exitBottomSheetDuration: exitBottomSheetDuration, + #enterBottomSheetDuration: enterBottomSheetDuration, + #ignoreSafeArea: ignoreSafeArea, + #useRootNavigator: useRootNavigator, + }, + ), + returnValue: _i7.Future<_i4.SheetResponse?>.value(), + returnValueForMissingStub: _i7.Future<_i4.SheetResponse?>.value(), + ) as _i7.Future<_i4.SheetResponse?>); + + @override + void completeSheet(_i4.SheetResponse? response) => + super.noSuchMethod( + Invocation.method( + #completeSheet, + [response], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [DialogService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockDialogService extends _i1.Mock implements _i4.DialogService { + @override + void registerCustomDialogBuilders( + Map? builders) => + super.noSuchMethod( + Invocation.method( + #registerCustomDialogBuilders, + [builders], + ), + returnValueForMissingStub: null, + ); + + @override + void registerCustomDialogBuilder({ + required dynamic variant, + required _i6.Widget Function( + _i6.BuildContext, + _i4.DialogRequest, + dynamic Function(_i4.DialogResponse), + )? builder, + }) => + super.noSuchMethod( + Invocation.method( + #registerCustomDialogBuilder, + [], + { + #variant: variant, + #builder: builder, + }, + ), + returnValueForMissingStub: null, + ); + + @override + _i7.Future<_i4.DialogResponse?> showDialog({ + String? title, + String? description, + String? cancelTitle, + _i8.Color? cancelTitleColor, + String? buttonTitle = r'Ok', + _i8.Color? buttonTitleColor, + bool? barrierDismissible = false, + _i6.RouteSettings? routeSettings, + _i6.GlobalKey<_i6.NavigatorState>? navigatorKey, + _i4.DialogPlatform? dialogPlatform, + }) => + (super.noSuchMethod( + Invocation.method( + #showDialog, + [], + { + #title: title, + #description: description, + #cancelTitle: cancelTitle, + #cancelTitleColor: cancelTitleColor, + #buttonTitle: buttonTitle, + #buttonTitleColor: buttonTitleColor, + #barrierDismissible: barrierDismissible, + #routeSettings: routeSettings, + #navigatorKey: navigatorKey, + #dialogPlatform: dialogPlatform, + }, + ), + returnValue: _i7.Future<_i4.DialogResponse?>.value(), + returnValueForMissingStub: + _i7.Future<_i4.DialogResponse?>.value(), + ) as _i7.Future<_i4.DialogResponse?>); + + @override + _i7.Future<_i4.DialogResponse?> showCustomDialog({ + dynamic variant, + String? title, + String? description, + bool? hasImage = false, + String? imageUrl, + bool? showIconInMainButton = false, + String? mainButtonTitle, + bool? showIconInSecondaryButton = false, + String? secondaryButtonTitle, + bool? showIconInAdditionalButton = false, + String? additionalButtonTitle, + bool? takesInput = false, + _i8.Color? barrierColor = const _i8.Color(2315255808), + bool? barrierDismissible = false, + String? barrierLabel = r'', + bool? useSafeArea = true, + _i6.RouteSettings? routeSettings, + _i6.GlobalKey<_i6.NavigatorState>? navigatorKey, + _i6.RouteTransitionsBuilder? transitionBuilder, + dynamic customData, + R? data, + }) => + (super.noSuchMethod( + Invocation.method( + #showCustomDialog, + [], + { + #variant: variant, + #title: title, + #description: description, + #hasImage: hasImage, + #imageUrl: imageUrl, + #showIconInMainButton: showIconInMainButton, + #mainButtonTitle: mainButtonTitle, + #showIconInSecondaryButton: showIconInSecondaryButton, + #secondaryButtonTitle: secondaryButtonTitle, + #showIconInAdditionalButton: showIconInAdditionalButton, + #additionalButtonTitle: additionalButtonTitle, + #takesInput: takesInput, + #barrierColor: barrierColor, + #barrierDismissible: barrierDismissible, + #barrierLabel: barrierLabel, + #useSafeArea: useSafeArea, + #routeSettings: routeSettings, + #navigatorKey: navigatorKey, + #transitionBuilder: transitionBuilder, + #customData: customData, + #data: data, + }, + ), + returnValue: _i7.Future<_i4.DialogResponse?>.value(), + returnValueForMissingStub: _i7.Future<_i4.DialogResponse?>.value(), + ) as _i7.Future<_i4.DialogResponse?>); + + @override + _i7.Future<_i4.DialogResponse?> showConfirmationDialog({ + String? title, + String? description, + String? cancelTitle = r'Cancel', + _i8.Color? cancelTitleColor, + String? confirmationTitle = r'Ok', + _i8.Color? confirmationTitleColor, + bool? barrierDismissible = false, + _i6.RouteSettings? routeSettings, + _i4.DialogPlatform? dialogPlatform, + }) => + (super.noSuchMethod( + Invocation.method( + #showConfirmationDialog, + [], + { + #title: title, + #description: description, + #cancelTitle: cancelTitle, + #cancelTitleColor: cancelTitleColor, + #confirmationTitle: confirmationTitle, + #confirmationTitleColor: confirmationTitleColor, + #barrierDismissible: barrierDismissible, + #routeSettings: routeSettings, + #dialogPlatform: dialogPlatform, + }, + ), + returnValue: _i7.Future<_i4.DialogResponse?>.value(), + returnValueForMissingStub: + _i7.Future<_i4.DialogResponse?>.value(), + ) as _i7.Future<_i4.DialogResponse?>); + + @override + void completeDialog(_i4.DialogResponse? response) => + super.noSuchMethod( + Invocation.method( + #completeDialog, + [response], + ), + returnValueForMissingStub: null, + ); +} + +/// A class which mocks [AuthenticationService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockAuthenticationService extends _i1.Mock + implements _i9.AuthenticationService { + @override + _i7.Future userLoggedIn() => (super.noSuchMethod( + Invocation.method( + #userLoggedIn, + [], + ), + returnValue: _i7.Future.value(false), + returnValueForMissingStub: _i7.Future.value(false), + ) as _i7.Future); + + @override + _i7.Future getAccessToken() => (super.noSuchMethod( + Invocation.method( + #getAccessToken, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future getRefreshToken() => (super.noSuchMethod( + Invocation.method( + #getRefreshToken, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future getUserId() => (super.noSuchMethod( + Invocation.method( + #getUserId, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future saveTokens({ + required String? access, + required String? refresh, + }) => + (super.noSuchMethod( + Invocation.method( + #saveTokens, + [], + { + #access: access, + #refresh: refresh, + }, + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future saveUserName(Map? data) => + (super.noSuchMethod( + Invocation.method( + #saveUserName, + [data], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future saveBasicUserData(Map? data) => + (super.noSuchMethod( + Invocation.method( + #saveBasicUserData, + [data], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future saveProfileStatus(bool? value) => (super.noSuchMethod( + Invocation.method( + #saveProfileStatus, + [value], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future saveProfileImage(String? image) => (super.noSuchMethod( + Invocation.method( + #saveProfileImage, + [image], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future saveFullName(Map? data) => + (super.noSuchMethod( + Invocation.method( + #saveFullName, + [data], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future isFirstTimeInstall() => (super.noSuchMethod( + Invocation.method( + #isFirstTimeInstall, + [], + ), + returnValue: _i7.Future.value(false), + returnValueForMissingStub: _i7.Future.value(false), + ) as _i7.Future); + + @override + _i7.Future setFirstTimeInstall(bool? value) => (super.noSuchMethod( + Invocation.method( + #setFirstTimeInstall, + [value], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future<_i10.UserModel?> getUser() => (super.noSuchMethod( + Invocation.method( + #getUser, + [], + ), + returnValue: _i7.Future<_i10.UserModel?>.value(), + returnValueForMissingStub: _i7.Future<_i10.UserModel?>.value(), + ) as _i7.Future<_i10.UserModel?>); + + @override + _i7.Future logOut() => (super.noSuchMethod( + Invocation.method( + #logOut, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); +} + +/// A class which mocks [ApiService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockApiService extends _i1.Mock implements _i11.ApiService { + @override + _i7.Future> register(Map? data) => + (super.noSuchMethod( + Invocation.method( + #register, + [data], + ), + returnValue: + _i7.Future>.value({}), + returnValueForMissingStub: + _i7.Future>.value({}), + ) as _i7.Future>); + + @override + _i7.Future> login(Map? data) => + (super.noSuchMethod( + Invocation.method( + #login, + [data], + ), + returnValue: + _i7.Future>.value({}), + returnValueForMissingStub: + _i7.Future>.value({}), + ) as _i7.Future>); + + @override + _i7.Future> verifyOtp(Map? data) => + (super.noSuchMethod( + Invocation.method( + #verifyOtp, + [data], + ), + returnValue: + _i7.Future>.value({}), + returnValueForMissingStub: + _i7.Future>.value({}), + ) as _i7.Future>); + + @override + _i7.Future> resendOtp(Map? data) => + (super.noSuchMethod( + Invocation.method( + #resendOtp, + [data], + ), + returnValue: + _i7.Future>.value({}), + returnValueForMissingStub: + _i7.Future>.value({}), + ) as _i7.Future>); + + @override + _i7.Future> getProfileStatus(_i10.UserModel? user) => + (super.noSuchMethod( + Invocation.method( + #getProfileStatus, + [user], + ), + returnValue: + _i7.Future>.value({}), + returnValueForMissingStub: + _i7.Future>.value({}), + ) as _i7.Future>); + + @override + _i7.Future> getProfileData(int? userId) => + (super.noSuchMethod( + Invocation.method( + #getProfileData, + [userId], + ), + returnValue: + _i7.Future>.value({}), + returnValueForMissingStub: + _i7.Future>.value({}), + ) as _i7.Future>); + + @override + _i7.Future> updateProfile({ + required _i10.UserModel? user, + required Map? data, + }) => + (super.noSuchMethod( + Invocation.method( + #updateProfile, + [], + { + #user: user, + #data: data, + }, + ), + returnValue: + _i7.Future>.value({}), + returnValueForMissingStub: + _i7.Future>.value({}), + ) as _i7.Future>); + + @override + _i7.Future> getAssessments() => (super.noSuchMethod( + Invocation.method( + #getAssessments, + [], + ), + returnValue: + _i7.Future>.value(<_i12.Assessment>[]), + returnValueForMissingStub: + _i7.Future>.value(<_i12.Assessment>[]), + ) as _i7.Future>); +} + +/// A class which mocks [SecureStorageService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockSecureStorageService extends _i1.Mock + implements _i3.SecureStorageService { + @override + _i7.Future clear() => (super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future getBool(String? key) => (super.noSuchMethod( + Invocation.method( + #getBool, + [key], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future getString(String? key) => (super.noSuchMethod( + Invocation.method( + #getString, + [key], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future getInt(String? key) => (super.noSuchMethod( + Invocation.method( + #getInt, + [key], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future setString( + String? key, + String? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setString, + [ + key, + value, + ], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future setInt( + String? key, + int? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setInt, + [ + key, + value, + ], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future setBool( + String? key, + bool? value, + ) => + (super.noSuchMethod( + Invocation.method( + #setBool, + [ + key, + value, + ], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); +} + +/// A class which mocks [DioService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockDioService extends _i1.Mock implements _i13.DioService { + @override + _i2.Dio get dio => (super.noSuchMethod( + Invocation.getter(#dio), + returnValue: _FakeDio_0( + this, + Invocation.getter(#dio), + ), + returnValueForMissingStub: _FakeDio_0( + this, + Invocation.getter(#dio), + ), + ) as _i2.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 + _i3.SecureStorageService get storage => (super.noSuchMethod( + Invocation.getter(#storage), + returnValue: _FakeSecureStorageService_1( + this, + Invocation.getter(#storage), + ), + returnValueForMissingStub: _FakeSecureStorageService_1( + this, + Invocation.getter(#storage), + ), + ) as _i3.SecureStorageService); + + @override + bool get previousConnection => (super.noSuchMethod( + Invocation.getter(#previousConnection), + returnValue: false, + returnValueForMissingStub: false, + ) as bool); + + @override + _i7.Future getBatteryLevel() => (super.noSuchMethod( + Invocation.method( + #getBatteryLevel, + [], + ), + returnValue: _i7.Future.value(0), + returnValueForMissingStub: _i7.Future.value(0), + ) as _i7.Future); + + @override + _i7.Future userAuthenticated() => (super.noSuchMethod( + Invocation.method( + #userAuthenticated, + [], + ), + returnValue: _i7.Future.value(false), + returnValueForMissingStub: _i7.Future.value(false), + ) as _i7.Future); + + @override + _i7.Future checkConnection() => (super.noSuchMethod( + Invocation.method( + #checkConnection, + [], + ), + returnValue: _i7.Future.value(false), + returnValueForMissingStub: _i7.Future.value(false), + ) as _i7.Future); + + @override + _i7.Future getAvailableStorage() => (super.noSuchMethod( + Invocation.method( + #getAvailableStorage, + [], + ), + returnValue: _i7.Future.value(0), + returnValueForMissingStub: _i7.Future.value(0), + ) as _i7.Future); + + @override + _i7.Future checkAndUpdate() => (super.noSuchMethod( + Invocation.method( + #checkAndUpdate, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); +} + +/// A class which mocks [PermissionHandlerService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockPermissionHandlerService extends _i1.Mock + implements _i15.PermissionHandlerService { + @override + _i7.Future<_i16.PermissionStatus> requestPermission( + _i16.Permission? requestedPermission) => + (super.noSuchMethod( + Invocation.method( + #requestPermission, + [requestedPermission], + ), + returnValue: _i7.Future<_i16.PermissionStatus>.value( + _i16.PermissionStatus.denied), + returnValueForMissingStub: _i7.Future<_i16.PermissionStatus>.value( + _i16.PermissionStatus.denied), + ) as _i7.Future<_i16.PermissionStatus>); + + @override + _i7.Future<_i16.PermissionStatus> request(_i16.Permission? permission) => + (super.noSuchMethod( + Invocation.method( + #request, + [permission], + ), + returnValue: _i7.Future<_i16.PermissionStatus>.value( + _i16.PermissionStatus.denied), + returnValueForMissingStub: _i7.Future<_i16.PermissionStatus>.value( + _i16.PermissionStatus.denied), + ) as _i7.Future<_i16.PermissionStatus>); +} + +/// A class which mocks [ImagePickerService]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockImagePickerService extends _i1.Mock + implements _i17.ImagePickerService { + @override + _i7.Future gallery() => (super.noSuchMethod( + Invocation.method( + #gallery, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); + + @override + _i7.Future camera() => (super.noSuchMethod( + Invocation.method( + #camera, + [], + ), + returnValue: _i7.Future.value(), + returnValueForMissingStub: _i7.Future.value(), + ) as _i7.Future); +} diff --git a/test/viewmodels/failure_viewmodel_test.dart b/test/services/api_service_test.dart similarity index 85% rename from test/viewmodels/failure_viewmodel_test.dart rename to test/services/api_service_test.dart index d06419f..93e9612 100644 --- a/test/viewmodels/failure_viewmodel_test.dart +++ b/test/services/api_service_test.dart @@ -4,7 +4,7 @@ import 'package:yimaru_app/app/app.locator.dart'; import '../helpers/test_helpers.dart'; void main() { - group('FailureViewModel Tests -', () { + group('ApiServiceTest -', () { setUp(() => registerServices()); tearDown(() => locator.reset()); }); diff --git a/test/viewmodels/learn_lesson_viewmodel_test.dart b/test/services/authentication_service_test.dart similarity index 83% rename from test/viewmodels/learn_lesson_viewmodel_test.dart rename to test/services/authentication_service_test.dart index 1056224..a06da40 100644 --- a/test/viewmodels/learn_lesson_viewmodel_test.dart +++ b/test/services/authentication_service_test.dart @@ -4,7 +4,7 @@ import 'package:yimaru_app/app/app.locator.dart'; import '../helpers/test_helpers.dart'; void main() { - group('LearnLessonViewModel Tests -', () { + group('AuthenticationServiceTest -', () { setUp(() => registerServices()); tearDown(() => locator.reset()); }); diff --git a/test/services/dio_service_test.dart b/test/services/dio_service_test.dart new file mode 100644 index 0000000..0651d4c --- /dev/null +++ b/test/services/dio_service_test.dart @@ -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('DioServiceTest -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/services/permission_handler_service_test.dart b/test/services/permission_handler_service_test.dart new file mode 100644 index 0000000..061b23b --- /dev/null +++ b/test/services/permission_handler_service_test.dart @@ -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('PermissionHandlerServiceTest -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/services/secure_storage_service_test.dart b/test/services/secure_storage_service_test.dart new file mode 100644 index 0000000..d6f4985 --- /dev/null +++ b/test/services/secure_storage_service_test.dart @@ -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('SecureStorageServiceTest -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/services/status_checker_service_test.dart b/test/services/status_checker_service_test.dart new file mode 100644 index 0000000..0460b20 --- /dev/null +++ b/test/services/status_checker_service_test.dart @@ -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()); + }); +} diff --git a/test/viewmodels/account_privacy_viewmodel_test.dart b/test/viewmodels/account_privacy_viewmodel_test.dart new file mode 100644 index 0000000..d687122 --- /dev/null +++ b/test/viewmodels/account_privacy_viewmodel_test.dart @@ -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('AccountPrivacyViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/assessment_viewmodel_test.dart b/test/viewmodels/assessment_viewmodel_test.dart new file mode 100644 index 0000000..e39ce4d --- /dev/null +++ b/test/viewmodels/assessment_viewmodel_test.dart @@ -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()); + }); +} diff --git a/test/viewmodels/call_support_viewmodel_test.dart b/test/viewmodels/call_support_viewmodel_test.dart new file mode 100644 index 0000000..52150a2 --- /dev/null +++ b/test/viewmodels/call_support_viewmodel_test.dart @@ -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('CallSupportViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/downloads_viewmodel_test.dart b/test/viewmodels/downloads_viewmodel_test.dart new file mode 100644 index 0000000..342bdcd --- /dev/null +++ b/test/viewmodels/downloads_viewmodel_test.dart @@ -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('DownloadsViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/full_name_view_viewmodel_test.dart b/test/viewmodels/full_name_view_viewmodel_test.dart new file mode 100644 index 0000000..c33d474 --- /dev/null +++ b/test/viewmodels/full_name_view_viewmodel_test.dart @@ -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('FullNameViewViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/home_viewmodel_test.dart b/test/viewmodels/home_viewmodel_test.dart new file mode 100644 index 0000000..0c5d802 --- /dev/null +++ b/test/viewmodels/home_viewmodel_test.dart @@ -0,0 +1,36 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:yimaru_app/app/app.bottomsheets.dart'; +import 'package:yimaru_app/app/app.locator.dart'; +import 'package:yimaru_app/ui/common/app_strings.dart'; +import 'package:yimaru_app/ui/views/home/home_viewmodel.dart'; + +import '../helpers/test_helpers.dart'; + +void main() { + HomeViewModel getModel() => HomeViewModel(); + + group('HomeViewmodelTest -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + + group('showBottomSheet -', () { + test( + 'When called, should show custom bottom sheet using notice variant', + () { + final bottomSheetService = getAndRegisterBottomSheetService(); + + final model = getModel(); + model.showBottomSheet(); + verify( + bottomSheetService.showCustomSheet( + variant: BottomSheetType.notice, + title: ksHomeBottomSheetTitle, + description: ksHomeBottomSheetDescription, + ), + ); + }, + ); + }); + }); +} diff --git a/test/viewmodels/language_viewmodel_test.dart b/test/viewmodels/language_viewmodel_test.dart new file mode 100644 index 0000000..0b8735a --- /dev/null +++ b/test/viewmodels/language_viewmodel_test.dart @@ -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('LanguageViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/learn_level_viewmodel_test.dart b/test/viewmodels/learn_level_viewmodel_test.dart new file mode 100644 index 0000000..5d97e54 --- /dev/null +++ b/test/viewmodels/learn_level_viewmodel_test.dart @@ -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('LearnLevelViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/learn_module_viewmodel_test.dart b/test/viewmodels/learn_module_viewmodel_test.dart new file mode 100644 index 0000000..0080f51 --- /dev/null +++ b/test/viewmodels/learn_module_viewmodel_test.dart @@ -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('LearnModuleViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/learn_viewmodel_test.dart b/test/viewmodels/learn_viewmodel_test.dart new file mode 100644 index 0000000..cf11c9c --- /dev/null +++ b/test/viewmodels/learn_viewmodel_test.dart @@ -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('LearnViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/login_viewmodel_test.dart b/test/viewmodels/login_viewmodel_test.dart new file mode 100644 index 0000000..8ff6466 --- /dev/null +++ b/test/viewmodels/login_viewmodel_test.dart @@ -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('LoginViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/onboarding_viewmodel_test.dart b/test/viewmodels/onboarding_viewmodel_test.dart new file mode 100644 index 0000000..4282556 --- /dev/null +++ b/test/viewmodels/onboarding_viewmodel_test.dart @@ -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('OnboardingViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/ongoing_progress_viewmodel_test.dart b/test/viewmodels/ongoing_progress_viewmodel_test.dart new file mode 100644 index 0000000..94a3ed4 --- /dev/null +++ b/test/viewmodels/ongoing_progress_viewmodel_test.dart @@ -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('OngoingProgressViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/privacy_policy_viewmodel_test.dart b/test/viewmodels/privacy_policy_viewmodel_test.dart new file mode 100644 index 0000000..81c404c --- /dev/null +++ b/test/viewmodels/privacy_policy_viewmodel_test.dart @@ -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('PrivacyPolicyViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/profile_detail_viewmodel_test.dart b/test/viewmodels/profile_detail_viewmodel_test.dart new file mode 100644 index 0000000..a1a9504 --- /dev/null +++ b/test/viewmodels/profile_detail_viewmodel_test.dart @@ -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('ProfileDetailViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/profile_viewmodel_test.dart b/test/viewmodels/profile_viewmodel_test.dart new file mode 100644 index 0000000..c72bc93 --- /dev/null +++ b/test/viewmodels/profile_viewmodel_test.dart @@ -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('ProfileViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/progress_viewmodel_test.dart b/test/viewmodels/progress_viewmodel_test.dart new file mode 100644 index 0000000..6f79cf5 --- /dev/null +++ b/test/viewmodels/progress_viewmodel_test.dart @@ -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('ProgressViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/register_viewmodel_test.dart b/test/viewmodels/register_viewmodel_test.dart new file mode 100644 index 0000000..78e03a5 --- /dev/null +++ b/test/viewmodels/register_viewmodel_test.dart @@ -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('RegisterViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/settings_viewmodel_test.dart b/test/viewmodels/settings_viewmodel_test.dart new file mode 100644 index 0000000..aa5a11d --- /dev/null +++ b/test/viewmodels/settings_viewmodel_test.dart @@ -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('SettingsViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/startup_viewmodel_test.dart b/test/viewmodels/startup_viewmodel_test.dart new file mode 100644 index 0000000..e560a6c --- /dev/null +++ b/test/viewmodels/startup_viewmodel_test.dart @@ -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('StartupViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/support_viewmodel_test.dart b/test/viewmodels/support_viewmodel_test.dart new file mode 100644 index 0000000..260dc47 --- /dev/null +++ b/test/viewmodels/support_viewmodel_test.dart @@ -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('SupportViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/telegram_support_viewmodel_test.dart b/test/viewmodels/telegram_support_viewmodel_test.dart new file mode 100644 index 0000000..1605ed4 --- /dev/null +++ b/test/viewmodels/telegram_support_viewmodel_test.dart @@ -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('TelegramSupportViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/terms_and_conditions_viewmodel_test.dart b/test/viewmodels/terms_and_conditions_viewmodel_test.dart new file mode 100644 index 0000000..7da4d4a --- /dev/null +++ b/test/viewmodels/terms_and_conditions_viewmodel_test.dart @@ -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('TermsAndConditionsViewModel Tests -', () { + setUp(() => registerServices()); + tearDown(() => locator.reset()); + }); +} diff --git a/test/viewmodels/welcome_viewmodel_test.dart b/test/viewmodels/welcome_viewmodel_test.dart new file mode 100644 index 0000000..4b59f78 --- /dev/null +++ b/test/viewmodels/welcome_viewmodel_test.dart @@ -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()); + }); +} diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8ac9fc6..0f5385e 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -8,13 +8,19 @@ #include #include +#include #include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { BatteryPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("BatteryPlusWindowsPlugin")); ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index e1ff19b..2c88dbb 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -5,7 +5,9 @@ list(APPEND FLUTTER_PLUGIN_LIST battery_plus connectivity_plus + file_selector_windows flutter_secure_storage_windows + permission_handler_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST