From bfbbb69ff9e2d07042736a8088935c7729882ed7 Mon Sep 17 00:00:00 2001 From: Augsorn Chanklad Date: Wed, 1 May 2024 19:58:59 +0700 Subject: [PATCH] Add song filter --- .../songs_list_filter_screen.dart | 52 +++++++++++++++ .../songs_list_screen/songs_list_screen.dart | 3 +- .../widgets/dropdown_song_sort.dart | 44 +++++++++++++ .../widgets/dropdown_song_types.dart | 64 +++++++++++++++++++ lib/src/routing/app_route_context.dart | 3 + lib/src/routing/app_router.dart | 11 ++++ 6 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 lib/src/features/songs/presentation/songs_list_screen/songs_list_filter_screen.dart create mode 100644 lib/src/features/songs/presentation/widgets/dropdown_song_sort.dart create mode 100644 lib/src/features/songs/presentation/widgets/dropdown_song_types.dart diff --git a/lib/src/features/songs/presentation/songs_list_screen/songs_list_filter_screen.dart b/lib/src/features/songs/presentation/songs_list_screen/songs_list_filter_screen.dart new file mode 100644 index 00000000..867d2c14 --- /dev/null +++ b/lib/src/features/songs/presentation/songs_list_screen/songs_list_filter_screen.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:vocadb_app/src/features/songs/presentation/songs_list_screen/songs_list_params_state.dart'; +import 'package:vocadb_app/src/features/songs/presentation/widgets/dropdown_song_sort.dart'; +import 'package:vocadb_app/src/features/songs/presentation/widgets/dropdown_song_types.dart'; +import 'package:vocadb_app/src/features/tags/presentation/tag_widgets/tag_input.dart'; + +class SongsFilterScreen extends StatelessWidget { + const SongsFilterScreen( + {super.key, this.onSortChanged, this.onSongTypesChanged}); + + final Function(String?)? onSongTypesChanged; + + final Function(String?)? onSortChanged; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Filter'), + ), + body: Consumer( + builder: (context, ref, child) { + final state = ref.watch(songsListParamsStateProvider); + + return ListView( + children: [ + DropdownSongTypes( + value: state.songTypes ?? '', + onChanged: (value) => + onSongTypesChanged?.call(value) ?? + ref + .read(songsListParamsStateProvider.notifier) + .updateSongTypes(value!), + ), + DropdownSongSort( + value: 'Name', + onChanged: (value) => + onSortChanged?.call(value) ?? + ref + .read(songsListParamsStateProvider.notifier) + .updateSort(value!), + ), + const Divider(), + const TagInput(), + ], + ); + }, + ), + ); + } +} diff --git a/lib/src/features/songs/presentation/songs_list_screen/songs_list_screen.dart b/lib/src/features/songs/presentation/songs_list_screen/songs_list_screen.dart index 82ddaea2..24e4f0d0 100644 --- a/lib/src/features/songs/presentation/songs_list_screen/songs_list_screen.dart +++ b/lib/src/features/songs/presentation/songs_list_screen/songs_list_screen.dart @@ -7,6 +7,7 @@ import 'package:vocadb_app/src/features/songs/data/song_repository.dart'; import 'package:vocadb_app/src/features/songs/domain/song.dart'; import 'package:vocadb_app/src/features/songs/presentation/songs_list/songs_list_view.dart'; import 'package:vocadb_app/src/features/songs/presentation/songs_list_screen/songs_list_params_state.dart'; +import 'package:vocadb_app/src/routing/app_route_context.dart'; class SongsListScreen extends ConsumerWidget { const SongsListScreen({super.key, this.onSelectSong}); @@ -24,7 +25,7 @@ class SongsListScreen extends ConsumerWidget { IconButton( key: filterKey, icon: const Icon(Icons.tune), - onPressed: () => {} + onPressed: () => context.goSongsListFilterScreen(), ), ], onSubmitted: (value) { diff --git a/lib/src/features/songs/presentation/widgets/dropdown_song_sort.dart b/lib/src/features/songs/presentation/widgets/dropdown_song_sort.dart new file mode 100644 index 00000000..538aec87 --- /dev/null +++ b/lib/src/features/songs/presentation/widgets/dropdown_song_sort.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:vocadb_app/src/common_widgets/dropdown_tile.dart'; + +class DropdownSongSort extends StatelessWidget { + const DropdownSongSort({super.key, required this.value, this.onChanged}); + + static const dropdownKey = Key('dropdown-artist-sort-key'); + + final String value; + + final Function(String?)? onChanged; + + @override + Widget build(BuildContext context) { + return DropdownTile( + dropdownButtonKey: dropdownKey, + value: value, + label: 'Sort', + onChanged: onChanged, + items: const [ + DropdownMenuItem( + value: 'Name', + child: Text('Name'), + ), + DropdownMenuItem( + value: 'AdditionDate', + child: Text('Addition date'), + ), + DropdownMenuItem( + value: 'PublishDate', + child: Text('Publish date'), + ), + DropdownMenuItem( + value: 'FavoritedTimes', + child: Text('Times favorited'), + ), + DropdownMenuItem( + value: 'RatingScore', + child: Text('Rating score'), + ), + ], + ); + } +} diff --git a/lib/src/features/songs/presentation/widgets/dropdown_song_types.dart b/lib/src/features/songs/presentation/widgets/dropdown_song_types.dart new file mode 100644 index 00000000..1f94a3f1 --- /dev/null +++ b/lib/src/features/songs/presentation/widgets/dropdown_song_types.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:vocadb_app/src/common_widgets/dropdown_tile.dart'; + +class DropdownSongTypes extends StatelessWidget { + const DropdownSongTypes({super.key, required this.value, this.onChanged}); + + static const dropdownKey = Key('dropdown-song-types-key'); + + final String value; + + final Function(String?)? onChanged; + + @override + Widget build(BuildContext context) { + return DropdownTile( + dropdownButtonKey: dropdownKey, + value: value, + label: 'Song Types', + onChanged: onChanged, + items: const [ + DropdownMenuItem( + value: '', + child: Text('Unspecified'), + ), + DropdownMenuItem( + value: 'Original', + child: Text('Original song'), + ), + DropdownMenuItem( + value: 'Remaster', + child: Text('Remaster'), + ), + DropdownMenuItem( + value: 'Remix', + child: Text('Remix'), + ), + DropdownMenuItem( + value: 'Cover', + child: Text('Cover'), + ), + DropdownMenuItem( + value: 'Instrumental', + child: Text('Instrumental'), + ), + DropdownMenuItem( + value: 'Mashup', + child: Text('Mashup'), + ), + DropdownMenuItem( + value: 'MusicPV', + child: Text('Music PV'), + ), + DropdownMenuItem( + value: 'DramaPV', + child: Text('Drama PV'), + ), + DropdownMenuItem( + value: 'Other', + child: Text('Other'), + ), + ], + ); + } +} diff --git a/lib/src/routing/app_route_context.dart b/lib/src/routing/app_route_context.dart index 56a6eb0a..8aade90f 100644 --- a/lib/src/routing/app_route_context.dart +++ b/lib/src/routing/app_route_context.dart @@ -41,7 +41,10 @@ extension AppRouteContext on BuildContext { Future goArtistsListFilterScreen() async { goNamed(AppRoute.artistsListFilter.name); + } + Future goSongsListFilterScreen() async { + goNamed(AppRoute.songsListFilter.name); } Future goEntryDetail(Entry entry) async { diff --git a/lib/src/routing/app_router.dart b/lib/src/routing/app_router.dart index c2b1252e..0e416b1b 100644 --- a/lib/src/routing/app_router.dart +++ b/lib/src/routing/app_router.dart @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:vocadb_app/src/features/albums/domain/album.dart'; import 'package:vocadb_app/src/features/albums/presentation/album_detail_screen/album_detail_screen.dart'; +import 'package:vocadb_app/src/features/songs/presentation/songs_list_screen/songs_list_filter_screen.dart'; import 'package:vocadb_app/src/features/songs/presentation/songs_list_screen/songs_list_screen.dart'; import 'package:vocadb_app/src/features/users/presentation/user_albums_screen/user_albums_filter_screen.dart'; import 'package:vocadb_app/src/features/users/presentation/user_albums_screen/user_albums_screen.dart'; @@ -37,6 +38,7 @@ enum AppRoute { account, signIn, songsList, + songsListFilter, albumDetail, artistDetail, artistsList, @@ -94,6 +96,15 @@ final goRouterProvider = Provider.autoDispose( }); }, routes: [ + GoRoute( + path: 'Filter', + name: AppRoute.songsListFilter.name, + pageBuilder: (context, state) => MaterialPage( + key: state.pageKey, + fullscreenDialog: true, + child: const SongsFilterScreen(), + ), + ), GoRoute( path: ':id', name: AppRoute.songDetail.name,