diff --git a/mobile/assets/i18n/en-US.json b/mobile/assets/i18n/en-US.json index 7f6e031b37..0b4e1ba7e6 100644 --- a/mobile/assets/i18n/en-US.json +++ b/mobile/assets/i18n/en-US.json @@ -47,6 +47,7 @@ "backup_info_card_assets": "assets", "control_bottom_app_bar_delete": "Delete", "create_shared_album_page_share": "Share", + "create_shared_album_page_create": "Create", "create_shared_album_page_share_add_assets": "ADD ASSETS", "create_shared_album_page_share_select_photos": "Select Photos", "daily_title_text_date": "E, MMM dd", @@ -97,10 +98,11 @@ "tab_controller_nav_photos": "Photos", "tab_controller_nav_search": "Search", "tab_controller_nav_sharing": "Sharing", + "tab_controller_nav_library": "Library", "version_announcement_overlay_ack": "Acknowledge", "version_announcement_overlay_release_notes": "release notes", "version_announcement_overlay_text_1": "Hi friend, there is a new release of", "version_announcement_overlay_text_2": "please take your time to visit the ", "version_announcement_overlay_text_3": " and ensure your docker-compose and .env setup is up-to-date to prevent any misconfigurations, especially if you use WatchTower or any mechanism that handles updating your server application automatically.", "version_announcement_overlay_title": "New Server Version Available \uD83C\uDF89" -} \ No newline at end of file +} diff --git a/mobile/lib/modules/sharing/models/album_viewer_page_state.model.dart b/mobile/lib/modules/album/models/album_viewer_page_state.model.dart similarity index 100% rename from mobile/lib/modules/sharing/models/album_viewer_page_state.model.dart rename to mobile/lib/modules/album/models/album_viewer_page_state.model.dart diff --git a/mobile/lib/modules/sharing/models/asset_selection_page_result.model.dart b/mobile/lib/modules/album/models/asset_selection_page_result.model.dart similarity index 100% rename from mobile/lib/modules/sharing/models/asset_selection_page_result.model.dart rename to mobile/lib/modules/album/models/asset_selection_page_result.model.dart diff --git a/mobile/lib/modules/sharing/models/asset_selection_state.model.dart b/mobile/lib/modules/album/models/asset_selection_state.model.dart similarity index 100% rename from mobile/lib/modules/sharing/models/asset_selection_state.model.dart rename to mobile/lib/modules/album/models/asset_selection_state.model.dart diff --git a/mobile/lib/modules/album/providers/album.provider.dart b/mobile/lib/modules/album/providers/album.provider.dart new file mode 100644 index 0000000000..c23fa4d523 --- /dev/null +++ b/mobile/lib/modules/album/providers/album.provider.dart @@ -0,0 +1,38 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/album/services/album.service.dart'; +import 'package:openapi/api.dart'; + +class AlbumNotifier extends StateNotifier> { + AlbumNotifier(this._albumService) : super([]); + final AlbumService _albumService; + + getAllAlbums() async { + List? albums = + await _albumService.getAlbums(isShared: false); + + if (albums != null) { + state = albums; + } + } + + deleteAlbum(String albumId) { + state = state.where((album) => album.id != albumId).toList(); + } + + Future createAlbum( + String albumTitle, Set assets) async { + AlbumResponseDto? album = + await _albumService.createAlbum(albumTitle, assets, []); + + if (album != null) { + state = [...state, album]; + return album; + } + return null; + } +} + +final albumProvider = + StateNotifierProvider>((ref) { + return AlbumNotifier(ref.watch(albumServiceProvider)); +}); diff --git a/mobile/lib/modules/sharing/providers/album_title.provider.dart b/mobile/lib/modules/album/providers/album_title.provider.dart similarity index 100% rename from mobile/lib/modules/sharing/providers/album_title.provider.dart rename to mobile/lib/modules/album/providers/album_title.provider.dart diff --git a/mobile/lib/modules/sharing/providers/album_viewer.provider.dart b/mobile/lib/modules/album/providers/album_viewer.provider.dart similarity index 79% rename from mobile/lib/modules/sharing/providers/album_viewer.provider.dart rename to mobile/lib/modules/album/providers/album_viewer.provider.dart index 561f937102..371d6c49c4 100644 --- a/mobile/lib/modules/sharing/providers/album_viewer.provider.dart +++ b/mobile/lib/modules/album/providers/album_viewer.provider.dart @@ -1,7 +1,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/models/album_viewer_page_state.model.dart'; -import 'package:immich_mobile/modules/sharing/providers/shared_album.provider.dart'; -import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart'; +import 'package:immich_mobile/modules/album/models/album_viewer_page_state.model.dart'; +import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; +import 'package:immich_mobile/modules/album/services/album.service.dart'; class AlbumViewerNotifier extends StateNotifier { AlbumViewerNotifier(this.ref) @@ -34,7 +34,7 @@ class AlbumViewerNotifier extends StateNotifier { String ownerId, String newAlbumTitle, ) async { - SharedAlbumService service = ref.watch(sharedAlbumServiceProvider); + AlbumService service = ref.watch(albumServiceProvider); bool isSuccess = await service.changeTitleAlbum(albumId, ownerId, newAlbumTitle); diff --git a/mobile/lib/modules/sharing/providers/asset_selection.provider.dart b/mobile/lib/modules/album/providers/asset_selection.provider.dart similarity index 97% rename from mobile/lib/modules/sharing/providers/asset_selection.provider.dart rename to mobile/lib/modules/album/providers/asset_selection.provider.dart index 809e3d18c1..2b01b7cf9c 100644 --- a/mobile/lib/modules/sharing/providers/asset_selection.provider.dart +++ b/mobile/lib/modules/album/providers/asset_selection.provider.dart @@ -1,5 +1,5 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/models/asset_selection_state.model.dart'; +import 'package:immich_mobile/modules/album/models/asset_selection_state.model.dart'; import 'package:openapi/api.dart'; diff --git a/mobile/lib/modules/sharing/providers/shared_album.provider.dart b/mobile/lib/modules/album/providers/shared_album.provider.dart similarity index 55% rename from mobile/lib/modules/sharing/providers/shared_album.provider.dart rename to mobile/lib/modules/album/providers/shared_album.provider.dart index 792db47aa7..202e8241f0 100644 --- a/mobile/lib/modules/sharing/providers/shared_album.provider.dart +++ b/mobile/lib/modules/album/providers/shared_album.provider.dart @@ -1,30 +1,48 @@ +import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart'; +import 'package:immich_mobile/modules/album/services/album.service.dart'; import 'package:openapi/api.dart'; class SharedAlbumNotifier extends StateNotifier> { SharedAlbumNotifier(this._sharedAlbumService) : super([]); - final SharedAlbumService _sharedAlbumService; + final AlbumService _sharedAlbumService; + + Future createSharedAlbum( + String albumName, + Set assets, + List sharedUserIds, + ) async { + try { + var newAlbum = await _sharedAlbumService.createAlbum( + albumName, + assets, + sharedUserIds, + ); + + if (newAlbum != null) { + state = [...state, newAlbum]; + } + + return newAlbum; + } catch (e) { + debugPrint("Error createSharedAlbum ${e.toString()}"); + + return null; + } + } getAllSharedAlbums() async { List? sharedAlbums = - await _sharedAlbumService.getAllSharedAlbum(); + await _sharedAlbumService.getAlbums(isShared: true); if (sharedAlbums != null) { state = sharedAlbums; } } - Future deleteAlbum(String albumId) async { - var res = await _sharedAlbumService.deleteAlbum(albumId); - - if (res) { - state = state.where((album) => album.id != albumId).toList(); - return true; - } else { - return false; - } + deleteAlbum(String albumId) async { + state = state.where((album) => album.id != albumId).toList(); } Future leaveAlbum(String albumId) async { @@ -54,13 +72,12 @@ class SharedAlbumNotifier extends StateNotifier> { final sharedAlbumProvider = StateNotifierProvider>((ref) { - return SharedAlbumNotifier(ref.watch(sharedAlbumServiceProvider)); + return SharedAlbumNotifier(ref.watch(albumServiceProvider)); }); final sharedAlbumDetailProvider = FutureProvider.autoDispose .family((ref, albumId) async { - final SharedAlbumService sharedAlbumService = - ref.watch(sharedAlbumServiceProvider); + final AlbumService sharedAlbumService = ref.watch(albumServiceProvider); return await sharedAlbumService.getAlbumDetail(albumId); }); diff --git a/mobile/lib/modules/sharing/providers/suggested_shared_users.provider.dart b/mobile/lib/modules/album/providers/suggested_shared_users.provider.dart similarity index 100% rename from mobile/lib/modules/sharing/providers/suggested_shared_users.provider.dart rename to mobile/lib/modules/album/providers/suggested_shared_users.provider.dart diff --git a/mobile/lib/modules/sharing/services/shared_album.service.dart b/mobile/lib/modules/album/services/album.service.dart similarity index 86% rename from mobile/lib/modules/sharing/services/shared_album.service.dart rename to mobile/lib/modules/album/services/album.service.dart index b9da4f1d49..a94d609ad6 100644 --- a/mobile/lib/modules/sharing/services/shared_album.service.dart +++ b/mobile/lib/modules/album/services/album.service.dart @@ -2,46 +2,47 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:openapi/api.dart'; -final sharedAlbumServiceProvider = Provider( - (ref) => SharedAlbumService( +final albumServiceProvider = Provider( + (ref) => AlbumService( ref.watch(apiServiceProvider), ), ); -class SharedAlbumService { +class AlbumService { final ApiService _apiService; - SharedAlbumService(this._apiService); - Future?> getAllSharedAlbum() async { + AlbumService(this._apiService); + + Future?> getAlbums({required bool isShared}) async { try { - return await _apiService.albumApi.getAllAlbums(shared: true); + return await _apiService.albumApi + .getAllAlbums(shared: isShared ? isShared : null); } catch (e) { debugPrint("Error getAllSharedAlbum ${e.toString()}"); return null; } } - Future createSharedAlbum( + Future createAlbum( String albumName, Set assets, List sharedUserIds, ) async { try { - _apiService.albumApi.createAlbum( + return await _apiService.albumApi.createAlbum( CreateAlbumDto( albumName: albumName, assetIds: assets.map((asset) => asset.id).toList(), sharedWithUserIds: sharedUserIds, ), ); - - return true; } catch (e) { debugPrint("Error createSharedAlbum ${e.toString()}"); - return false; + return null; } } diff --git a/mobile/lib/modules/sharing/ui/album_action_outlined_button.dart b/mobile/lib/modules/album/ui/album_action_outlined_button.dart similarity index 100% rename from mobile/lib/modules/sharing/ui/album_action_outlined_button.dart rename to mobile/lib/modules/album/ui/album_action_outlined_button.dart diff --git a/mobile/lib/modules/album/ui/album_thumbnail_card.dart b/mobile/lib/modules/album/ui/album_thumbnail_card.dart new file mode 100644 index 0000000000..20114ca34e --- /dev/null +++ b/mobile/lib/modules/album/ui/album_thumbnail_card.dart @@ -0,0 +1,77 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:hive/hive.dart'; +import 'package:immich_mobile/constants/hive_box.dart'; +import 'package:immich_mobile/routing/router.dart'; +import 'package:openapi/api.dart'; +import 'package:transparent_image/transparent_image.dart'; + +class AlbumThumbnailCard extends StatelessWidget { + const AlbumThumbnailCard({Key? key, required this.album}) : super(key: key); + + final AlbumResponseDto album; + + @override + Widget build(BuildContext context) { + var box = Hive.box(userInfoBox); + + return GestureDetector( + onTap: () { + AutoRouter.of(context).push(AlbumViewerRoute(albumId: album.id)); + }, + child: Padding( + padding: const EdgeInsets.only(bottom: 32.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: FadeInImage( + width: MediaQuery.of(context).size.width / 2 - 18, + height: MediaQuery.of(context).size.width / 2 - 18, + fit: BoxFit.cover, + placeholder: MemoryImage(kTransparentImage), + image: NetworkImage( + '${box.get(serverEndpointKey)}/asset/thumbnail/${album.albumThumbnailAssetId}?format=JPEG', + headers: { + "Authorization": "Bearer ${box.get(accessTokenKey)}" + }, + ), + fadeInDuration: const Duration(milliseconds: 200), + fadeOutDuration: const Duration(milliseconds: 200), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + album.albumName, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + '${album.assets.length} item${album.assets.length > 1 ? 's' : ''}', + style: const TextStyle( + fontSize: 10, + ), + ), + if (album.shared) + const Text( + ' ยท Shared', + style: TextStyle( + fontSize: 10, + ), + ) + ], + ) + ], + ), + ), + ); + } +} diff --git a/mobile/lib/modules/sharing/ui/album_title_text_field.dart b/mobile/lib/modules/album/ui/album_title_text_field.dart similarity index 96% rename from mobile/lib/modules/sharing/ui/album_title_text_field.dart rename to mobile/lib/modules/album/ui/album_title_text_field.dart index 61dbad01a6..fa7f27471d 100644 --- a/mobile/lib/modules/sharing/ui/album_title_text_field.dart +++ b/mobile/lib/modules/album/ui/album_title_text_field.dart @@ -1,7 +1,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/providers/album_title.provider.dart'; +import 'package:immich_mobile/modules/album/providers/album_title.provider.dart'; class AlbumTitleTextField extends ConsumerWidget { const AlbumTitleTextField({ diff --git a/mobile/lib/modules/sharing/ui/album_viewer_appbar.dart b/mobile/lib/modules/album/ui/album_viewer_appbar.dart similarity index 85% rename from mobile/lib/modules/sharing/ui/album_viewer_appbar.dart rename to mobile/lib/modules/album/ui/album_viewer_appbar.dart index dd85021e5b..ed7e817c79 100644 --- a/mobile/lib/modules/sharing/ui/album_viewer_appbar.dart +++ b/mobile/lib/modules/album/ui/album_viewer_appbar.dart @@ -4,9 +4,11 @@ import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/immich_colors.dart'; -import 'package:immich_mobile/modules/sharing/providers/album_viewer.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/shared_album.provider.dart'; +import 'package:immich_mobile/modules/album/providers/album.provider.dart'; +import 'package:immich_mobile/modules/album/providers/album_viewer.provider.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; +import 'package:immich_mobile/modules/album/services/album.service.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/shared/ui/immich_toast.dart'; import 'package:immich_mobile/shared/views/immich_loading_overlay.dart'; @@ -15,13 +17,12 @@ import 'package:openapi/api.dart'; class AlbumViewerAppbar extends HookConsumerWidget with PreferredSizeWidget { const AlbumViewerAppbar({ Key? key, - required AsyncValue albumInfo, + required this.albumInfo, required this.userId, required this.albumId, - }) : _albumInfo = albumInfo, - super(key: key); + }) : super(key: key); - final AsyncValue _albumInfo; + final AlbumResponseDto albumInfo; final String userId; final String albumId; @@ -38,11 +39,18 @@ class AlbumViewerAppbar extends HookConsumerWidget with PreferredSizeWidget { ImmichLoadingOverlayController.appLoader.show(); bool isSuccess = - await ref.watch(sharedAlbumProvider.notifier).deleteAlbum(albumId); + await ref.watch(albumServiceProvider).deleteAlbum(albumId); if (isSuccess) { - AutoRouter.of(context) - .navigate(const TabControllerRoute(children: [SharingRoute()])); + if (albumInfo.shared) { + ref.watch(sharedAlbumProvider.notifier).deleteAlbum(albumId); + AutoRouter.of(context) + .navigate(const TabControllerRoute(children: [SharingRoute()])); + } else { + ref.watch(albumProvider.notifier).deleteAlbum(albumId); + AutoRouter.of(context) + .navigate(const TabControllerRoute(children: [LibraryRoute()])); + } } else { ImmichToast.show( context: context, @@ -105,7 +113,7 @@ class AlbumViewerAppbar extends HookConsumerWidget with PreferredSizeWidget { _buildBottomSheetActionButton() { if (isMultiSelectionEnable) { - if (_albumInfo.asData?.value?.ownerId == userId) { + if (albumInfo.ownerId == userId) { return ListTile( leading: const Icon(Icons.delete_sweep_rounded), title: const Text( @@ -118,7 +126,7 @@ class AlbumViewerAppbar extends HookConsumerWidget with PreferredSizeWidget { return const SizedBox(); } } else { - if (_albumInfo.asData?.value?.ownerId == userId) { + if (albumInfo.ownerId == userId) { return ListTile( leading: const Icon(Icons.delete_forever_rounded), title: const Text( diff --git a/mobile/lib/modules/sharing/ui/album_viewer_editable_title.dart b/mobile/lib/modules/album/ui/album_viewer_editable_title.dart similarity index 97% rename from mobile/lib/modules/sharing/ui/album_viewer_editable_title.dart rename to mobile/lib/modules/album/ui/album_viewer_editable_title.dart index 79f87d5b27..c0a1f148b6 100644 --- a/mobile/lib/modules/sharing/ui/album_viewer_editable_title.dart +++ b/mobile/lib/modules/album/ui/album_viewer_editable_title.dart @@ -2,7 +2,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/providers/album_viewer.provider.dart'; +import 'package:immich_mobile/modules/album/providers/album_viewer.provider.dart'; import 'package:openapi/api.dart'; class AlbumViewerEditableTitle extends HookConsumerWidget { diff --git a/mobile/lib/modules/sharing/ui/album_viewer_thumbnail.dart b/mobile/lib/modules/album/ui/album_viewer_thumbnail.dart similarity index 98% rename from mobile/lib/modules/sharing/ui/album_viewer_thumbnail.dart rename to mobile/lib/modules/album/ui/album_viewer_thumbnail.dart index c5f3a6bd99..b959418419 100644 --- a/mobile/lib/modules/sharing/ui/album_viewer_thumbnail.dart +++ b/mobile/lib/modules/album/ui/album_viewer_thumbnail.dart @@ -6,7 +6,7 @@ import 'package:hive_flutter/hive_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:openapi/api.dart'; diff --git a/mobile/lib/modules/sharing/ui/asset_grid_by_month.dart b/mobile/lib/modules/album/ui/asset_grid_by_month.dart similarity index 90% rename from mobile/lib/modules/sharing/ui/asset_grid_by_month.dart rename to mobile/lib/modules/album/ui/asset_grid_by_month.dart index 3586487621..8489a9247f 100644 --- a/mobile/lib/modules/sharing/ui/asset_grid_by_month.dart +++ b/mobile/lib/modules/album/ui/asset_grid_by_month.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/ui/selection_thumbnail_image.dart'; +import 'package:immich_mobile/modules/album/ui/selection_thumbnail_image.dart'; import 'package:openapi/api.dart'; class AssetGridByMonth extends HookConsumerWidget { diff --git a/mobile/lib/modules/sharing/ui/month_group_title.dart b/mobile/lib/modules/album/ui/month_group_title.dart similarity index 97% rename from mobile/lib/modules/sharing/ui/month_group_title.dart rename to mobile/lib/modules/album/ui/month_group_title.dart index 5ea00d1532..ad136c374f 100644 --- a/mobile/lib/modules/sharing/ui/month_group_title.dart +++ b/mobile/lib/modules/album/ui/month_group_title.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; import 'package:openapi/api.dart'; class MonthGroupTitle extends HookConsumerWidget { diff --git a/mobile/lib/modules/sharing/ui/selection_thumbnail_image.dart b/mobile/lib/modules/album/ui/selection_thumbnail_image.dart similarity index 95% rename from mobile/lib/modules/sharing/ui/selection_thumbnail_image.dart rename to mobile/lib/modules/album/ui/selection_thumbnail_image.dart index a81b5416df..1019a18d42 100644 --- a/mobile/lib/modules/sharing/ui/selection_thumbnail_image.dart +++ b/mobile/lib/modules/album/ui/selection_thumbnail_image.dart @@ -4,7 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; import 'package:openapi/api.dart'; class SelectionThumbnailImage extends HookConsumerWidget { diff --git a/mobile/lib/modules/sharing/ui/shared_album_thumbnail_image.dart b/mobile/lib/modules/album/ui/shared_album_thumbnail_image.dart similarity index 100% rename from mobile/lib/modules/sharing/ui/shared_album_thumbnail_image.dart rename to mobile/lib/modules/album/ui/shared_album_thumbnail_image.dart diff --git a/mobile/lib/modules/sharing/ui/sharing_sliver_appbar.dart b/mobile/lib/modules/album/ui/sharing_sliver_appbar.dart similarity index 96% rename from mobile/lib/modules/sharing/ui/sharing_sliver_appbar.dart rename to mobile/lib/modules/album/ui/sharing_sliver_appbar.dart index e39bcf115e..49ac3741fe 100644 --- a/mobile/lib/modules/sharing/ui/sharing_sliver_appbar.dart +++ b/mobile/lib/modules/album/ui/sharing_sliver_appbar.dart @@ -16,8 +16,6 @@ class SharingSliverAppBar extends StatelessWidget { pinned: true, snap: false, automaticallyImplyLeading: false, - // leading: Container(), - // elevation: 0, title: Text( 'IMMICH', style: TextStyle( @@ -46,7 +44,7 @@ class SharingSliverAppBar extends StatelessWidget { ), onPressed: () { AutoRouter.of(context) - .push(const CreateSharedAlbumRoute()); + .push(CreateAlbumRoute(isSharedAlbum: true)); }, icon: const Icon( Icons.photo_album_outlined, diff --git a/mobile/lib/modules/sharing/views/album_viewer_page.dart b/mobile/lib/modules/album/views/album_viewer_page.dart similarity index 76% rename from mobile/lib/modules/sharing/views/album_viewer_page.dart rename to mobile/lib/modules/album/views/album_viewer_page.dart index c10268d677..c6fd6e7278 100644 --- a/mobile/lib/modules/sharing/views/album_viewer_page.dart +++ b/mobile/lib/modules/album/views/album_viewer_page.dart @@ -6,14 +6,14 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/immich_colors.dart'; import 'package:immich_mobile/modules/home/ui/draggable_scrollbar.dart'; import 'package:immich_mobile/modules/login/providers/authentication.provider.dart'; -import 'package:immich_mobile/modules/sharing/models/asset_selection_page_result.model.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/shared_album.provider.dart'; -import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart'; -import 'package:immich_mobile/modules/sharing/ui/album_action_outlined_button.dart'; -import 'package:immich_mobile/modules/sharing/ui/album_viewer_appbar.dart'; -import 'package:immich_mobile/modules/sharing/ui/album_viewer_editable_title.dart'; -import 'package:immich_mobile/modules/sharing/ui/album_viewer_thumbnail.dart'; +import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; +import 'package:immich_mobile/modules/album/services/album.service.dart'; +import 'package:immich_mobile/modules/album/ui/album_action_outlined_button.dart'; +import 'package:immich_mobile/modules/album/ui/album_viewer_appbar.dart'; +import 'package:immich_mobile/modules/album/ui/album_viewer_editable_title.dart'; +import 'package:immich_mobile/modules/album/ui/album_viewer_thumbnail.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart'; import 'package:immich_mobile/shared/ui/immich_sliver_persistent_app_bar_delegate.dart'; @@ -29,6 +29,7 @@ class AlbumViewerPage extends HookConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { FocusNode titleFocusNode = useFocusNode(); ScrollController scrollController = useScrollController(); + AsyncValue albumInfo = ref.watch(sharedAlbumDetailProvider(albumId)); @@ -53,12 +54,11 @@ class AlbumViewerPage extends HookConsumerWidget { if (returnPayload.selectedAdditionalAsset.isNotEmpty) { ImmichLoadingOverlayController.appLoader.show(); - var isSuccess = await ref - .watch(sharedAlbumServiceProvider) - .addAdditionalAssetToAlbum( - returnPayload.selectedAdditionalAsset, - albumId, - ); + var isSuccess = + await ref.watch(albumServiceProvider).addAdditionalAssetToAlbum( + returnPayload.selectedAdditionalAsset, + albumId, + ); if (isSuccess) { ref.refresh(sharedAlbumDetailProvider(albumId)); @@ -83,7 +83,7 @@ class AlbumViewerPage extends HookConsumerWidget { ImmichLoadingOverlayController.appLoader.show(); var isSuccess = await ref - .watch(sharedAlbumServiceProvider) + .watch(albumServiceProvider) .addAdditionalUserToAlbum(sharedUserIds, albumId); if (isSuccess) { @@ -132,7 +132,11 @@ class AlbumViewerPage extends HookConsumerWidget { String endDate = DateFormat('LLL d, y').format(parsedEndDate); return Padding( - padding: const EdgeInsets.only(left: 16.0, top: 8), + padding: EdgeInsets.only( + left: 16.0, + top: 8.0, + bottom: albumInfo.shared ? 0.0 : 8.0, + ), child: Text( "$startDate-$endDate", style: const TextStyle( @@ -152,31 +156,33 @@ class AlbumViewerPage extends HookConsumerWidget { _buildTitle(albumInfo), if (albumInfo.assets.isNotEmpty == true) _buildAlbumDateRange(albumInfo), - SizedBox( - height: 60, - child: ListView.builder( - padding: const EdgeInsets.only(left: 16), - scrollDirection: Axis.horizontal, - itemBuilder: ((context, index) { - return Padding( - padding: const EdgeInsets.only(right: 8.0), - child: CircleAvatar( - backgroundColor: Colors.grey[300], - radius: 18, - child: Padding( - padding: const EdgeInsets.all(2.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(50.0), - child: - Image.asset('assets/immich-logo-no-outline.png'), + if (albumInfo.shared) + SizedBox( + height: 60, + child: ListView.builder( + padding: const EdgeInsets.only(left: 16), + scrollDirection: Axis.horizontal, + itemBuilder: ((context, index) { + return Padding( + padding: const EdgeInsets.only(right: 8.0), + child: CircleAvatar( + backgroundColor: Colors.grey[300], + radius: 18, + child: Padding( + padding: const EdgeInsets.all(2.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(50.0), + child: Image.asset( + 'assets/immich-logo-no-outline.png', + ), + ), ), ), - ), - ); - }), - itemCount: albumInfo.sharedUsers.length, - ), - ) + ); + }), + itemCount: albumInfo.sharedUsers.length, + ), + ) ], ), ); @@ -261,10 +267,19 @@ class AlbumViewerPage extends HookConsumerWidget { } return Scaffold( - appBar: AlbumViewerAppbar( - albumInfo: albumInfo, - userId: userId, - albumId: albumId, + appBar: albumInfo.when( + data: (AlbumResponseDto? data) { + if (data != null) { + return AlbumViewerAppbar( + albumInfo: data, + userId: userId, + albumId: albumId, + ); + } + return null; + }, + error: (e, _) => null, + loading: () => null, ), body: albumInfo.when( data: (albumInfo) => albumInfo != null diff --git a/mobile/lib/modules/sharing/views/asset_selection_page.dart b/mobile/lib/modules/album/views/asset_selection_page.dart similarity index 90% rename from mobile/lib/modules/sharing/views/asset_selection_page.dart rename to mobile/lib/modules/album/views/asset_selection_page.dart index b12a96de7b..a8bde660fb 100644 --- a/mobile/lib/modules/sharing/views/asset_selection_page.dart +++ b/mobile/lib/modules/album/views/asset_selection_page.dart @@ -3,15 +3,16 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/models/asset_selection_page_result.model.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; -import 'package:immich_mobile/modules/sharing/ui/asset_grid_by_month.dart'; -import 'package:immich_mobile/modules/sharing/ui/month_group_title.dart'; +import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/ui/asset_grid_by_month.dart'; +import 'package:immich_mobile/modules/album/ui/month_group_title.dart'; import 'package:immich_mobile/shared/providers/asset.provider.dart'; import 'package:immich_mobile/modules/home/ui/draggable_scrollbar.dart'; class AssetSelectionPage extends HookConsumerWidget { const AssetSelectionPage({Key? key}) : super(key: key); + @override Widget build(BuildContext context, WidgetRef ref) { ScrollController scrollController = useScrollController(); diff --git a/mobile/lib/modules/sharing/views/create_shared_album_page.dart b/mobile/lib/modules/album/views/create_album_page.dart similarity index 75% rename from mobile/lib/modules/sharing/views/create_shared_album_page.dart rename to mobile/lib/modules/album/views/create_album_page.dart index 6cc6b1faaf..9f0d2ec53c 100644 --- a/mobile/lib/modules/sharing/views/create_shared_album_page.dart +++ b/mobile/lib/modules/album/views/create_album_page.dart @@ -3,16 +3,20 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/models/asset_selection_page_result.model.dart'; -import 'package:immich_mobile/modules/sharing/providers/album_title.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; -import 'package:immich_mobile/modules/sharing/ui/album_action_outlined_button.dart'; -import 'package:immich_mobile/modules/sharing/ui/album_title_text_field.dart'; -import 'package:immich_mobile/modules/sharing/ui/shared_album_thumbnail_image.dart'; +import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart'; +import 'package:immich_mobile/modules/album/providers/album.provider.dart'; +import 'package:immich_mobile/modules/album/providers/album_title.provider.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/ui/album_action_outlined_button.dart'; +import 'package:immich_mobile/modules/album/ui/album_title_text_field.dart'; +import 'package:immich_mobile/modules/album/ui/shared_album_thumbnail_image.dart'; import 'package:immich_mobile/routing/router.dart'; -class CreateSharedAlbumPage extends HookConsumerWidget { - const CreateSharedAlbumPage({Key? key}) : super(key: key); +// ignore: must_be_immutable +class CreateAlbumPage extends HookConsumerWidget { + bool isSharedAlbum; + + CreateAlbumPage({Key? key, required this.isSharedAlbum}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { @@ -165,6 +169,21 @@ class CreateSharedAlbumPage extends HookConsumerWidget { return const SliverToBoxAdapter(); } + _createNonSharedAlbum() async { + var newAlbum = await ref.watch(albumProvider.notifier).createAlbum( + ref.watch(albumTitleProvider), + ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum, + ); + + if (newAlbum != null) { + ref.watch(albumProvider.notifier).getAllAlbums(); + ref.watch(assetSelectionProvider.notifier).removeAll(); + ref.watch(albumTitleProvider.notifier).clearAlbumTitle(); + + AutoRouter.of(context).replace(AlbumViewerRoute(albumId: newAlbum.id)); + } + } + return Scaffold( appBar: AppBar( elevation: 0, @@ -181,17 +200,31 @@ class CreateSharedAlbumPage extends HookConsumerWidget { style: TextStyle(color: Colors.black), ).tr(), actions: [ - TextButton( - onPressed: albumTitleController.text.isNotEmpty - ? _showSelectUserPage - : null, - child: Text( - 'create_shared_album_page_share'.tr(), - style: const TextStyle( - fontWeight: FontWeight.bold, + if (isSharedAlbum) + TextButton( + onPressed: albumTitleController.text.isNotEmpty + ? _showSelectUserPage + : null, + child: Text( + 'create_shared_album_page_share'.tr(), + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + ), + if (!isSharedAlbum) + TextButton( + onPressed: albumTitleController.text.isNotEmpty && + selectedAssets.isNotEmpty + ? _createNonSharedAlbum + : null, + child: Text( + 'create_shared_album_page_create'.tr(), + style: const TextStyle( + fontWeight: FontWeight.bold, + ), ), ), - ), ], ), body: GestureDetector( diff --git a/mobile/lib/modules/album/views/library_page.dart b/mobile/lib/modules/album/views/library_page.dart new file mode 100644 index 0000000000..f5d933f488 --- /dev/null +++ b/mobile/lib/modules/album/views/library_page.dart @@ -0,0 +1,116 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/album/providers/album.provider.dart'; +import 'package:immich_mobile/modules/album/ui/album_thumbnail_card.dart'; +import 'package:immich_mobile/routing/router.dart'; + +class LibraryPage extends HookConsumerWidget { + const LibraryPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final albums = ref.watch(albumProvider); + + useEffect( + () { + ref.read(albumProvider.notifier).getAllAlbums(); + return null; + }, + [], + ); + + Widget _buildAppBar() { + return SliverAppBar( + centerTitle: true, + floating: true, + pinned: false, + snap: false, + automaticallyImplyLeading: false, + title: Text( + 'IMMICH', + style: TextStyle( + fontFamily: 'SnowburstOne', + fontWeight: FontWeight.bold, + fontSize: 22, + color: Theme.of(context).primaryColor, + ), + ), + ); + } + + Widget _buildCreateAlbumButton() { + return GestureDetector( + onTap: () { + AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false)); + }, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: MediaQuery.of(context).size.width / 2 - 18, + height: MediaQuery.of(context).size.width / 2 - 18, + decoration: BoxDecoration( + border: Border.all( + color: Colors.grey, + ), + borderRadius: BorderRadius.circular(8), + ), + child: Center( + child: Icon( + Icons.add_rounded, + size: 28, + color: Theme.of(context).primaryColor, + ), + ), + ), + const Padding( + padding: EdgeInsets.only(top: 8.0), + child: Text( + "New album", + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + ), + ), + ) + ], + ), + ); + } + + return Scaffold( + body: CustomScrollView( + slivers: [ + _buildAppBar(), + const SliverToBoxAdapter( + child: Padding( + padding: EdgeInsets.all(12.0), + child: Text( + "Albums", + style: TextStyle(fontWeight: FontWeight.bold), + ), + ), + ), + SliverPadding( + padding: const EdgeInsets.only(left: 12.0, right: 12, bottom: 50), + sliver: SliverToBoxAdapter( + child: Wrap( + spacing: 12, + children: [ + _buildCreateAlbumButton(), + for (var album in albums) + AlbumThumbnailCard( + album: album, + ), + ], + ), + ), + ) + ], + ), + ); + } +} diff --git a/mobile/lib/modules/sharing/views/select_additional_user_for_sharing_page.dart b/mobile/lib/modules/album/views/select_additional_user_for_sharing_page.dart similarity index 98% rename from mobile/lib/modules/sharing/views/select_additional_user_for_sharing_page.dart rename to mobile/lib/modules/album/views/select_additional_user_for_sharing_page.dart index 21fd7acb72..61ee9a6e6a 100644 --- a/mobile/lib/modules/sharing/views/select_additional_user_for_sharing_page.dart +++ b/mobile/lib/modules/album/views/select_additional_user_for_sharing_page.dart @@ -3,7 +3,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/providers/suggested_shared_users.provider.dart'; +import 'package:immich_mobile/modules/album/providers/suggested_shared_users.provider.dart'; import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart'; import 'package:openapi/api.dart'; diff --git a/mobile/lib/modules/sharing/views/select_user_for_sharing_page.dart b/mobile/lib/modules/album/views/select_user_for_sharing_page.dart similarity index 90% rename from mobile/lib/modules/sharing/views/select_user_for_sharing_page.dart rename to mobile/lib/modules/album/views/select_user_for_sharing_page.dart index 74c5c59df6..8f479df498 100644 --- a/mobile/lib/modules/sharing/views/select_user_for_sharing_page.dart +++ b/mobile/lib/modules/album/views/select_user_for_sharing_page.dart @@ -3,11 +3,10 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/sharing/providers/album_title.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/asset_selection.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/shared_album.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/suggested_shared_users.provider.dart'; -import 'package:immich_mobile/modules/sharing/services/shared_album.service.dart'; +import 'package:immich_mobile/modules/album/providers/album_title.provider.dart'; +import 'package:immich_mobile/modules/album/providers/asset_selection.provider.dart'; +import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; +import 'package:immich_mobile/modules/album/providers/suggested_shared_users.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart'; import 'package:openapi/api.dart'; @@ -22,14 +21,14 @@ class SelectUserForSharingPage extends HookConsumerWidget { ref.watch(suggestedSharedUsersProvider); _createSharedAlbum() async { - var isSuccess = - await ref.watch(sharedAlbumServiceProvider).createSharedAlbum( + var newAlbum = + await ref.watch(sharedAlbumProvider.notifier).createSharedAlbum( ref.watch(albumTitleProvider), ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum, sharedUsersList.value.map((userInfo) => userInfo.id).toList(), ); - if (isSuccess) { + if (newAlbum != null) { await ref.watch(sharedAlbumProvider.notifier).getAllSharedAlbums(); ref.watch(assetSelectionProvider.notifier).removeAll(); ref.watch(albumTitleProvider.notifier).clearAlbumTitle(); diff --git a/mobile/lib/modules/sharing/views/sharing_page.dart b/mobile/lib/modules/album/views/sharing_page.dart similarity index 97% rename from mobile/lib/modules/sharing/views/sharing_page.dart rename to mobile/lib/modules/album/views/sharing_page.dart index 728d52673c..bc862f4a82 100644 --- a/mobile/lib/modules/sharing/views/sharing_page.dart +++ b/mobile/lib/modules/album/views/sharing_page.dart @@ -5,8 +5,8 @@ import 'package:flutter_hooks/flutter_hooks.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/modules/sharing/providers/shared_album.provider.dart'; -import 'package:immich_mobile/modules/sharing/ui/sharing_sliver_appbar.dart'; +import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; +import 'package:immich_mobile/modules/album/ui/sharing_sliver_appbar.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:openapi/api.dart'; import 'package:transparent_image/transparent_image.dart'; @@ -23,7 +23,6 @@ class SharingPage extends HookConsumerWidget { useEffect( () { ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums(); - return null; }, [], diff --git a/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart b/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart index 771b0873d8..f9f52a15d0 100644 --- a/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart +++ b/mobile/lib/modules/asset_viewer/services/image_viewer.service.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:openapi/api.dart'; import 'package:path/path.dart' as p; @@ -14,6 +15,7 @@ final imageViewerServiceProvider = class ImageViewerService { final ApiService _apiService; + ImageViewerService(this._apiService); Future downloadAssetToDevice(AssetResponseDto asset) async { diff --git a/mobile/lib/modules/backup/services/backup.service.dart b/mobile/lib/modules/backup/services/backup.service.dart index 59696028f4..e54633bc27 100644 --- a/mobile/lib/modules/backup/services/backup.service.dart +++ b/mobile/lib/modules/backup/services/backup.service.dart @@ -8,6 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/constants/hive_box.dart'; import 'package:immich_mobile/modules/backup/models/current_upload_asset.model.dart'; import 'package:immich_mobile/modules/backup/models/error_upload_asset.model.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:immich_mobile/utils/files_helper.dart'; import 'package:openapi/api.dart'; @@ -24,6 +25,7 @@ final backupServiceProvider = Provider( class BackupService { final ApiService _apiService; + BackupService(this._apiService); Future?> getDeviceBackupAsset() async { diff --git a/mobile/lib/modules/home/services/asset.service.dart b/mobile/lib/modules/home/services/asset.service.dart index 3e44d8b165..b34c424143 100644 --- a/mobile/lib/modules/home/services/asset.service.dart +++ b/mobile/lib/modules/home/services/asset.service.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:openapi/api.dart'; diff --git a/mobile/lib/modules/login/providers/authentication.provider.dart b/mobile/lib/modules/login/providers/authentication.provider.dart index 885066e220..2ccf616a7b 100644 --- a/mobile/lib/modules/login/providers/authentication.provider.dart +++ b/mobile/lib/modules/login/providers/authentication.provider.dart @@ -5,6 +5,7 @@ import 'package:immich_mobile/constants/hive_box.dart'; import 'package:immich_mobile/modules/login/models/authentication_state.model.dart'; import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart'; import 'package:immich_mobile/modules/backup/services/backup.service.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:immich_mobile/shared/services/device_info.service.dart'; import 'package:openapi/api.dart'; diff --git a/mobile/lib/modules/search/services/search.service.dart b/mobile/lib/modules/search/services/search.service.dart index 83e6122a80..721bfc20b8 100644 --- a/mobile/lib/modules/search/services/search.service.dart +++ b/mobile/lib/modules/search/services/search.service.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:openapi/api.dart'; @@ -11,6 +12,7 @@ final searchServiceProvider = Provider( class SearchService { final ApiService _apiService; + SearchService(this._apiService); Future?> getUserSuggestedSearchTerms() async { diff --git a/mobile/lib/routing/router.dart b/mobile/lib/routing/router.dart index a964b46951..7680f2355e 100644 --- a/mobile/lib/routing/router.dart +++ b/mobile/lib/routing/router.dart @@ -1,6 +1,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/album/views/library_page.dart'; import 'package:immich_mobile/modules/backup/views/album_preview_page.dart'; import 'package:immich_mobile/modules/backup/views/backup_album_selection_page.dart'; import 'package:immich_mobile/modules/backup/views/failed_backup_status_page.dart'; @@ -9,16 +10,17 @@ import 'package:immich_mobile/modules/login/views/login_page.dart'; import 'package:immich_mobile/modules/home/views/home_page.dart'; import 'package:immich_mobile/modules/search/views/search_page.dart'; import 'package:immich_mobile/modules/search/views/search_result_page.dart'; -import 'package:immich_mobile/modules/sharing/models/asset_selection_page_result.model.dart'; -import 'package:immich_mobile/modules/sharing/views/album_viewer_page.dart'; -import 'package:immich_mobile/modules/sharing/views/asset_selection_page.dart'; -import 'package:immich_mobile/modules/sharing/views/create_shared_album_page.dart'; -import 'package:immich_mobile/modules/sharing/views/select_additional_user_for_sharing_page.dart'; -import 'package:immich_mobile/modules/sharing/views/select_user_for_sharing_page.dart'; -import 'package:immich_mobile/modules/sharing/views/sharing_page.dart'; +import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart'; +import 'package:immich_mobile/modules/album/views/album_viewer_page.dart'; +import 'package:immich_mobile/modules/album/views/asset_selection_page.dart'; +import 'package:immich_mobile/modules/album/views/create_album_page.dart'; +import 'package:immich_mobile/modules/album/views/select_additional_user_for_sharing_page.dart'; +import 'package:immich_mobile/modules/album/views/select_user_for_sharing_page.dart'; +import 'package:immich_mobile/modules/album/views/sharing_page.dart'; import 'package:immich_mobile/routing/auth_guard.dart'; import 'package:immich_mobile/modules/backup/views/backup_controller_page.dart'; import 'package:immich_mobile/modules/asset_viewer/views/image_viewer_page.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:immich_mobile/shared/views/splash_screen.dart'; import 'package:immich_mobile/shared/views/tab_controller_page.dart'; @@ -40,7 +42,8 @@ part 'router.gr.dart'; children: [ AutoRoute(page: HomePage, guards: [AuthGuard]), AutoRoute(page: SearchPage, guards: [AuthGuard]), - AutoRoute(page: SharingPage, guards: [AuthGuard]) + AutoRoute(page: SharingPage, guards: [AuthGuard]), + AutoRoute(page: LibraryPage, guards: [AuthGuard]) ], transitionsBuilder: TransitionsBuilders.fadeIn, ), @@ -48,7 +51,7 @@ part 'router.gr.dart'; AutoRoute(page: VideoViewerPage, guards: [AuthGuard]), AutoRoute(page: BackupControllerPage, guards: [AuthGuard]), AutoRoute(page: SearchResultPage, guards: [AuthGuard]), - AutoRoute(page: CreateSharedAlbumPage, guards: [AuthGuard]), + AutoRoute(page: CreateAlbumPage, guards: [AuthGuard]), CustomRoute( page: AssetSelectionPage, guards: [AuthGuard], @@ -76,6 +79,7 @@ part 'router.gr.dart'; ) class AppRouter extends _$AppRouter { final ApiService _apiService; + AppRouter(this._apiService) : super(authGuard: AuthGuard(_apiService)); } diff --git a/mobile/lib/routing/router.gr.dart b/mobile/lib/routing/router.gr.dart index 79ce762d01..552a7fa773 100644 --- a/mobile/lib/routing/router.gr.dart +++ b/mobile/lib/routing/router.gr.dart @@ -69,9 +69,12 @@ class _$AppRouter extends RootStackRouter { routeData: routeData, child: SearchResultPage(key: args.key, searchTerm: args.searchTerm)); }, - CreateSharedAlbumRoute.name: (routeData) { + CreateAlbumRoute.name: (routeData) { + final args = routeData.argsAs(); return MaterialPageX( - routeData: routeData, child: const CreateSharedAlbumPage()); + routeData: routeData, + child: CreateAlbumPage( + key: args.key, isSharedAlbum: args.isSharedAlbum)); }, AssetSelectionRoute.name: (routeData) { return CustomPage( @@ -136,6 +139,10 @@ class _$AppRouter extends RootStackRouter { SharingRoute.name: (routeData) { return MaterialPageX( routeData: routeData, child: const SharingPage()); + }, + LibraryRoute.name: (routeData) { + return MaterialPageX( + routeData: routeData, child: const LibraryPage()); } }; @@ -161,6 +168,10 @@ class _$AppRouter extends RootStackRouter { RouteConfig(SharingRoute.name, path: 'sharing-page', parent: TabControllerRoute.name, + guards: [authGuard]), + RouteConfig(LibraryRoute.name, + path: 'library-page', + parent: TabControllerRoute.name, guards: [authGuard]) ]), RouteConfig(ImageViewerRoute.name, @@ -171,8 +182,8 @@ class _$AppRouter extends RootStackRouter { path: '/backup-controller-page', guards: [authGuard]), RouteConfig(SearchResultRoute.name, path: '/search-result-page', guards: [authGuard]), - RouteConfig(CreateSharedAlbumRoute.name, - path: '/create-shared-album-page', guards: [authGuard]), + RouteConfig(CreateAlbumRoute.name, + path: '/create-album-page', guards: [authGuard]), RouteConfig(AssetSelectionRoute.name, path: '/asset-selection-page', guards: [authGuard]), RouteConfig(SelectUserForSharingRoute.name, @@ -334,12 +345,27 @@ class SearchResultRouteArgs { } /// generated route for -/// [CreateSharedAlbumPage] -class CreateSharedAlbumRoute extends PageRouteInfo { - const CreateSharedAlbumRoute() - : super(CreateSharedAlbumRoute.name, path: '/create-shared-album-page'); +/// [CreateAlbumPage] +class CreateAlbumRoute extends PageRouteInfo { + CreateAlbumRoute({Key? key, required bool isSharedAlbum}) + : super(CreateAlbumRoute.name, + path: '/create-album-page', + args: CreateAlbumRouteArgs(key: key, isSharedAlbum: isSharedAlbum)); - static const String name = 'CreateSharedAlbumRoute'; + static const String name = 'CreateAlbumRoute'; +} + +class CreateAlbumRouteArgs { + const CreateAlbumRouteArgs({this.key, required this.isSharedAlbum}); + + final Key? key; + + final bool isSharedAlbum; + + @override + String toString() { + return 'CreateAlbumRouteArgs{key: $key, isSharedAlbum: $isSharedAlbum}'; + } } /// generated route for @@ -492,3 +518,11 @@ class SharingRoute extends PageRouteInfo { static const String name = 'SharingRoute'; } + +/// generated route for +/// [LibraryPage] +class LibraryRoute extends PageRouteInfo { + const LibraryRoute() : super(LibraryRoute.name, path: 'library-page'); + + static const String name = 'LibraryRoute'; +} diff --git a/mobile/lib/routing/tab_navigation_observer.dart b/mobile/lib/routing/tab_navigation_observer.dart index bac868cf30..25db941848 100644 --- a/mobile/lib/routing/tab_navigation_observer.dart +++ b/mobile/lib/routing/tab_navigation_observer.dart @@ -1,8 +1,9 @@ import 'package:auto_route/auto_route.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/album/providers/album.provider.dart'; import 'package:immich_mobile/modules/search/providers/search_page_state.provider.dart'; -import 'package:immich_mobile/modules/sharing/providers/shared_album.provider.dart'; +import 'package:immich_mobile/modules/album/providers/shared_album.provider.dart'; import 'package:immich_mobile/shared/providers/server_info.provider.dart'; class TabNavigationObserver extends AutoRouterObserver { @@ -37,6 +38,9 @@ class TabNavigationObserver extends AutoRouterObserver { ref.read(sharedAlbumProvider.notifier).getAllSharedAlbums(); } + if (route.name == 'LibraryRoute') { + ref.read(albumProvider.notifier).getAllAlbums(); + } ref.watch(serverInfoProvider.notifier).getServerVersion(); } } diff --git a/mobile/lib/shared/providers/api.provider.dart b/mobile/lib/shared/providers/api.provider.dart new file mode 100644 index 0000000000..24cf864e09 --- /dev/null +++ b/mobile/lib/shared/providers/api.provider.dart @@ -0,0 +1,4 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/shared/services/api.service.dart'; + +final apiServiceProvider = Provider((ref) => ApiService()); diff --git a/mobile/lib/shared/services/api.service.dart b/mobile/lib/shared/services/api.service.dart index 69c977bfff..c1b70a0e81 100644 --- a/mobile/lib/shared/services/api.service.dart +++ b/mobile/lib/shared/services/api.service.dart @@ -1,8 +1,5 @@ -import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:openapi/api.dart'; -final apiServiceProvider = Provider((ref) => ApiService()); - class ApiService { late ApiClient _apiClient; @@ -15,7 +12,6 @@ class ApiService { setEndpoint(String endpoint) { _apiClient = ApiClient(basePath: endpoint); - userApi = UserApi(_apiClient); authenticationApi = AuthenticationApi(_apiClient); albumApi = AlbumApi(_apiClient); diff --git a/mobile/lib/shared/services/server_info.service.dart b/mobile/lib/shared/services/server_info.service.dart index 92ea9d89d4..b112fc46ca 100644 --- a/mobile/lib/shared/services/server_info.service.dart +++ b/mobile/lib/shared/services/server_info.service.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:openapi/api.dart'; @@ -11,6 +12,7 @@ final serverInfoServiceProvider = Provider( class ServerInfoService { final ApiService _apiService; + ServerInfoService(this._apiService); Future getServerInfo() async { diff --git a/mobile/lib/shared/services/user.service.dart b/mobile/lib/shared/services/user.service.dart index 482f08635f..114293a5da 100644 --- a/mobile/lib/shared/services/user.service.dart +++ b/mobile/lib/shared/services/user.service.dart @@ -3,6 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:http/http.dart'; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:immich_mobile/shared/providers/api.provider.dart'; import 'package:immich_mobile/shared/services/api.service.dart'; import 'package:immich_mobile/utils/files_helper.dart'; import 'package:openapi/api.dart'; diff --git a/mobile/lib/shared/views/tab_controller_page.dart b/mobile/lib/shared/views/tab_controller_page.dart index 9da202f089..f15f3380e6 100644 --- a/mobile/lib/shared/views/tab_controller_page.dart +++ b/mobile/lib/shared/views/tab_controller_page.dart @@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/constants/immich_colors.dart'; import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart'; import 'package:immich_mobile/routing/router.dart'; @@ -18,6 +19,7 @@ class TabControllerPage extends ConsumerWidget { const HomeRoute(), SearchRoute(), const SharingRoute(), + const LibraryRoute() ], builder: (context, child, animation) { final tabsRouter = AutoTabsRouter.of(context); @@ -34,12 +36,14 @@ class TabControllerPage extends ConsumerWidget { bottomNavigationBar: isMultiSelectEnable ? null : BottomNavigationBar( + type: BottomNavigationBarType.fixed, + backgroundColor: immichBackgroundColor, selectedLabelStyle: const TextStyle( - fontSize: 15, + fontSize: 13, fontWeight: FontWeight.w600, ), unselectedLabelStyle: const TextStyle( - fontSize: 15, + fontSize: 13, fontWeight: FontWeight.w600, ), currentIndex: tabsRouter.activeIndex, @@ -59,6 +63,12 @@ class TabControllerPage extends ConsumerWidget { label: 'tab_controller_nav_sharing'.tr(), icon: const Icon(Icons.group_outlined), ), + BottomNavigationBarItem( + label: 'tab_controller_nav_library'.tr(), + icon: const Icon( + Icons.photo_album_outlined, + ), + ) ], ), ),