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 'dart:math';
|
||||||
|
|
||||||
import 'package:auto_route/auto_route.dart';
|
import 'package:auto_route/auto_route.dart';
|
||||||
@ -21,8 +22,9 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
|||||||
final albumSortIsReverse = ref.watch(albumSortOrderProvider);
|
final albumSortIsReverse = ref.watch(albumSortOrderProvider);
|
||||||
final remote = albums.where((a) => a.isRemote).toList();
|
final remote = albums.where((a) => a.isRemote).toList();
|
||||||
final sorted = albumSortOption.sortFn(remote, albumSortIsReverse);
|
final sorted = albumSortOption.sortFn(remote, albumSortIsReverse);
|
||||||
final local = albums.where((a) => a.isLocal).toList();
|
final isGrid = useState(true);
|
||||||
final isGrid = useState(false);
|
final searchController = useTextEditingController();
|
||||||
|
final debounceTimer = useRef<Timer?>(null);
|
||||||
|
|
||||||
useEffect(
|
useEffect(
|
||||||
() {
|
() {
|
||||||
@ -36,6 +38,28 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
|||||||
isGrid.value = !isGrid.value;
|
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(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("Albums"),
|
title: const Text("Albums"),
|
||||||
@ -44,6 +68,30 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
|||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
padding: const EdgeInsets.all(18.0),
|
padding: const EdgeInsets.all(18.0),
|
||||||
children: [
|
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(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -51,46 +99,53 @@ class AlbumsCollectionPage extends HookConsumerWidget {
|
|||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
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,
|
onPressed: toggleViewMode,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isGrid.value)
|
const SizedBox(height: 16),
|
||||||
GridView.builder(
|
AnimatedSwitcher(
|
||||||
shrinkWrap: true,
|
duration: const Duration(milliseconds: 500),
|
||||||
physics: const ClampingScrollPhysics(),
|
child: isGrid.value
|
||||||
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
? GridView.builder(
|
||||||
maxCrossAxisExtent: 250,
|
shrinkWrap: true,
|
||||||
mainAxisSpacing: 12,
|
physics: const ClampingScrollPhysics(),
|
||||||
crossAxisSpacing: 12,
|
gridDelegate:
|
||||||
childAspectRatio: .7,
|
const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
),
|
maxCrossAxisExtent: 250,
|
||||||
itemBuilder: (context, index) {
|
mainAxisSpacing: 12,
|
||||||
return AlbumThumbnailCard(
|
crossAxisSpacing: 12,
|
||||||
album: sorted[index],
|
childAspectRatio: .7,
|
||||||
onTap: () => context.pushRoute(
|
),
|
||||||
AlbumViewerRoute(albumId: sorted[index].id),
|
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);
|
final albumSortIsReverse = ref.watch(albumSortOrderProvider);
|
||||||
|
|
||||||
return MenuAnchor(
|
return MenuAnchor(
|
||||||
|
style: MenuStyle(
|
||||||
|
shape: WidgetStateProperty.all(
|
||||||
|
RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
consumeOutsideTap: true,
|
||||||
menuChildren: AlbumSortMode.values
|
menuChildren: AlbumSortMode.values
|
||||||
.map(
|
.map(
|
||||||
(mode) => MenuItemButton(
|
(mode) => MenuItemButton(
|
||||||
@ -144,6 +207,11 @@ class SortButton extends ConsumerWidget {
|
|||||||
? context.colorScheme.primary
|
? context.colorScheme.primary
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
),
|
),
|
||||||
|
shape: WidgetStateProperty.all(
|
||||||
|
RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
mode.label.tr(),
|
mode.label.tr(),
|
||||||
|
@ -12,7 +12,7 @@ import 'package:immich_mobile/utils/renderlist_generator.dart';
|
|||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
|
||||||
class AlbumNotifier extends StateNotifier<List<Album>> {
|
class AlbumNotifier extends StateNotifier<List<Album>> {
|
||||||
AlbumNotifier(this._albumService, Isar db) : super([]) {
|
AlbumNotifier(this._albumService, this.db) : super([]) {
|
||||||
final query = db.albums
|
final query = db.albums
|
||||||
.filter()
|
.filter()
|
||||||
.owner((q) => q.isarIdEqualTo(Store.get(StoreKey.currentUser).isarId));
|
.owner((q) => q.isarIdEqualTo(Store.get(StoreKey.currentUser).isarId));
|
||||||
@ -25,6 +25,7 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final AlbumService _albumService;
|
final AlbumService _albumService;
|
||||||
|
final Isar db;
|
||||||
late final StreamSubscription<List<Album>> _streamSub;
|
late final StreamSubscription<List<Album>> _streamSub;
|
||||||
|
|
||||||
Future<void> getAllAlbums() => Future.wait([
|
Future<void> getAllAlbums() => Future.wait([
|
||||||
@ -64,6 +65,16 @@ class AlbumNotifier extends StateNotifier<List<Album>> {
|
|||||||
_streamSub.cancel();
|
_streamSub.cancel();
|
||||||
super.dispose();
|
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 =
|
final albumProvider =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user