You've already forked immich
mirror of
https://github.com/immich-app/immich.git
synced 2025-08-07 23:03:36 +02:00
feat(mobile): drift local albums page (#19817)
* feat(mobile): drift local albums page * fix: lint * refactor: use AsyncValue * fix: lint * local album thumbnail --------- Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
116
mobile/lib/presentation/pages/dev/drift_local_album.page.dart
Normal file
116
mobile/lib/presentation/pages/dev/drift_local_album.page.dart
Normal file
@ -0,0 +1,116 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.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/extensions/translate_extensions.dart';
|
||||
import 'package:immich_mobile/pages/common/large_leading_tile.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/local_album_thumbnail.widget.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/widgets/common/local_album_sliver_app_bar.dart';
|
||||
|
||||
@RoutePage()
|
||||
class DriftLocalAlbumsPage extends StatelessWidget {
|
||||
const DriftLocalAlbumsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
LocalAlbumsSliverAppBar(),
|
||||
_AlbumList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AlbumList extends ConsumerWidget {
|
||||
const _AlbumList();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final albums = ref.watch(localAlbumProvider);
|
||||
|
||||
return albums.when(
|
||||
loading: () => const SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(20.0),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
),
|
||||
error: (error, stack) => SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: Text(
|
||||
'Error loading albums: $error, stack: $stack',
|
||||
style: TextStyle(
|
||||
color: context.colorScheme.error,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
data: (albums) {
|
||||
if (albums.isEmpty) {
|
||||
return const SliverToBoxAdapter(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(20.0),
|
||||
child: Text('No albums found'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.all(18.0),
|
||||
sliver: SliverList.builder(
|
||||
itemBuilder: (_, index) {
|
||||
final album = albums[index];
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: LargeLeadingTile(
|
||||
leadingPadding: const EdgeInsets.only(
|
||||
right: 16,
|
||||
),
|
||||
leading: SizedBox(
|
||||
width: 80,
|
||||
height: 80,
|
||||
child: LocalAlbumThumbnail(
|
||||
albumId: album.id,
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
album.name,
|
||||
style: context.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
'items_count'.t(
|
||||
context: context,
|
||||
args: {'count': album.assetCount},
|
||||
),
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: context.colorScheme.onSurfaceSecondary,
|
||||
),
|
||||
),
|
||||
onTap: () =>
|
||||
context.pushRoute(LocalTimelineRoute(albumId: album.id)),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: albums.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -5,14 +5,14 @@ import 'package:immich_mobile/domain/models/user.model.dart';
|
||||
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||
import 'package:immich_mobile/providers/album/album.provider.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/local_album_thumbnail.widget.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||
import 'package:immich_mobile/providers/partner.provider.dart';
|
||||
import 'package:immich_mobile/providers/search/people.provider.dart';
|
||||
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||
import 'package:immich_mobile/routing/router.dart';
|
||||
import 'package:immich_mobile/services/api.service.dart';
|
||||
import 'package:immich_mobile/utils/image_url_builder.dart';
|
||||
import 'package:immich_mobile/widgets/album/album_thumbnail_card.dart';
|
||||
import 'package:immich_mobile/widgets/common/immich_sliver_app_bar.dart';
|
||||
import 'package:immich_mobile/widgets/common/user_avatar.dart';
|
||||
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
|
||||
@ -305,8 +305,7 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
// TODO: Migrate to the drift after local album page
|
||||
final albums = ref.watch(localAlbumsProvider);
|
||||
final albums = ref.watch(localAlbumProvider);
|
||||
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
@ -315,9 +314,7 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
|
||||
final size = context.width * widthFactor - 20.0;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => context.pushRoute(
|
||||
const LocalAlbumsRoute(),
|
||||
),
|
||||
onTap: () => context.pushRoute(const DriftLocalAlbumsRoute()),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -342,12 +339,29 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisSpacing: 8,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: albums.take(4).map((album) {
|
||||
return AlbumThumbnailCard(
|
||||
album: album,
|
||||
showTitle: false,
|
||||
);
|
||||
}).toList(),
|
||||
children: albums.when(
|
||||
data: (data) {
|
||||
return data.take(4).map((album) {
|
||||
return LocalAlbumThumbnail(
|
||||
albumId: album.id,
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
error: (error, _) {
|
||||
return [
|
||||
Center(
|
||||
child: Text('Error: $error'),
|
||||
),
|
||||
];
|
||||
},
|
||||
loading: () {
|
||||
return [
|
||||
const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -0,0 +1,54 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
|
||||
|
||||
class LocalAlbumThumbnail extends ConsumerWidget {
|
||||
const LocalAlbumThumbnail({
|
||||
super.key,
|
||||
required this.albumId,
|
||||
});
|
||||
|
||||
final String albumId;
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final localAlbumThumbnail = ref.watch(localAlbumThumbnailProvider(albumId));
|
||||
return localAlbumThumbnail.when(
|
||||
data: (data) {
|
||||
if (data == null) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: context.colorScheme.surfaceContainer,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
border: Border.all(
|
||||
color: context.colorScheme.outline.withAlpha(50),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.collections,
|
||||
size: 24,
|
||||
color: context.primaryColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
child: Thumbnail(
|
||||
asset: data,
|
||||
),
|
||||
);
|
||||
},
|
||||
error: (error, stack) {
|
||||
return const Icon(Icons.error, size: 24);
|
||||
},
|
||||
loading: () => const SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user