search album

This commit is contained in:
Alex 2024-09-06 22:46:38 -05:00
parent 31f2b94396
commit 77bfa5d445
No known key found for this signature in database
GPG Key ID: 53CD082B3A5E1082
2 changed files with 116 additions and 37 deletions

View File

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

View File

@ -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 =