mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:06:56 -04:00
search album
This commit is contained in:
parent
31f2b94396
commit
77bfa5d445
@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
@ -21,8 +22,9 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
||||
final albumSortIsReverse = ref.watch(albumSortOrderProvider);
|
||||
final remote = albums.where((a) => a.isRemote).toList();
|
||||
final sorted = albumSortOption.sortFn(remote, albumSortIsReverse);
|
||||
final local = albums.where((a) => a.isLocal).toList();
|
||||
final isGrid = useState(false);
|
||||
final isGrid = useState(true);
|
||||
final searchController = useTextEditingController();
|
||||
final debounceTimer = useRef<Timer?>(null);
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
@ -36,6 +38,28 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
||||
isGrid.value = !isGrid.value;
|
||||
}
|
||||
|
||||
onSearch(String value) {
|
||||
debounceTimer.value?.cancel();
|
||||
debounceTimer.value = Timer(const Duration(milliseconds: 300), () {
|
||||
ref.read(albumProvider.notifier).searchAlbums(value);
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
searchController.addListener(() {
|
||||
onSearch(searchController.text);
|
||||
});
|
||||
return () {
|
||||
searchController.removeListener(() {
|
||||
onSearch(searchController.text);
|
||||
});
|
||||
debounceTimer.value?.cancel();
|
||||
};
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Albums"),
|
||||
@ -44,6 +68,30 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
||||
shrinkWrap: true,
|
||||
padding: const EdgeInsets.all(18.0),
|
||||
children: [
|
||||
SearchBar(
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
context.colorScheme.surfaceContainer,
|
||||
),
|
||||
autoFocus: false,
|
||||
hintText: "Search albums",
|
||||
onChanged: onSearch,
|
||||
elevation: const WidgetStatePropertyAll(0.25),
|
||||
controller: searchController,
|
||||
leading: const Icon(Icons.search_rounded),
|
||||
padding: WidgetStateProperty.all(
|
||||
const EdgeInsets.symmetric(horizontal: 16),
|
||||
),
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
side: BorderSide(
|
||||
color: context.colorScheme.onSurface.withAlpha(10),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
@ -51,46 +99,53 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
||||
const SizedBox(width: 10),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
isGrid.value ? Icons.list_rounded : Icons.grid_view_outlined,
|
||||
isGrid.value
|
||||
? Icons.view_list_rounded
|
||||
: Icons.grid_view_outlined,
|
||||
size: 24,
|
||||
),
|
||||
onPressed: toggleViewMode,
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isGrid.value)
|
||||
GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 250,
|
||||
mainAxisSpacing: 12,
|
||||
crossAxisSpacing: 12,
|
||||
childAspectRatio: .7,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return AlbumThumbnailCard(
|
||||
album: sorted[index],
|
||||
onTap: () => context.pushRoute(
|
||||
AlbumViewerRoute(albumId: sorted[index].id),
|
||||
const SizedBox(height: 16),
|
||||
AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
child: isGrid.value
|
||||
? GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
maxCrossAxisExtent: 250,
|
||||
mainAxisSpacing: 12,
|
||||
crossAxisSpacing: 12,
|
||||
childAspectRatio: .7,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
return AlbumThumbnailCard(
|
||||
album: sorted[index],
|
||||
onTap: () => context.pushRoute(
|
||||
AlbumViewerRoute(albumId: sorted[index].id),
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: sorted.length,
|
||||
)
|
||||
: ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemCount: sorted.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(sorted[index].name),
|
||||
onTap: () => context.pushRoute(
|
||||
AlbumViewerRoute(albumId: sorted[index].id),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
itemCount: sorted.length,
|
||||
)
|
||||
else
|
||||
ListView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const ClampingScrollPhysics(),
|
||||
itemCount: sorted.length,
|
||||
itemBuilder: (context, index) {
|
||||
return ListTile(
|
||||
title: Text(sorted[index].name),
|
||||
onTap: () => context.pushRoute(
|
||||
AlbumViewerRoute(albumId: sorted[index].id),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
@ -106,6 +161,14 @@ class SortButton extends ConsumerWidget {
|
||||
final albumSortIsReverse = ref.watch(albumSortOrderProvider);
|
||||
|
||||
return MenuAnchor(
|
||||
style: MenuStyle(
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
),
|
||||
),
|
||||
consumeOutsideTap: true,
|
||||
menuChildren: AlbumSortMode.values
|
||||
.map(
|
||||
(mode) => MenuItemButton(
|
||||
@ -144,6 +207,11 @@ class SortButton extends ConsumerWidget {
|
||||
? context.colorScheme.primary
|
||||
: Colors.transparent,
|
||||
),
|
||||
shape: WidgetStateProperty.all(
|
||||
RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
mode.label.tr(),
|
||||
|
@ -12,7 +12,7 @@ import 'package:immich_mobile/utils/renderlist_generator.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
AlbumNotifier(this._albumService, Isar db) : super([]) {
|
||||
AlbumNotifier(this._albumService, this.db) : super([]) {
|
||||
final query = db.albums
|
||||
.filter()
|
||||
.owner((q) => q.isarIdEqualTo(Store.get(StoreKey.currentUser).isarId));
|
||||
@ -25,6 +25,7 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
}
|
||||
|
||||
final AlbumService _albumService;
|
||||
final Isar db;
|
||||
late final StreamSubscription<List<Album>> _streamSub;
|
||||
|
||||
Future<void> getAllAlbums() => Future.wait([
|
||||
@ -64,6 +65,16 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||
_streamSub.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void searchAlbums(String value) async {
|
||||
final query = db.albums
|
||||
.filter()
|
||||
.owner((q) => q.isarIdEqualTo(Store.get(StoreKey.currentUser).isarId))
|
||||
.nameContains(value, caseSensitive: false);
|
||||
|
||||
final albums = await query.findAll();
|
||||
state = albums;
|
||||
}
|
||||
}
|
||||
|
||||
final albumProvider =
|
||||
|
Loading…
x
Reference in New Issue
Block a user