add albums to dedicated item menu

This commit is contained in:
Alex 2024-09-11 13:56:31 -05:00
parent bee7cd9683
commit e69bcf3f70
No known key found for this signature in database
GPG Key ID: 53CD082B3A5E1082
6 changed files with 169 additions and 86 deletions

View File

@ -8,11 +8,14 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_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/album_sort_by_options.provider.dart';
import 'package:immich_mobile/providers/album/albumv2.provider.dart'; import 'package:immich_mobile/providers/album/albumv2.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart'; import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/widgets/album/album_thumbnail_card.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'; import 'package:immich_mobile/widgets/common/immich_thumbnail.dart';
enum QuickFilterMode { enum QuickFilterMode {
@ -23,7 +26,10 @@ enum QuickFilterMode {
@RoutePage() @RoutePage()
class AlbumsCollectionPage extends HookConsumerWidget { class AlbumsCollectionPage extends HookConsumerWidget {
const AlbumsCollectionPage({super.key}); const AlbumsCollectionPage({super.key, this.showImmichAppbar = false});
final bool showImmichAppbar;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final albums = final albums =
@ -72,7 +78,13 @@ class AlbumsCollectionPage extends HookConsumerWidget {
return Scaffold( return Scaffold(
appBar: AppBar( 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( body: ListView(
shrinkWrap: true, shrinkWrap: true,
@ -170,9 +182,11 @@ class AlbumsCollectionPage extends HookConsumerWidget {
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 8.0), padding: const EdgeInsets.only(bottom: 8.0),
child: ListTile( child: LargeLeadingTile(
title: Text( title: Text(
sorted[index].name, sorted[index].name,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: context.textTheme.titleSmall?.copyWith( style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
@ -180,6 +194,7 @@ class AlbumsCollectionPage extends HookConsumerWidget {
subtitle: sorted[index].ownerId == userId subtitle: sorted[index].ownerId == userId
? Text( ? Text(
'${sorted[index].assetCount} items', '${sorted[index].assetCount} items',
overflow: TextOverflow.ellipsis,
style: context.textTheme.bodyMedium?.copyWith( style: context.textTheme.bodyMedium?.copyWith(
color: color:
context.colorScheme.onSurfaceSecondary, context.colorScheme.onSurfaceSecondary,
@ -192,6 +207,7 @@ class AlbumsCollectionPage extends HookConsumerWidget {
sorted[index].ownerName!, sorted[index].ownerName!,
], ],
)}', )}',
overflow: TextOverflow.ellipsis,
style: context.textTheme.bodyMedium style: context.textTheme.bodyMedium
?.copyWith( ?.copyWith(
color: context color: context
@ -202,19 +218,19 @@ class AlbumsCollectionPage extends HookConsumerWidget {
onTap: () => context.pushRoute( onTap: () => context.pushRoute(
AlbumViewerRoute(albumId: sorted[index].id), AlbumViewerRoute(albumId: sorted[index].id),
), ),
contentPadding: const EdgeInsets.all(0), leadingPadding: const EdgeInsets.only(
dense: false, right: 16,
visualDensity: VisualDensity.comfortable, ),
leading: ClipRRect( leading: ClipRRect(
borderRadius: borderRadius:
const BorderRadius.all(Radius.circular(15)), const BorderRadius.all(Radius.circular(15)),
child: ImmichThumbnail( child: ImmichThumbnail(
asset: sorted[index].thumbnail.value, asset: sorted[index].thumbnail.value,
width: 60, width: 80,
height: 90, height: 80,
), ),
), ),
minVerticalPadding: 1, // minVerticalPadding: 1,
), ),
); );
}, },

View File

@ -154,11 +154,11 @@ class AlbumsCollectionCard extends HookConsumerWidget {
final size = MediaQuery.of(context).size.width * 0.5 - 20; final size = MediaQuery.of(context).size.width * 0.5 - 20;
return GestureDetector( return GestureDetector(
onTap: () => context.pushRoute( onTap: () => isLocal
isLocal ? context.pushRoute(
? const LocalAlbumsCollectionRoute() const LocalAlbumsCollectionRoute(),
: const AlbumsCollectionRoute(), )
), : context.pushRoute(AlbumsCollectionRoute()),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [

View File

@ -6,8 +6,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/entities/asset.entity.dart'; import 'package:immich_mobile/entities/asset.entity.dart';
import 'package:immich_mobile/entities/store.entity.dart'; import 'package:immich_mobile/entities/store.entity.dart';
import 'package:immich_mobile/extensions/build_context_extensions.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/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/providers/search/search_page_state.provider.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/services/api.service.dart'; import 'package:immich_mobile/services/api.service.dart';
@ -100,33 +100,25 @@ class PlaceTile extends StatelessWidget {
); );
} }
return InkWell( return LargeLeadingTile(
onTap: () => navigateToPlace(), onTap: () => navigateToPlace(),
child: Row( title: Text(
crossAxisAlignment: CrossAxisAlignment.center, name,
children: [ style: context.textTheme.titleMedium?.copyWith(
Padding( fontWeight: FontWeight.w500,
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16.0), ),
child: ClipRRect( ),
borderRadius: BorderRadius.circular(20), leading: ClipRRect(
child: CachedNetworkImage( borderRadius: BorderRadius.circular(20),
width: 80, child: CachedNetworkImage(
height: 80, width: 80,
fit: BoxFit.cover, height: 80,
imageUrl: thumbnailUrl, fit: BoxFit.cover,
httpHeaders: ApiService.getRequestHeaders(), imageUrl: thumbnailUrl,
errorWidget: (context, url, error) => httpHeaders: ApiService.getRequestHeaders(),
const Icon(Icons.image_not_supported_outlined), errorWidget: (context, url, error) =>
), const Icon(Icons.image_not_supported_outlined),
), ),
),
Text(
name,
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w500,
),
),
],
), ),
); );
} }

View File

@ -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(),
],
),
],
),
);
}
}

View File

@ -76,6 +76,18 @@ class TabControllerPage extends HookConsumerWidget {
selectedIcon: const Icon(Icons.photo_library), selectedIcon: const Icon(Icons.photo_library),
label: const Text('tab_controller_nav_photos').tr(), 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( NavigationRailDestination(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
icon: const Icon(Icons.search_rounded), icon: const Icon(Icons.search_rounded),
@ -94,18 +106,6 @@ class TabControllerPage extends HookConsumerWidget {
// selectedIcon: const Icon(Icons.photo_album), // selectedIcon: const Icon(Icons.photo_album),
// label: const Text('tab_controller_nav_library').tr(), // 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( NavigationDestination(
label: 'tab_controller_nav_search'.tr(), label: 'tab_controller_nav_search'.tr(),
icon: const Icon( 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); final multiselectEnabled = ref.watch(multiselectProvider);
return AutoTabsRouter( return AutoTabsRouter(
routes: const [ routes: [
PhotosRoute(), const PhotosRoute(),
SearchRoute(), AlbumsCollectionRoute(showImmichAppbar: true),
const CollectionsRoute(),
// SharingRoute(), // SharingRoute(),
// LibraryRoute(), // LibraryRoute(),
AlbumsCollectionRoute(), const SearchRoute(),
CollectionsRoute(),
], ],
duration: const Duration(milliseconds: 600), duration: const Duration(milliseconds: 600),
transitionBuilder: (context, child, animation) => FadeTransition( transitionBuilder: (context, child, animation) => FadeTransition(

View File

@ -321,10 +321,17 @@ class AlbumViewerRouteArgs {
/// generated route for /// generated route for
/// [AlbumsCollectionPage] /// [AlbumsCollectionPage]
class AlbumsCollectionRoute extends PageRouteInfo<void> { class AlbumsCollectionRoute extends PageRouteInfo<AlbumsCollectionRouteArgs> {
const AlbumsCollectionRoute({List<PageRouteInfo>? children}) AlbumsCollectionRoute({
: super( Key? key,
bool showImmichAppbar = false,
List<PageRouteInfo>? children,
}) : super(
AlbumsCollectionRoute.name, AlbumsCollectionRoute.name,
args: AlbumsCollectionRouteArgs(
key: key,
showImmichAppbar: showImmichAppbar,
),
initialChildren: children, initialChildren: children,
); );
@ -333,11 +340,32 @@ class AlbumsCollectionRoute extends PageRouteInfo<void> {
static PageInfo page = PageInfo( static PageInfo page = PageInfo(
name, name,
builder: (data) { builder: (data) {
return const AlbumsCollectionPage(); final args = data.argsAs<AlbumsCollectionRouteArgs>(
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 /// generated route for
/// [AllMotionPhotosPage] /// [AllMotionPhotosPage]
class AllMotionPhotosRoute extends PageRouteInfo<void> { class AllMotionPhotosRoute extends PageRouteInfo<void> {