diff --git a/mobile/lib/pages/collections/albums/albums_collection.page.dart b/mobile/lib/pages/collections/albums/albums_collection.page.dart index f51b6dc01ab05..f71bfbafc0a52 100644 --- a/mobile/lib/pages/collections/albums/albums_collection.page.dart +++ b/mobile/lib/pages/collections/albums/albums_collection.page.dart @@ -8,11 +8,14 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; +import 'package:immich_mobile/main.dart'; +import 'package:immich_mobile/pages/common/large_leading_tile.dart'; import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dart'; import 'package:immich_mobile/providers/album/albumv2.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/widgets/album/album_thumbnail_card.dart'; +import 'package:immich_mobile/widgets/common/immich_app_bar.dart'; import 'package:immich_mobile/widgets/common/immich_thumbnail.dart'; enum QuickFilterMode { @@ -23,7 +26,10 @@ enum QuickFilterMode { @RoutePage() class AlbumsCollectionPage extends HookConsumerWidget { - const AlbumsCollectionPage({super.key}); + const AlbumsCollectionPage({super.key, this.showImmichAppbar = false}); + + final bool showImmichAppbar; + @override Widget build(BuildContext context, WidgetRef ref) { final albums = @@ -72,7 +78,13 @@ class AlbumsCollectionPage extends HookConsumerWidget { return Scaffold( appBar: AppBar( - title: Text("Albums ${albums.length}"), + title: showImmichAppbar ? null : Text('albums'.tr()), + bottom: showImmichAppbar + ? const PreferredSize( + preferredSize: Size.fromHeight(0), + child: ImmichAppBar(), + ) + : null, ), body: ListView( shrinkWrap: true, @@ -170,9 +182,11 @@ class AlbumsCollectionPage extends HookConsumerWidget { itemBuilder: (context, index) { return Padding( padding: const EdgeInsets.only(bottom: 8.0), - child: ListTile( + child: LargeLeadingTile( title: Text( sorted[index].name, + maxLines: 2, + overflow: TextOverflow.ellipsis, style: context.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w600, ), @@ -180,6 +194,7 @@ class AlbumsCollectionPage extends HookConsumerWidget { subtitle: sorted[index].ownerId == userId ? Text( '${sorted[index].assetCount} items', + overflow: TextOverflow.ellipsis, style: context.textTheme.bodyMedium?.copyWith( color: context.colorScheme.onSurfaceSecondary, @@ -192,6 +207,7 @@ class AlbumsCollectionPage extends HookConsumerWidget { sorted[index].ownerName!, ], )}', + overflow: TextOverflow.ellipsis, style: context.textTheme.bodyMedium ?.copyWith( color: context @@ -202,19 +218,19 @@ class AlbumsCollectionPage extends HookConsumerWidget { onTap: () => context.pushRoute( AlbumViewerRoute(albumId: sorted[index].id), ), - contentPadding: const EdgeInsets.all(0), - dense: false, - visualDensity: VisualDensity.comfortable, + leadingPadding: const EdgeInsets.only( + right: 16, + ), leading: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(15)), child: ImmichThumbnail( asset: sorted[index].thumbnail.value, - width: 60, - height: 90, + width: 80, + height: 80, ), ), - minVerticalPadding: 1, + // minVerticalPadding: 1, ), ); }, diff --git a/mobile/lib/pages/collections/collections.page.dart b/mobile/lib/pages/collections/collections.page.dart index 8cf13f8354b4d..c37103788161f 100644 --- a/mobile/lib/pages/collections/collections.page.dart +++ b/mobile/lib/pages/collections/collections.page.dart @@ -154,11 +154,11 @@ class AlbumsCollectionCard extends HookConsumerWidget { final size = MediaQuery.of(context).size.width * 0.5 - 20; return GestureDetector( - onTap: () => context.pushRoute( - isLocal - ? const LocalAlbumsCollectionRoute() - : const AlbumsCollectionRoute(), - ), + onTap: () => isLocal + ? context.pushRoute( + const LocalAlbumsCollectionRoute(), + ) + : context.pushRoute(AlbumsCollectionRoute()), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ diff --git a/mobile/lib/pages/collections/places/places_collection.part.dart b/mobile/lib/pages/collections/places/places_collection.part.dart index 97c6dffddba0c..639c5f0c6c356 100644 --- a/mobile/lib/pages/collections/places/places_collection.part.dart +++ b/mobile/lib/pages/collections/places/places_collection.part.dart @@ -6,8 +6,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/models/search/search_curated_content.model.dart'; import 'package:immich_mobile/models/search/search_filter.model.dart'; +import 'package:immich_mobile/pages/common/large_leading_tile.dart'; import 'package:immich_mobile/providers/search/search_page_state.provider.dart'; import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/services/api.service.dart'; @@ -100,33 +100,25 @@ class PlaceTile extends StatelessWidget { ); } - return InkWell( + return LargeLeadingTile( onTap: () => navigateToPlace(), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16.0), - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: CachedNetworkImage( - width: 80, - height: 80, - fit: BoxFit.cover, - imageUrl: thumbnailUrl, - httpHeaders: ApiService.getRequestHeaders(), - errorWidget: (context, url, error) => - const Icon(Icons.image_not_supported_outlined), - ), - ), - ), - Text( - name, - style: context.textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w500, - ), - ), - ], + title: Text( + name, + style: context.textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w500, + ), + ), + leading: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: CachedNetworkImage( + width: 80, + height: 80, + fit: BoxFit.cover, + imageUrl: thumbnailUrl, + httpHeaders: ApiService.getRequestHeaders(), + errorWidget: (context, url, error) => + const Icon(Icons.image_not_supported_outlined), + ), ), ); } diff --git a/mobile/lib/pages/common/large_leading_tile.dart b/mobile/lib/pages/common/large_leading_tile.dart new file mode 100644 index 0000000000000..7f1eb44dc6c76 --- /dev/null +++ b/mobile/lib/pages/common/large_leading_tile.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; + +class LargeLeadingTile extends StatelessWidget { + const LargeLeadingTile({ + super.key, + required this.leading, + required this.onTap, + required this.title, + this.subtitle, + this.leadingPadding = const EdgeInsets.symmetric( + vertical: 8, + horizontal: 16.0, + ), + }); + + final Widget leading; + final VoidCallback onTap; + final Widget title; + final Widget? subtitle; + final EdgeInsetsGeometry leadingPadding; + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: leadingPadding, + child: leading, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.6, + child: title, + ), + subtitle ?? const SizedBox.shrink(), + ], + ), + ], + ), + ); + } +} diff --git a/mobile/lib/pages/common/tab_controller.page.dart b/mobile/lib/pages/common/tab_controller.page.dart index 33faf101b6e15..8866f169c732f 100644 --- a/mobile/lib/pages/common/tab_controller.page.dart +++ b/mobile/lib/pages/common/tab_controller.page.dart @@ -76,6 +76,18 @@ class TabControllerPage extends HookConsumerWidget { selectedIcon: const Icon(Icons.photo_library), label: const Text('tab_controller_nav_photos').tr(), ), + NavigationRailDestination( + padding: const EdgeInsets.all(4), + icon: const Icon(Icons.photo_album_outlined), + selectedIcon: const Icon(Icons.photo_album), + label: const Text('albums').tr(), + ), + NavigationRailDestination( + padding: const EdgeInsets.all(4), + icon: const Icon(Icons.space_dashboard_outlined), + selectedIcon: const Icon(Icons.space_dashboard_rounded), + label: const Text('collections').tr(), + ), NavigationRailDestination( padding: const EdgeInsets.all(4), icon: const Icon(Icons.search_rounded), @@ -94,18 +106,6 @@ class TabControllerPage extends HookConsumerWidget { // selectedIcon: const Icon(Icons.photo_album), // label: const Text('tab_controller_nav_library').tr(), // ), - NavigationRailDestination( - padding: const EdgeInsets.all(4), - icon: const Icon(Icons.photo_album_outlined), - selectedIcon: const Icon(Icons.photo_album), - label: const Text('albums').tr(), - ), - NavigationRailDestination( - padding: const EdgeInsets.all(4), - icon: const Icon(Icons.space_dashboard_outlined), - selectedIcon: const Icon(Icons.space_dashboard_rounded), - label: const Text('collections').tr(), - ), ], ); } @@ -136,6 +136,30 @@ class TabControllerPage extends HookConsumerWidget { ), ), ), + NavigationDestination( + label: 'albums'.tr(), + icon: const Icon( + Icons.photo_album_outlined, + ), + selectedIcon: buildIcon( + Icon( + Icons.photo_album_rounded, + color: context.primaryColor, + ), + ), + ), + NavigationDestination( + label: 'collections'.tr(), + icon: const Icon( + Icons.space_dashboard_outlined, + ), + selectedIcon: buildIcon( + Icon( + Icons.space_dashboard_rounded, + color: context.primaryColor, + ), + ), + ), NavigationDestination( label: 'tab_controller_nav_search'.tr(), icon: const Icon( @@ -168,43 +192,19 @@ class TabControllerPage extends HookConsumerWidget { // ), // ), // ), - NavigationDestination( - label: 'albums'.tr(), - icon: const Icon( - Icons.photo_album_outlined, - ), - selectedIcon: buildIcon( - Icon( - Icons.photo_album_rounded, - color: context.primaryColor, - ), - ), - ), - NavigationDestination( - label: 'collections'.tr(), - icon: const Icon( - Icons.space_dashboard_outlined, - ), - selectedIcon: buildIcon( - Icon( - Icons.space_dashboard_rounded, - color: context.primaryColor, - ), - ), - ), ], ); } final multiselectEnabled = ref.watch(multiselectProvider); return AutoTabsRouter( - routes: const [ - PhotosRoute(), - SearchRoute(), + routes: [ + const PhotosRoute(), + AlbumsCollectionRoute(showImmichAppbar: true), + const CollectionsRoute(), // SharingRoute(), // LibraryRoute(), - AlbumsCollectionRoute(), - CollectionsRoute(), + const SearchRoute(), ], duration: const Duration(milliseconds: 600), transitionBuilder: (context, child, animation) => FadeTransition( diff --git a/mobile/lib/routing/router.gr.dart b/mobile/lib/routing/router.gr.dart index 16f65f948ba8f..cbd461d8845f5 100644 --- a/mobile/lib/routing/router.gr.dart +++ b/mobile/lib/routing/router.gr.dart @@ -321,10 +321,17 @@ class AlbumViewerRouteArgs { /// generated route for /// [AlbumsCollectionPage] -class AlbumsCollectionRoute extends PageRouteInfo { - const AlbumsCollectionRoute({List? children}) - : super( +class AlbumsCollectionRoute extends PageRouteInfo { + AlbumsCollectionRoute({ + Key? key, + bool showImmichAppbar = false, + List? children, + }) : super( AlbumsCollectionRoute.name, + args: AlbumsCollectionRouteArgs( + key: key, + showImmichAppbar: showImmichAppbar, + ), initialChildren: children, ); @@ -333,11 +340,32 @@ class AlbumsCollectionRoute extends PageRouteInfo { static PageInfo page = PageInfo( name, builder: (data) { - return const AlbumsCollectionPage(); + final args = data.argsAs( + orElse: () => const AlbumsCollectionRouteArgs()); + return AlbumsCollectionPage( + key: args.key, + showImmichAppbar: args.showImmichAppbar, + ); }, ); } +class AlbumsCollectionRouteArgs { + const AlbumsCollectionRouteArgs({ + this.key, + this.showImmichAppbar = false, + }); + + final Key? key; + + final bool showImmichAppbar; + + @override + String toString() { + return 'AlbumsCollectionRouteArgs{key: $key, showImmichAppbar: $showImmichAppbar}'; + } +} + /// generated route for /// [AllMotionPhotosPage] class AllMotionPhotosRoute extends PageRouteInfo {