From d02b97e1c135312e367f32ad0ad844f148f6c389 Mon Sep 17 00:00:00 2001 From: xpwmaosldk Date: Sun, 26 Jun 2022 03:46:51 +0900 Subject: [PATCH] Add service provider (#250) * optimize android side gradle settings * android minsdk back to 21 * remove unused package, update linter and fix lint error * clean code of 'shared module' with offical dart style guide * restore uploadProfileImage method in UserService * add service provider * fix searchFocusNode init error --- .../asset_viewer/views/image_viewer_page.dart | 55 +++++++++++-------- .../asset_viewer/views/video_viewer_page.dart | 24 +++++--- .../backup/providers/backup.provider.dart | 51 ++++++++--------- .../backup/services/backup.service.dart | 32 ++++++++--- .../upload_profile_image.provider.dart | 26 ++++++--- .../modules/home/services/asset.service.dart | 22 ++++++-- .../providers/authentication.provider.dart | 36 +++++++----- .../providers/search_page_state.provider.dart | 10 ++-- .../search_result_page.provider.dart | 37 +++++++++---- .../search/services/search.service.dart | 16 ++++-- .../lib/modules/search/views/search_page.dart | 2 +- .../providers/album_viewer.provider.dart | 14 +++-- .../providers/shared_album.provider.dart | 9 +-- .../suggested_shared_users.provider.dart | 5 +- .../services/shared_album.service.dart | 7 ++- .../sharing/views/album_viewer_page.dart | 9 ++- .../views/select_user_for_sharing_page.dart | 50 +++++++++++------ .../lib/shared/providers/asset.provider.dart | 7 +-- .../providers/server_info.provider.dart | 6 +- .../shared/services/device_info.service.dart | 4 ++ .../services/local_storage.service.dart | 3 + .../lib/shared/services/network.service.dart | 6 +- .../shared/services/server_info.service.dart | 7 ++- mobile/lib/shared/services/user.service.dart | 7 ++- 24 files changed, 288 insertions(+), 157 deletions(-) diff --git a/mobile/lib/modules/asset_viewer/views/image_viewer_page.dart b/mobile/lib/modules/asset_viewer/views/image_viewer_page.dart index 8954b987b6..a59fc825ce 100644 --- a/mobile/lib/modules/asset_viewer/views/image_viewer_page.dart +++ b/mobile/lib/modules/asset_viewer/views/image_viewer_page.dart @@ -20,20 +20,26 @@ class ImageViewerPage extends HookConsumerWidget { final String heroTag; final String thumbnailUrl; final ImmichAsset asset; - final AssetService _assetService = AssetService(); + ImmichAssetWithExif? assetDetail; - ImageViewerPage( - {Key? key, required this.imageUrl, required this.heroTag, required this.thumbnailUrl, required this.asset}) - : super(key: key); + ImageViewerPage({ + Key? key, + required this.imageUrl, + required this.heroTag, + required this.thumbnailUrl, + required this.asset, + }) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final downloadAssetStatus = ref.watch(imageViewerStateProvider).downloadAssetStatus; + final downloadAssetStatus = + ref.watch(imageViewerStateProvider).downloadAssetStatus; var box = Hive.box(userInfoBox); getAssetExif() async { - assetDetail = await _assetService.getAssetById(asset.id); + assetDetail = + await ref.watch(assetServiceProvider).getAssetById(asset.id); } showInfo() { @@ -59,31 +65,32 @@ class ImageViewerPage extends HookConsumerWidget { asset: asset, onMoreInfoPressed: showInfo, onDownloadPressed: () { - ref.watch(imageViewerStateProvider.notifier).downloadAsset(asset, context); + ref + .watch(imageViewerStateProvider.notifier) + .downloadAsset(asset, context); }, ), body: SafeArea( - child: Stack( - children: [ - Center( - child: Hero( + child: Stack( + children: [ + Center( + child: Hero( tag: heroTag, child: RemotePhotoView( - thumbnailUrl: thumbnailUrl, - imageUrl: imageUrl, - authToken: "Bearer ${box.get(accessTokenKey)}", - onSwipeDown: () => AutoRouter.of(context).pop(), - onSwipeUp: () => showInfo(), - ) - ), + thumbnailUrl: thumbnailUrl, + imageUrl: imageUrl, + authToken: "Bearer ${box.get(accessTokenKey)}", + onSwipeDown: () => AutoRouter.of(context).pop(), + onSwipeUp: () => showInfo(), + )), + ), + if (downloadAssetStatus == DownloadAssetStatus.loading) + const Center( + child: DownloadLoadingIndicator(), ), - if (downloadAssetStatus == DownloadAssetStatus.loading) - const Center( - child: DownloadLoadingIndicator(), - ), - ], - ), + ], ), + ), ); } } diff --git a/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart b/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart index e93e83d22e..cdc60b0029 100644 --- a/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart +++ b/mobile/lib/modules/asset_viewer/views/video_viewer_page.dart @@ -21,13 +21,14 @@ class VideoViewerPage extends HookConsumerWidget { final String videoUrl; final ImmichAsset asset; ImmichAssetWithExif? assetDetail; - final AssetService _assetService = AssetService(); - VideoViewerPage({Key? key, required this.videoUrl, required this.asset}) : super(key: key); + VideoViewerPage({Key? key, required this.videoUrl, required this.asset}) + : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { - final downloadAssetStatus = ref.watch(imageViewerStateProvider).downloadAssetStatus; + final downloadAssetStatus = + ref.watch(imageViewerStateProvider).downloadAssetStatus; String jwtToken = Hive.box(userInfoBox).get(accessTokenKey); @@ -44,7 +45,8 @@ class VideoViewerPage extends HookConsumerWidget { } getAssetExif() async { - assetDetail = await _assetService.getAssetById(asset.id); + assetDetail = + await ref.watch(assetServiceProvider).getAssetById(asset.id); } useEffect(() { @@ -60,7 +62,9 @@ class VideoViewerPage extends HookConsumerWidget { showInfo(); }, onDownloadPressed: () { - ref.watch(imageViewerStateProvider.notifier).downloadAsset(asset, context); + ref + .watch(imageViewerStateProvider.notifier) + .downloadAsset(asset, context); }, ), body: SwipeDetector( @@ -93,7 +97,8 @@ class VideoThumbnailPlayer extends StatefulWidget { final String url; final String? jwtToken; - const VideoThumbnailPlayer({Key? key, required this.url, this.jwtToken}) : super(key: key); + const VideoThumbnailPlayer({Key? key, required this.url, this.jwtToken}) + : super(key: key); @override State createState() => _VideoThumbnailPlayerState(); @@ -111,8 +116,8 @@ class _VideoThumbnailPlayerState extends State { Future initializePlayer() async { try { - videoPlayerController = - VideoPlayerController.network(widget.url, httpHeaders: {"Authorization": "Bearer ${widget.jwtToken}"}); + videoPlayerController = VideoPlayerController.network(widget.url, + httpHeaders: {"Authorization": "Bearer ${widget.jwtToken}"}); await videoPlayerController.initialize(); _createChewieController(); @@ -142,7 +147,8 @@ class _VideoThumbnailPlayerState extends State { @override Widget build(BuildContext context) { - return chewieController != null && chewieController!.videoPlayerController.value.isInitialized + return chewieController != null && + chewieController!.videoPlayerController.value.isInitialized ? SizedBox( child: Chewie( controller: chewieController!, diff --git a/mobile/lib/modules/backup/providers/backup.provider.dart b/mobile/lib/modules/backup/providers/backup.provider.dart index 592781d570..e8efaa0068 100644 --- a/mobile/lib/modules/backup/providers/backup.provider.dart +++ b/mobile/lib/modules/backup/providers/backup.provider.dart @@ -7,13 +7,14 @@ import 'package:immich_mobile/modules/backup/models/available_album.model.dart'; import 'package:immich_mobile/modules/backup/models/backup_state.model.dart'; import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart'; import 'package:immich_mobile/modules/backup/services/backup.service.dart'; +import 'package:immich_mobile/modules/login/models/authentication_state.model.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; import 'package:immich_mobile/shared/models/server_info.model.dart'; import 'package:immich_mobile/shared/services/server_info.service.dart'; import 'package:photo_manager/photo_manager.dart'; class BackupNotifier extends StateNotifier { - BackupNotifier({this.ref}) + BackupNotifier(this._backupService, this._serverInfoService, this._authState) : super( BackUpState( backupProgress: BackUpProgressEnum.idle, @@ -37,9 +38,9 @@ class BackupNotifier extends StateNotifier { ), ); - Ref? ref; - final BackupService _backupService = BackupService(); - final ServerInfoService _serverInfoService = ServerInfoService(); + final BackupService _backupService; + final ServerInfoService _serverInfoService; + final AuthenticationState _authState; /// /// UI INTERACTION @@ -338,38 +339,38 @@ class BackupNotifier extends StateNotifier { } void resumeBackup() { - var authState = ref?.read(authenticationProvider); - // Check if user is login var accessKey = Hive.box(userInfoBox).get(accessTokenKey); // User has been logged out return - if (authState != null) { - if (accessKey == null || !authState.isAuthenticated) { - debugPrint("[resumeBackup] not authenticated - abort"); + if (accessKey == null || !_authState.isAuthenticated) { + debugPrint("[resumeBackup] not authenticated - abort"); + return; + } + + // Check if this device is enable backup by the user + if ((_authState.deviceInfo.deviceId == _authState.deviceId) && + _authState.deviceInfo.isAutoBackup) { + // check if backup is alreayd in process - then return + if (state.backupProgress == BackUpProgressEnum.inProgress) { + debugPrint("[resumeBackup] Backup is already in progress - abort"); return; } - // Check if this device is enable backup by the user - if ((authState.deviceInfo.deviceId == authState.deviceId) && - authState.deviceInfo.isAutoBackup) { - // check if backup is alreayd in process - then return - if (state.backupProgress == BackUpProgressEnum.inProgress) { - debugPrint("[resumeBackup] Backup is already in progress - abort"); - return; - } - - // Run backup - debugPrint("[resumeBackup] Start back up"); - startBackupProcess(); - } - - return; + // Run backup + debugPrint("[resumeBackup] Start back up"); + startBackupProcess(); } + + return; } } final backupProvider = StateNotifierProvider((ref) { - return BackupNotifier(ref: ref); + return BackupNotifier( + ref.watch(backupServiceProvider), + ref.watch(serverInfoServiceProvider), + ref.watch(authenticationProvider), + ); }); diff --git a/mobile/lib/modules/backup/services/backup.service.dart b/mobile/lib/modules/backup/services/backup.service.dart index 5d2f50fca7..3a0e223bb5 100644 --- a/mobile/lib/modules/backup/services/backup.service.dart +++ b/mobile/lib/modules/backup/services/backup.service.dart @@ -5,6 +5,7 @@ import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; import 'package:immich_mobile/shared/services/network.service.dart'; import 'package:immich_mobile/shared/models/device_info.model.dart'; @@ -14,20 +15,28 @@ import 'package:http_parser/http_parser.dart'; import 'package:path/path.dart' as p; import 'package:cancellation_token_http/http.dart' as http; +final backupServiceProvider = + Provider((ref) => BackupService(ref.watch(networkServiceProvider))); + class BackupService { - final NetworkService _networkService = NetworkService(); + final NetworkService _networkService; + BackupService(this._networkService); Future> getDeviceBackupAsset() async { String deviceId = Hive.box(userInfoBox).get(deviceIdKey); - Response response = await _networkService.getRequest(url: "asset/$deviceId"); + Response response = + await _networkService.getRequest(url: "asset/$deviceId"); List result = jsonDecode(response.toString()); return result.cast(); } - backupAsset(Set assetList, http.CancellationToken cancelToken, - Function(String, String) singleAssetDoneCb, Function(int, int) uploadProgress) async { + backupAsset( + Set assetList, + http.CancellationToken cancelToken, + Function(String, String) singleAssetDoneCb, + Function(int, int) uploadProgress) async { String deviceId = Hive.box(userInfoBox).get(deviceIdKey); String savedEndpoint = Hive.box(userInfoBox).get(serverEndpointKey); File? file; @@ -44,7 +53,8 @@ class BackupService { if (file != null) { String originalFileName = await entity.titleAsync; - String fileNameWithoutPath = originalFileName.toString().split(".")[0]; + String fileNameWithoutPath = + originalFileName.toString().split(".")[0]; var fileExtension = p.extension(file.path); var mimeType = FileHelper.getMimeType(file.path); var fileStream = file.openRead(); @@ -60,7 +70,8 @@ class BackupService { ); // Build thumbnail multipart data - var thumbnailData = await entity.thumbnailDataWithSize(const ThumbnailSize(1440, 2560)); + var thumbnailData = await entity + .thumbnailDataWithSize(const ThumbnailSize(1440, 2560)); if (thumbnailData != null) { thumbnailUploadData = http.MultipartFile.fromBytes( "thumbnailData", @@ -75,8 +86,10 @@ class BackupService { var box = Hive.box(userInfoBox); - var req = MultipartRequest('POST', Uri.parse('$savedEndpoint/asset/upload'), - onProgress: ((bytes, totalBytes) => uploadProgress(bytes, totalBytes))); + var req = MultipartRequest( + 'POST', Uri.parse('$savedEndpoint/asset/upload'), + onProgress: ((bytes, totalBytes) => + uploadProgress(bytes, totalBytes))); req.headers["Authorization"] = "Bearer ${box.get(accessTokenKey)}"; req.fields['deviceAssetId'] = entity.id; @@ -126,7 +139,8 @@ class BackupService { } } - Future setAutoBackup(bool status, String deviceId, String deviceType) async { + Future setAutoBackup( + bool status, String deviceId, String deviceType) async { var res = await _networkService.patchRequest(url: 'device-info', data: { "isAutoBackup": status, "deviceId": deviceId, diff --git a/mobile/lib/modules/home/providers/upload_profile_image.provider.dart b/mobile/lib/modules/home/providers/upload_profile_image.provider.dart index d0f3103c56..f8d21d782c 100644 --- a/mobile/lib/modules/home/providers/upload_profile_image.provider.dart +++ b/mobile/lib/modules/home/providers/upload_profile_image.provider.dart @@ -50,37 +50,46 @@ class UploadProfileImageState { String toJson() => json.encode(toMap()); - factory UploadProfileImageState.fromJson(String source) => UploadProfileImageState.fromMap(json.decode(source)); + factory UploadProfileImageState.fromJson(String source) => + UploadProfileImageState.fromMap(json.decode(source)); @override - String toString() => 'UploadProfileImageState(status: $status, profileImagePath: $profileImagePath)'; + String toString() => + 'UploadProfileImageState(status: $status, profileImagePath: $profileImagePath)'; @override bool operator ==(Object other) { if (identical(this, other)) return true; - return other is UploadProfileImageState && other.status == status && other.profileImagePath == profileImagePath; + return other is UploadProfileImageState && + other.status == status && + other.profileImagePath == profileImagePath; } @override int get hashCode => status.hashCode ^ profileImagePath.hashCode; } -class UploadProfileImageNotifier extends StateNotifier { - UploadProfileImageNotifier() +class UploadProfileImageNotifier + extends StateNotifier { + UploadProfileImageNotifier(this._userSErvice) : super(UploadProfileImageState( profileImagePath: '', status: UploadProfileStatus.idle, )); + final UserService _userSErvice; + Future upload(XFile file) async { state = state.copyWith(status: UploadProfileStatus.loading); - var res = await UserService().uploadProfileImage(file); + var res = await _userSErvice.uploadProfileImage(file); if (res != null) { debugPrint("Succesfully upload profile image"); - state = state.copyWith(status: UploadProfileStatus.success, profileImagePath: res.profileImagePath); + state = state.copyWith( + status: UploadProfileStatus.success, + profileImagePath: res.profileImagePath); return true; } @@ -90,4 +99,5 @@ class UploadProfileImageNotifier extends StateNotifier } final uploadProfileImageProvider = - StateNotifierProvider(((ref) => UploadProfileImageNotifier())); + StateNotifierProvider( + ((ref) => UploadProfileImageNotifier(ref.watch(userServiceProvider)))); diff --git a/mobile/lib/modules/home/services/asset.service.dart b/mobile/lib/modules/home/services/asset.service.dart index 025acbe64e..16546f1dc7 100644 --- a/mobile/lib/modules/home/services/asset.service.dart +++ b/mobile/lib/modules/home/services/asset.service.dart @@ -1,21 +1,27 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/modules/home/models/delete_asset_response.model.dart'; import 'package:immich_mobile/modules/home/models/get_all_asset_response.model.dart'; import 'package:immich_mobile/shared/models/immich_asset.model.dart'; import 'package:immich_mobile/shared/models/immich_asset_with_exif.model.dart'; import 'package:immich_mobile/shared/services/network.service.dart'; +final assetServiceProvider = + Provider((ref) => AssetService(ref.watch(networkServiceProvider))); + class AssetService { - final NetworkService _networkService = NetworkService(); + final NetworkService _networkService; + AssetService(this._networkService); Future?> getAllAsset() async { var res = await _networkService.getRequest(url: "asset/"); try { List decodedData = jsonDecode(res.toString()); - List result = List.from(decodedData.map((a) => ImmichAsset.fromMap(a))); + List result = + List.from(decodedData.map((a) => ImmichAsset.fromMap(a))); return result; } catch (e) { debugPrint("Error getAllAsset ${e.toString()}"); @@ -62,7 +68,8 @@ class AssetService { List decodedData = jsonDecode(res.toString()); - List result = List.from(decodedData.map((a) => ImmichAsset.fromMap(a))); + List result = + List.from(decodedData.map((a) => ImmichAsset.fromMap(a))); if (result.isNotEmpty) { return result; } @@ -90,7 +97,8 @@ class AssetService { } } - Future?> deleteAssets(Set deleteAssets) async { + Future?> deleteAssets( + Set deleteAssets) async { try { var payload = []; @@ -98,11 +106,13 @@ class AssetService { payload.add(asset.id); } - var res = await _networkService.deleteRequest(url: "asset/", data: {"ids": payload}); + var res = await _networkService + .deleteRequest(url: "asset/", data: {"ids": payload}); List decodedData = jsonDecode(res.toString()); - List result = List.from(decodedData.map((a) => DeleteAssetResponse.fromMap(a))); + List result = + List.from(decodedData.map((a) => DeleteAssetResponse.fromMap(a))); return result; } catch (e) { diff --git a/mobile/lib/modules/login/providers/authentication.provider.dart b/mobile/lib/modules/login/providers/authentication.provider.dart index df475b36d5..014912bd72 100644 --- a/mobile/lib/modules/login/providers/authentication.provider.dart +++ b/mobile/lib/modules/login/providers/authentication.provider.dart @@ -12,7 +12,8 @@ import 'package:immich_mobile/shared/services/network.service.dart'; import 'package:immich_mobile/shared/models/device_info.model.dart'; class AuthenticationNotifier extends StateNotifier { - AuthenticationNotifier(this.ref) + AuthenticationNotifier( + this._deviceInfoService, this._backupService, this._networkService) : super( AuthenticationState( deviceId: "", @@ -37,12 +38,12 @@ class AuthenticationNotifier extends StateNotifier { ), ); - final Ref ref; - final DeviceInfoService _deviceInfoService = DeviceInfoService(); - final BackupService _backupService = BackupService(); - final NetworkService _networkService = NetworkService(); + final DeviceInfoService _deviceInfoService; + final BackupService _backupService; + final NetworkService _networkService; - Future login(String email, String password, String serverEndpoint, bool isSavedLoginInfo) async { + Future login(String email, String password, String serverEndpoint, + bool isSavedLoginInfo) async { // Store server endpoint to Hive and test endpoint if (serverEndpoint[serverEndpoint.length - 1] == "/") { var validUrl = serverEndpoint.substring(0, serverEndpoint.length - 1); @@ -71,7 +72,8 @@ class AuthenticationNotifier extends StateNotifier { // Make sign-in request try { - Response res = await _networkService.postRequest(url: 'auth/login', data: {'email': email, 'password': password}); + Response res = await _networkService.postRequest( + url: 'auth/login', data: {'email': email, 'password': password}); var payload = LogInReponse.fromJson(res.toString()); @@ -99,7 +101,8 @@ class AuthenticationNotifier extends StateNotifier { serverUrl: Hive.box(userInfoBox).get(serverEndpointKey)), ); } else { - Hive.box(hiveLoginInfoBox).delete(savedLoginInfoKey); + Hive.box(hiveLoginInfoBox) + .delete(savedLoginInfoKey); } } catch (e) { return false; @@ -107,8 +110,9 @@ class AuthenticationNotifier extends StateNotifier { // Register device info try { - Response res = await _networkService - .postRequest(url: 'device-info', data: {'deviceId': state.deviceId, 'deviceType': state.deviceType}); + Response res = await _networkService.postRequest( + url: 'device-info', + data: {'deviceId': state.deviceId, 'deviceType': state.deviceType}); DeviceInfoRemote deviceInfo = DeviceInfoRemote.fromJson(res.toString()); state = state.copyWith(deviceInfo: deviceInfo); @@ -151,7 +155,8 @@ class AuthenticationNotifier extends StateNotifier { var deviceId = deviceInfo["deviceId"]; var deviceType = deviceInfo["deviceType"]; - DeviceInfoRemote deviceInfoRemote = await _backupService.setAutoBackup(backupState, deviceId, deviceType); + DeviceInfoRemote deviceInfoRemote = + await _backupService.setAutoBackup(backupState, deviceId, deviceType); state = state.copyWith(deviceInfo: deviceInfoRemote); } @@ -160,6 +165,11 @@ class AuthenticationNotifier extends StateNotifier { } } -final authenticationProvider = StateNotifierProvider((ref) { - return AuthenticationNotifier(ref); +final authenticationProvider = + StateNotifierProvider((ref) { + return AuthenticationNotifier( + ref.watch(deviceInfoServiceProvider), + ref.watch(backupServiceProvider), + ref.watch(networkServiceProvider), + ); }); diff --git a/mobile/lib/modules/search/providers/search_page_state.provider.dart b/mobile/lib/modules/search/providers/search_page_state.provider.dart index 6611f12736..87b6c88bc0 100644 --- a/mobile/lib/modules/search/providers/search_page_state.provider.dart +++ b/mobile/lib/modules/search/providers/search_page_state.provider.dart @@ -6,7 +6,7 @@ import 'package:immich_mobile/modules/search/models/search_page_state.model.dart import 'package:immich_mobile/modules/search/services/search.service.dart'; class SearchPageStateNotifier extends StateNotifier { - SearchPageStateNotifier() + SearchPageStateNotifier(this._searchService) : super( SearchPageState( searchTerm: "", @@ -16,7 +16,7 @@ class SearchPageStateNotifier extends StateNotifier { ), ); - final SearchService _searchService = SearchService(); + final SearchService _searchService; void enableSearch() { state = state.copyWith(isSearchEnabled: true); @@ -54,12 +54,12 @@ class SearchPageStateNotifier extends StateNotifier { final searchPageStateProvider = StateNotifierProvider((ref) { - return SearchPageStateNotifier(); + return SearchPageStateNotifier(ref.watch(searchServiceProvider)); }); final getCuratedLocationProvider = FutureProvider.autoDispose>((ref) async { - final SearchService searchService = SearchService(); + final SearchService searchService = ref.watch(searchServiceProvider); var curatedLocation = await searchService.getCuratedLocation(); if (curatedLocation != null) { @@ -71,7 +71,7 @@ final getCuratedLocationProvider = final getCuratedObjectProvider = FutureProvider.autoDispose>((ref) async { - final SearchService searchService = SearchService(); + final SearchService searchService = ref.watch(searchServiceProvider); var curatedObject = await searchService.getCuratedObjects(); if (curatedObject != null) { diff --git a/mobile/lib/modules/search/providers/search_result_page.provider.dart b/mobile/lib/modules/search/providers/search_result_page.provider.dart index a27033827d..eb9f9c3daf 100644 --- a/mobile/lib/modules/search/providers/search_result_page.provider.dart +++ b/mobile/lib/modules/search/providers/search_result_page.provider.dart @@ -7,31 +7,48 @@ import 'package:immich_mobile/shared/models/immich_asset.model.dart'; import 'package:intl/intl.dart'; class SearchResultPageNotifier extends StateNotifier { - SearchResultPageNotifier() - : super(SearchResultPageState(searchResult: [], isError: false, isLoading: true, isSuccess: false)); + SearchResultPageNotifier(this._searchService) + : super( + SearchResultPageState( + searchResult: [], + isError: false, + isLoading: true, + isSuccess: false, + ), + ); - final SearchService _searchService = SearchService(); + final SearchService _searchService; void search(String searchTerm) async { - state = state.copyWith(searchResult: [], isError: false, isLoading: true, isSuccess: false); + state = state.copyWith( + searchResult: [], isError: false, isLoading: true, isSuccess: false); List? assets = await _searchService.searchAsset(searchTerm); if (assets != null) { - state = state.copyWith(searchResult: assets, isError: false, isLoading: false, isSuccess: true); + state = state.copyWith( + searchResult: assets, + isError: false, + isLoading: false, + isSuccess: true); } else { - state = state.copyWith(searchResult: [], isError: true, isLoading: false, isSuccess: false); + state = state.copyWith( + searchResult: [], isError: true, isLoading: false, isSuccess: false); } } } -final searchResultPageProvider = StateNotifierProvider((ref) { - return SearchResultPageNotifier(); +final searchResultPageProvider = + StateNotifierProvider( + (ref) { + return SearchResultPageNotifier(ref.watch(searchServiceProvider)); }); final searchResultGroupByDateTimeProvider = StateProvider((ref) { var assets = ref.watch(searchResultPageProvider).searchResult; - assets.sortByCompare((e) => DateTime.parse(e.createdAt), (a, b) => b.compareTo(a)); - return assets.groupListsBy((element) => DateFormat('y-MM-dd').format(DateTime.parse(element.createdAt))); + assets.sortByCompare( + (e) => DateTime.parse(e.createdAt), (a, b) => b.compareTo(a)); + return assets.groupListsBy((element) => + DateFormat('y-MM-dd').format(DateTime.parse(element.createdAt))); }); diff --git a/mobile/lib/modules/search/services/search.service.dart b/mobile/lib/modules/search/services/search.service.dart index a29d6f0c64..06e6bab6f1 100644 --- a/mobile/lib/modules/search/services/search.service.dart +++ b/mobile/lib/modules/search/services/search.service.dart @@ -1,13 +1,18 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/modules/search/models/curated_location.model.dart'; import 'package:immich_mobile/modules/search/models/curated_object.model.dart'; import 'package:immich_mobile/shared/models/immich_asset.model.dart'; import 'package:immich_mobile/shared/services/network.service.dart'; +final searchServiceProvider = + Provider((ref) => SearchService(ref.watch(networkServiceProvider))); + class SearchService { - final NetworkService _networkService = NetworkService(); + final NetworkService _networkService; + SearchService(this._networkService); Future?> getUserSuggestedSearchTerms() async { try { @@ -30,7 +35,8 @@ class SearchService { List decodedData = jsonDecode(res.toString()); - List result = List.from(decodedData.map((a) => ImmichAsset.fromMap(a))); + List result = + List.from(decodedData.map((a) => ImmichAsset.fromMap(a))); return result; } catch (e) { @@ -45,7 +51,8 @@ class SearchService { List decodedData = jsonDecode(res.toString()); - List result = List.from(decodedData.map((a) => CuratedLocation.fromMap(a))); + List result = + List.from(decodedData.map((a) => CuratedLocation.fromMap(a))); return result; } catch (e) { @@ -60,7 +67,8 @@ class SearchService { List decodedData = jsonDecode(res.toString()); - List result = List.from(decodedData.map((a) => CuratedObject.fromMap(a))); + List result = + List.from(decodedData.map((a) => CuratedObject.fromMap(a))); return result; } catch (e) { diff --git a/mobile/lib/modules/search/views/search_page.dart b/mobile/lib/modules/search/views/search_page.dart index e47074cee0..4b236bc065 100644 --- a/mobile/lib/modules/search/views/search_page.dart +++ b/mobile/lib/modules/search/views/search_page.dart @@ -18,7 +18,7 @@ import 'package:immich_mobile/utils/capitalize_first_letter.dart'; class SearchPage extends HookConsumerWidget { SearchPage({Key? key}) : super(key: key); - late FocusNode searchFocusNode; + FocusNode searchFocusNode = FocusNode(); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/mobile/lib/modules/sharing/providers/album_viewer.provider.dart b/mobile/lib/modules/sharing/providers/album_viewer.provider.dart index f32e43d8a8..4e64b8eb5b 100644 --- a/mobile/lib/modules/sharing/providers/album_viewer.provider.dart +++ b/mobile/lib/modules/sharing/providers/album_viewer.provider.dart @@ -4,7 +4,8 @@ import 'package:immich_mobile/modules/sharing/providers/shared_album.provider.da import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart'; class AlbumViewerNotifier extends StateNotifier { - AlbumViewerNotifier(this.ref) : super(AlbumViewerPageState(editTitleText: "", isEditAlbum: false)); + AlbumViewerNotifier(this.ref) + : super(AlbumViewerPageState(editTitleText: "", isEditAlbum: false)); final Ref ref; @@ -28,10 +29,12 @@ class AlbumViewerNotifier extends StateNotifier { state = state.copyWith(editTitleText: "", isEditAlbum: false); } - Future changeAlbumTitle(String albumId, String ownerId, String newAlbumTitle) async { - SharedAlbumService service = SharedAlbumService(); + Future changeAlbumTitle( + String albumId, String ownerId, String newAlbumTitle) async { + SharedAlbumService service = ref.watch(sharedAlbumServiceProvider); - bool isSuccess = await service.changeTitleAlbum(albumId, ownerId, newAlbumTitle); + bool isSuccess = + await service.changeTitleAlbum(albumId, ownerId, newAlbumTitle); if (isSuccess) { state = state.copyWith(editTitleText: "", isEditAlbum: false); @@ -45,6 +48,7 @@ class AlbumViewerNotifier extends StateNotifier { } } -final albumViewerProvider = StateNotifierProvider((ref) { +final albumViewerProvider = + StateNotifierProvider((ref) { return AlbumViewerNotifier(ref); }); diff --git a/mobile/lib/modules/sharing/providers/shared_album.provider.dart b/mobile/lib/modules/sharing/providers/shared_album.provider.dart index c65d50dccd..efb3c090a7 100644 --- a/mobile/lib/modules/sharing/providers/shared_album.provider.dart +++ b/mobile/lib/modules/sharing/providers/shared_album.provider.dart @@ -3,9 +3,9 @@ import 'package:immich_mobile/modules/sharing/models/shared_album.model.dart'; import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart'; class SharedAlbumNotifier extends StateNotifier> { - SharedAlbumNotifier() : super([]); + SharedAlbumNotifier(this._sharedAlbumService) : super([]); - final SharedAlbumService _sharedAlbumService = SharedAlbumService(); + final SharedAlbumService _sharedAlbumService; getAllSharedAlbums() async { List sharedAlbums = @@ -50,12 +50,13 @@ class SharedAlbumNotifier extends StateNotifier> { final sharedAlbumProvider = StateNotifierProvider>((ref) { - return SharedAlbumNotifier(); + return SharedAlbumNotifier(ref.watch(sharedAlbumServiceProvider)); }); final sharedAlbumDetailProvider = FutureProvider.autoDispose .family((ref, albumId) async { - final SharedAlbumService sharedAlbumService = SharedAlbumService(); + final SharedAlbumService sharedAlbumService = + ref.watch(sharedAlbumServiceProvider); return await sharedAlbumService.getAlbumDetail(albumId); }); diff --git a/mobile/lib/modules/sharing/providers/suggested_shared_users.provider.dart b/mobile/lib/modules/sharing/providers/suggested_shared_users.provider.dart index 6d4646aa25..8ddc122b26 100644 --- a/mobile/lib/modules/sharing/providers/suggested_shared_users.provider.dart +++ b/mobile/lib/modules/sharing/providers/suggested_shared_users.provider.dart @@ -2,8 +2,9 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/shared/models/user.model.dart'; import 'package:immich_mobile/shared/services/user.service.dart'; -final suggestedSharedUsersProvider = FutureProvider.autoDispose>((ref) async { - UserService userService = UserService(); +final suggestedSharedUsersProvider = + FutureProvider.autoDispose>((ref) async { + UserService userService = ref.watch(userServiceProvider); return await userService.getAllUsersInfo(); }); diff --git a/mobile/lib/modules/sharing/services/shared_album.service.dart b/mobile/lib/modules/sharing/services/shared_album.service.dart index 9f42aac7f4..2327469e24 100644 --- a/mobile/lib/modules/sharing/services/shared_album.service.dart +++ b/mobile/lib/modules/sharing/services/shared_album.service.dart @@ -3,12 +3,17 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/modules/sharing/models/shared_album.model.dart'; import 'package:immich_mobile/shared/models/immich_asset.model.dart'; import 'package:immich_mobile/shared/services/network.service.dart'; +final sharedAlbumServiceProvider = + Provider((ref) => SharedAlbumService(ref.watch(networkServiceProvider))); + class SharedAlbumService { - final NetworkService _networkService = NetworkService(); + final NetworkService _networkService; + SharedAlbumService(this._networkService); Future> getAllSharedAlbum() async { try { diff --git a/mobile/lib/modules/sharing/views/album_viewer_page.dart b/mobile/lib/modules/sharing/views/album_viewer_page.dart index 662baf61a6..0a823db584 100644 --- a/mobile/lib/modules/sharing/views/album_viewer_page.dart +++ b/mobile/lib/modules/sharing/views/album_viewer_page.dart @@ -53,8 +53,10 @@ class AlbumViewerPage extends HookConsumerWidget { if (returnPayload.selectedAdditionalAsset.isNotEmpty) { ImmichLoadingOverlayController.appLoader.show(); - var isSuccess = await SharedAlbumService().addAdditionalAssetToAlbum( - returnPayload.selectedAdditionalAsset, albumId); + var isSuccess = await ref + .watch(sharedAlbumServiceProvider) + .addAdditionalAssetToAlbum( + returnPayload.selectedAdditionalAsset, albumId); if (isSuccess) { ref.refresh(sharedAlbumDetailProvider(albumId)); @@ -77,7 +79,8 @@ class AlbumViewerPage extends HookConsumerWidget { if (sharedUserIds != null) { ImmichLoadingOverlayController.appLoader.show(); - var isSuccess = await SharedAlbumService() + var isSuccess = await ref + .watch(sharedAlbumServiceProvider) .addAdditionalUserToAlbum(sharedUserIds, albumId); if (isSuccess) { diff --git a/mobile/lib/modules/sharing/views/select_user_for_sharing_page.dart b/mobile/lib/modules/sharing/views/select_user_for_sharing_page.dart index 91d7971bad..0001edd206 100644 --- a/mobile/lib/modules/sharing/views/select_user_for_sharing_page.dart +++ b/mobile/lib/modules/sharing/views/select_user_for_sharing_page.dart @@ -16,24 +16,28 @@ class SelectUserForSharingPage extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final sharedUsersList = useState>({}); - AsyncValue> suggestedShareUsers = ref.watch(suggestedSharedUsersProvider); + AsyncValue> suggestedShareUsers = + ref.watch(suggestedSharedUsersProvider); _createSharedAlbum() async { - var isSuccess = await SharedAlbumService().createSharedAlbum( - ref.watch(albumTitleProvider), - ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum, - sharedUsersList.value.map((userInfo) => userInfo.id).toList(), - ); + var isSuccess = + await ref.watch(sharedAlbumServiceProvider).createSharedAlbum( + ref.watch(albumTitleProvider), + ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum, + sharedUsersList.value.map((userInfo) => userInfo.id).toList(), + ); if (isSuccess) { await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums(); ref.watch(assetSelectionProvider.notifier).removeAll(); ref.watch(albumTitleProvider.notifier).clearAlbumTitle(); - AutoRouter.of(context).navigate(const TabControllerRoute(children: [SharingRoute()])); + AutoRouter.of(context) + .navigate(const TabControllerRoute(children: [SharingRoute()])); } - const ScaffoldMessenger(child: SnackBar(content: Text('Failed to create album'))); + const ScaffoldMessenger( + child: SnackBar(content: Text('Failed to create album'))); } _buildTileIcon(User user) { @@ -47,7 +51,8 @@ class SelectUserForSharingPage extends HookConsumerWidget { ); } else { return CircleAvatar( - backgroundImage: const AssetImage('assets/immich-logo-no-outline.png'), + backgroundImage: + const AssetImage('assets/immich-logo-no-outline.png'), backgroundColor: Theme.of(context).primaryColor.withAlpha(50), ); } @@ -64,7 +69,10 @@ class SelectUserForSharingPage extends HookConsumerWidget { backgroundColor: Theme.of(context).primaryColor.withOpacity(0.15), label: Text( user.email, - style: const TextStyle(fontSize: 12, color: Colors.black87, fontWeight: FontWeight.bold), + style: const TextStyle( + fontSize: 12, + color: Colors.black87, + fontWeight: FontWeight.bold), ), ), ), @@ -80,7 +88,10 @@ class SelectUserForSharingPage extends HookConsumerWidget { padding: EdgeInsets.all(16.0), child: Text( 'Suggestions', - style: TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold), + style: TextStyle( + fontSize: 14, + color: Colors.grey, + fontWeight: FontWeight.bold), ), ), ListView.builder( @@ -90,14 +101,20 @@ class SelectUserForSharingPage extends HookConsumerWidget { leading: _buildTileIcon(users[index]), title: Text( users[index].email, - style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold), + style: const TextStyle( + fontSize: 14, fontWeight: FontWeight.bold), ), onTap: () { if (sharedUsersList.value.contains(users[index])) { - sharedUsersList.value = - sharedUsersList.value.where((selectedUser) => selectedUser.id != users[index].id).toSet(); + sharedUsersList.value = sharedUsersList.value + .where((selectedUser) => + selectedUser.id != users[index].id) + .toSet(); } else { - sharedUsersList.value = {...sharedUsersList.value, users[index]}; + sharedUsersList.value = { + ...sharedUsersList.value, + users[index] + }; } }, ); @@ -124,7 +141,8 @@ class SelectUserForSharingPage extends HookConsumerWidget { ), actions: [ TextButton( - onPressed: sharedUsersList.value.isEmpty ? null : _createSharedAlbum, + onPressed: + sharedUsersList.value.isEmpty ? null : _createSharedAlbum, child: const Text( "Create Album", style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold), diff --git a/mobile/lib/shared/providers/asset.provider.dart b/mobile/lib/shared/providers/asset.provider.dart index 99d6632d63..b1a6b6c671 100644 --- a/mobile/lib/shared/providers/asset.provider.dart +++ b/mobile/lib/shared/providers/asset.provider.dart @@ -9,11 +9,10 @@ import 'package:intl/intl.dart'; import 'package:photo_manager/photo_manager.dart'; class AssetNotifier extends StateNotifier> { - final AssetService _assetService = AssetService(); + final AssetService _assetService; final DeviceInfoService _deviceInfoService = DeviceInfoService(); - final Ref ref; - AssetNotifier(this.ref) : super([]); + AssetNotifier(this._assetService) : super([]); getAllAsset() async { List? allAssets = await _assetService.getAllAsset(); @@ -71,7 +70,7 @@ class AssetNotifier extends StateNotifier> { final assetProvider = StateNotifierProvider>((ref) { - return AssetNotifier(ref); + return AssetNotifier(ref.watch(assetServiceProvider)); }); final assetGroupByDateTimeProvider = StateProvider((ref) { diff --git a/mobile/lib/shared/providers/server_info.provider.dart b/mobile/lib/shared/providers/server_info.provider.dart index 00ee4aec7f..2eb2eedfc9 100644 --- a/mobile/lib/shared/providers/server_info.provider.dart +++ b/mobile/lib/shared/providers/server_info.provider.dart @@ -7,7 +7,7 @@ import 'package:immich_mobile/shared/services/server_info.service.dart'; import 'package:package_info_plus/package_info_plus.dart'; class ServerInfoNotifier extends StateNotifier { - ServerInfoNotifier() + ServerInfoNotifier(this._serverInfoService) : super( ServerInfoState( mapboxInfo: MapboxInfo(isEnable: false, mapboxSecret: ""), @@ -18,7 +18,7 @@ class ServerInfoNotifier extends StateNotifier { ), ); - final ServerInfoService _serverInfoService = ServerInfoService(); + final ServerInfoService _serverInfoService; getServerVersion() async { ServerVersion? serverVersion = await _serverInfoService.getServerVersion(); @@ -79,5 +79,5 @@ class ServerInfoNotifier extends StateNotifier { final serverInfoProvider = StateNotifierProvider((ref) { - return ServerInfoNotifier(); + return ServerInfoNotifier(ref.watch(serverInfoServiceProvider)); }); diff --git a/mobile/lib/shared/services/device_info.service.dart b/mobile/lib/shared/services/device_info.service.dart index 30762ae348..e1cd8a91fe 100644 --- a/mobile/lib/shared/services/device_info.service.dart +++ b/mobile/lib/shared/services/device_info.service.dart @@ -1,6 +1,10 @@ import 'package:flutter_udid/flutter_udid.dart'; import 'dart:io' show Platform; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +final deviceInfoServiceProvider = Provider((_) => DeviceInfoService()); + class DeviceInfoService { Future> getDeviceInfo() async { // Get device info diff --git a/mobile/lib/shared/services/local_storage.service.dart b/mobile/lib/shared/services/local_storage.service.dart index f4c7caaf9d..f409b2d7c0 100644 --- a/mobile/lib/shared/services/local_storage.service.dart +++ b/mobile/lib/shared/services/local_storage.service.dart @@ -1,6 +1,9 @@ import 'package:hive/hive.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; +final localStorageServiceProvider = Provider((_) => LocalStorageService()); + class LocalStorageService { late Box _box; diff --git a/mobile/lib/shared/services/network.service.dart b/mobile/lib/shared/services/network.service.dart index 5c53f2580b..300d69dfcf 100644 --- a/mobile/lib/shared/services/network.service.dart +++ b/mobile/lib/shared/services/network.service.dart @@ -4,11 +4,11 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:hive/hive.dart'; -import 'package:http_parser/http_parser.dart'; -import 'package:image_picker/image_picker.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; import 'package:immich_mobile/utils/dio_http_interceptor.dart'; -import 'package:immich_mobile/utils/files_helper.dart'; + +final networkServiceProvider = Provider((_) => NetworkService()); class NetworkService { late final Dio dio; diff --git a/mobile/lib/shared/services/server_info.service.dart b/mobile/lib/shared/services/server_info.service.dart index bd1b08b6e0..df25fe256e 100644 --- a/mobile/lib/shared/services/server_info.service.dart +++ b/mobile/lib/shared/services/server_info.service.dart @@ -1,11 +1,16 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/shared/models/server_info.model.dart'; import 'package:immich_mobile/shared/models/server_version.model.dart'; import 'package:immich_mobile/shared/services/network.service.dart'; +final serverInfoServiceProvider = + Provider((ref) => ServerInfoService(ref.watch(networkServiceProvider))); + class ServerInfoService { - final NetworkService _networkService = NetworkService(); + final NetworkService _networkService; + ServerInfoService(this._networkService); Future getServerInfo() async { Response response = await _networkService.getRequest(url: 'server-info'); diff --git a/mobile/lib/shared/services/user.service.dart b/mobile/lib/shared/services/user.service.dart index c36a5fa0d3..737cd97fc4 100644 --- a/mobile/lib/shared/services/user.service.dart +++ b/mobile/lib/shared/services/user.service.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; import 'package:immich_mobile/constants/hive_box.dart'; @@ -12,8 +13,12 @@ import 'package:immich_mobile/shared/services/network.service.dart'; import 'package:immich_mobile/utils/dio_http_interceptor.dart'; import 'package:immich_mobile/utils/files_helper.dart'; +final userServiceProvider = + Provider((ref) => UserService(ref.watch(networkServiceProvider))); + class UserService { - final NetworkService _networkService = NetworkService(); + final NetworkService _networkService; + UserService(this._networkService); Future> getAllUsersInfo() async { try {