mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-09 07:28:14 -07:00
feature: Added option to save and set default filters for libraries (#107)
Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
parent
d3e34d57e0
commit
691293648b
23 changed files with 1353 additions and 62 deletions
|
|
@ -18,6 +18,7 @@ import 'package:fladder/providers/settings/client_settings_provider.dart';
|
|||
import 'package:fladder/providers/video_player_provider.dart';
|
||||
import 'package:fladder/screens/collections/add_to_collection.dart';
|
||||
import 'package:fladder/screens/library_search/widgets/library_filter_chips.dart';
|
||||
import 'package:fladder/screens/library_search/widgets/library_saved_filters.dart';
|
||||
import 'package:fladder/screens/library_search/widgets/library_sort_dialogue.dart';
|
||||
import 'package:fladder/screens/library_search/widgets/library_views.dart';
|
||||
import 'package:fladder/screens/library_search/widgets/suggestion_search_bar.dart';
|
||||
|
|
@ -31,6 +32,7 @@ import 'package:fladder/util/fab_extended_anim.dart';
|
|||
import 'package:fladder/util/item_base_model/item_base_model_extensions.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
import 'package:fladder/util/map_bool_helper.dart';
|
||||
import 'package:fladder/util/refresh_state.dart';
|
||||
import 'package:fladder/util/router_extension.dart';
|
||||
import 'package:fladder/util/sliver_list_padding.dart';
|
||||
|
|
@ -105,14 +107,12 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
|
||||
Future.microtask(
|
||||
() async {
|
||||
if (libraryProvider.mounted) {
|
||||
libraryProvider.setDefaultOptions(widget.sortOrder, widget.sortingOptions);
|
||||
}
|
||||
await refreshKey.currentState?.show();
|
||||
SystemChrome.setEnabledSystemUIMode(
|
||||
SystemUiMode.edgeToEdge,
|
||||
overlays: [],
|
||||
);
|
||||
|
||||
if (context.mounted && widget.photoToView != null) {
|
||||
libraryProvider.viewGallery(context, selected: widget.photoToView);
|
||||
}
|
||||
|
|
@ -133,7 +133,7 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
Widget build(BuildContext context) {
|
||||
final isEmptySearchScreen = widget.viewModelId == null && widget.favourites == null && widget.folderId == null;
|
||||
final librarySearchResults = ref.watch(providerKey);
|
||||
final postersList = librarySearchResults.posters.hideEmptyChildren(librarySearchResults.hideEmtpyShows);
|
||||
final postersList = librarySearchResults.posters.hideEmptyChildren(librarySearchResults.hideEmptyShows);
|
||||
final playerState = ref.watch(mediaPlaybackProvider.select((value) => value.state));
|
||||
final libraryViewType = ref.watch(libraryViewTypeProvider);
|
||||
|
||||
|
|
@ -230,7 +230,12 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
onRefresh: () async {
|
||||
if (libraryProvider.mounted) {
|
||||
return libraryProvider.initRefresh(
|
||||
widget.folderId, widget.viewModelId, widget.favourites);
|
||||
widget.folderId,
|
||||
widget.viewModelId,
|
||||
widget.favourites,
|
||||
widget.sortOrder,
|
||||
widget.sortingOptions,
|
||||
);
|
||||
}
|
||||
},
|
||||
refreshOnStart: false,
|
||||
|
|
@ -282,6 +287,11 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
action: () => refreshKey.currentState?.show(),
|
||||
icon: const Icon(IconsaxOutline.refresh),
|
||||
);
|
||||
final showSavedFiltersDialogue = ItemActionButton(
|
||||
label: Text("Filters"),
|
||||
action: () => showSavedFilters(context, librarySearchResults, libraryProvider),
|
||||
icon: const Icon(IconsaxOutline.refresh),
|
||||
);
|
||||
final itemViewAction = ItemActionButton(
|
||||
label: Text(context.localized.selectViewType),
|
||||
icon: Icon(libraryViewType.icon),
|
||||
|
|
@ -359,6 +369,8 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
itemCountWidget.toPopupMenuItem(useIcons: true),
|
||||
refreshAction.toPopupMenuItem(useIcons: true),
|
||||
itemViewAction.toPopupMenuItem(useIcons: true),
|
||||
if (librarySearchResults.views.hasEnabled == true)
|
||||
showSavedFiltersDialogue.toPopupMenuItem(useIcons: true),
|
||||
if (itemActions.isNotEmpty) ItemActionDivider().toPopupMenuItem(),
|
||||
...itemActions.popupMenuItems(useIcons: true),
|
||||
],
|
||||
|
|
@ -374,6 +386,8 @@ class _LibrarySearchScreenState extends ConsumerState<LibrarySearchScreen> {
|
|||
itemCountWidget.toListItem(context, useIcons: true),
|
||||
refreshAction.toListItem(context, useIcons: true),
|
||||
itemViewAction.toListItem(context, useIcons: true),
|
||||
if (librarySearchResults.views.hasEnabled == true)
|
||||
showSavedFiltersDialogue.toPopupMenuItem(useIcons: true),
|
||||
if (itemActions.isNotEmpty) ItemActionDivider().toListItem(context),
|
||||
...itemActions.listTileItems(context, useIcons: true),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -190,10 +190,10 @@ List<Widget> libraryFilterChips(
|
|||
if (librarySearchResults.types[FladderItemType.series] == true)
|
||||
FilterChip(
|
||||
avatar: Icon(
|
||||
librarySearchResults.hideEmtpyShows ? Icons.visibility_off_rounded : Icons.visibility_rounded,
|
||||
librarySearchResults.hideEmptyShows ? Icons.visibility_off_rounded : Icons.visibility_rounded,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
selected: librarySearchResults.hideEmtpyShows,
|
||||
selected: librarySearchResults.hideEmptyShows,
|
||||
showCheckmark: false,
|
||||
label: Text(context.localized.hideEmpty),
|
||||
onSelected: libraryProvider.setHideEmpty,
|
||||
|
|
|
|||
171
lib/screens/library_search/widgets/library_saved_filters.dart
Normal file
171
lib/screens/library_search/widgets/library_saved_filters.dart
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:ficonsax/ficonsax.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:fladder/models/library_search/library_search_model.dart';
|
||||
import 'package:fladder/providers/library_search_provider.dart';
|
||||
import 'package:fladder/screens/shared/default_alert_dialog.dart';
|
||||
import 'package:fladder/screens/shared/flat_button.dart';
|
||||
import 'package:fladder/screens/shared/outlined_text_field.dart';
|
||||
import 'package:fladder/util/list_padding.dart';
|
||||
import 'package:fladder/util/localization_helper.dart';
|
||||
|
||||
Future<void> showSavedFilters(
|
||||
BuildContext context,
|
||||
LibrarySearchModel model,
|
||||
LibrarySearchNotifier provider,
|
||||
) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
builder: (context) => LibrarySavedFiltersDialogue(
|
||||
searchModel: model,
|
||||
provider: provider,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class LibrarySavedFiltersDialogue extends ConsumerWidget {
|
||||
final LibrarySearchModel searchModel;
|
||||
final LibrarySearchNotifier provider;
|
||||
const LibrarySavedFiltersDialogue({
|
||||
required this.searchModel,
|
||||
required this.provider,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final controller = TextEditingController();
|
||||
final filters = ref.watch(provider.filterProvider);
|
||||
final filterProvider = ref.watch(provider.filterProvider.notifier);
|
||||
return Dialog(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
context.localized.filter(2),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
if (filters.isNotEmpty) ...[
|
||||
const Divider(),
|
||||
Flexible(
|
||||
child: ListView(
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
...filters.map(
|
||||
(filter) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 4),
|
||||
child: Card(
|
||||
child: FlatButton(
|
||||
onTap: () => provider.loadModel(filter),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(child: Text(filter.name)),
|
||||
IconButton.filledTonal(
|
||||
tooltip: context.localized.defaultFilterForLibrary,
|
||||
style: ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(
|
||||
filter.isFavourite ? Colors.yellowAccent.shade700.withOpacity(0.5) : null,
|
||||
),
|
||||
),
|
||||
onPressed: () =>
|
||||
filterProvider.saveFilter(filter.copyWith(isFavourite: !filter.isFavourite)),
|
||||
icon: Icon(
|
||||
color: filter.isFavourite ? Colors.yellowAccent : null,
|
||||
filter.isFavourite ? IconsaxBold.star_1 : IconsaxOutline.star,
|
||||
),
|
||||
),
|
||||
IconButton.filledTonal(
|
||||
tooltip: context.localized.updateFilterForLibrary,
|
||||
onPressed: () => provider.updateFilter(filter),
|
||||
icon: Icon(IconsaxBold.refresh),
|
||||
),
|
||||
IconButton.filledTonal(
|
||||
tooltip: context.localized.delete,
|
||||
onPressed: () {
|
||||
showDefaultAlertDialog(
|
||||
context,
|
||||
context.localized.removeFilterForLibrary(filter.name),
|
||||
context.localized.deleteFilterConfirmation,
|
||||
(context) {
|
||||
filterProvider.removeFilter(filter);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
context.localized.delete,
|
||||
(context) {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
context.localized.cancel,
|
||||
);
|
||||
},
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
WidgetStatePropertyAll(Theme.of(context).colorScheme.errorContainer),
|
||||
foregroundColor:
|
||||
WidgetStatePropertyAll(Theme.of(context).colorScheme.onErrorContainer),
|
||||
),
|
||||
icon: Icon(IconsaxOutline.trash),
|
||||
),
|
||||
].addInBetween(const SizedBox(width: 8)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
],
|
||||
if (filters.length < 10)
|
||||
Row(
|
||||
children: [
|
||||
Flexible(
|
||||
child: OutlinedTextField(
|
||||
controller: controller,
|
||||
label: context.localized.name,
|
||||
onSubmitted: (value) => provider.saveFiltersNew(value),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
FilledButton.tonal(
|
||||
onPressed: () => provider.saveFiltersNew(controller.text),
|
||||
child: Icon(IconsaxOutline.save_2),
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
Text(context.localized.libraryFiltersLimitReached),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
showDefaultAlertDialog(
|
||||
context,
|
||||
context.localized.libraryFiltersRemoveAll,
|
||||
context.localized.libraryFiltersRemoveAllConfirm,
|
||||
(context) {
|
||||
filterProvider.deleteAllFilters();
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
context.localized.delete,
|
||||
(context) {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
context.localized.cancel,
|
||||
);
|
||||
},
|
||||
child: Text(context.localized.libraryFiltersRemoveAll),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue