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

View File

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