mirror of
https://github.com/gabehf/Fladder.git
synced 2026-03-08 23:18:16 -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
21
lib/providers/library_filters_provider.dart
Normal file
21
lib/providers/library_filters_provider.dart
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import 'package:fladder/models/library_filters_model.dart';
|
||||
import 'package:fladder/providers/user_provider.dart';
|
||||
|
||||
part 'library_filters_provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
class LibraryFilters extends _$LibraryFilters {
|
||||
@override
|
||||
List<LibraryFiltersModel> build(List<String> ids) => ref.watch(
|
||||
userProvider
|
||||
.select((value) => (value?.savedFilters ?? []).where((element) => element.containsSameIds(ids)).toList()),
|
||||
);
|
||||
|
||||
void removeFilter(LibraryFiltersModel model) => ref.read(userProvider.notifier).removeFilter(model);
|
||||
|
||||
void saveFilter(LibraryFiltersModel model) => ref.read(userProvider.notifier).saveFilter(model);
|
||||
|
||||
void deleteAllFilters() => ref.read(userProvider.notifier).deleteAllFilters();
|
||||
}
|
||||
174
lib/providers/library_filters_provider.g.dart
Normal file
174
lib/providers/library_filters_provider.g.dart
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'library_filters_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$libraryFiltersHash() => r'7b4661651df7e0c019dca5bb7eb6433bcd8b3ebb';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$LibraryFilters
|
||||
extends BuildlessAutoDisposeNotifier<List<LibraryFiltersModel>> {
|
||||
late final List<String> ids;
|
||||
|
||||
List<LibraryFiltersModel> build(
|
||||
List<String> ids,
|
||||
);
|
||||
}
|
||||
|
||||
/// See also [LibraryFilters].
|
||||
@ProviderFor(LibraryFilters)
|
||||
const libraryFiltersProvider = LibraryFiltersFamily();
|
||||
|
||||
/// See also [LibraryFilters].
|
||||
class LibraryFiltersFamily extends Family<List<LibraryFiltersModel>> {
|
||||
/// See also [LibraryFilters].
|
||||
const LibraryFiltersFamily();
|
||||
|
||||
/// See also [LibraryFilters].
|
||||
LibraryFiltersProvider call(
|
||||
List<String> ids,
|
||||
) {
|
||||
return LibraryFiltersProvider(
|
||||
ids,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
LibraryFiltersProvider getProviderOverride(
|
||||
covariant LibraryFiltersProvider provider,
|
||||
) {
|
||||
return call(
|
||||
provider.ids,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'libraryFiltersProvider';
|
||||
}
|
||||
|
||||
/// See also [LibraryFilters].
|
||||
class LibraryFiltersProvider extends AutoDisposeNotifierProviderImpl<
|
||||
LibraryFilters, List<LibraryFiltersModel>> {
|
||||
/// See also [LibraryFilters].
|
||||
LibraryFiltersProvider(
|
||||
List<String> ids,
|
||||
) : this._internal(
|
||||
() => LibraryFilters()..ids = ids,
|
||||
from: libraryFiltersProvider,
|
||||
name: r'libraryFiltersProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$libraryFiltersHash,
|
||||
dependencies: LibraryFiltersFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
LibraryFiltersFamily._allTransitiveDependencies,
|
||||
ids: ids,
|
||||
);
|
||||
|
||||
LibraryFiltersProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.ids,
|
||||
}) : super.internal();
|
||||
|
||||
final List<String> ids;
|
||||
|
||||
@override
|
||||
List<LibraryFiltersModel> runNotifierBuild(
|
||||
covariant LibraryFilters notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
ids,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(LibraryFilters Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: LibraryFiltersProvider._internal(
|
||||
() => create()..ids = ids,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
ids: ids,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeNotifierProviderElement<LibraryFilters, List<LibraryFiltersModel>>
|
||||
createElement() {
|
||||
return _LibraryFiltersProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is LibraryFiltersProvider && other.ids == ids;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, ids.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
mixin LibraryFiltersRef
|
||||
on AutoDisposeNotifierProviderRef<List<LibraryFiltersModel>> {
|
||||
/// The parameter `ids` of this provider.
|
||||
List<String> get ids;
|
||||
}
|
||||
|
||||
class _LibraryFiltersProviderElement extends AutoDisposeNotifierProviderElement<
|
||||
LibraryFilters, List<LibraryFiltersModel>> with LibraryFiltersRef {
|
||||
_LibraryFiltersProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
List<String> get ids => (origin as LibraryFiltersProvider).ids;
|
||||
}
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
|
|
@ -13,11 +13,13 @@ import 'package:fladder/models/item_base_model.dart';
|
|||
import 'package:fladder/models/items/folder_model.dart';
|
||||
import 'package:fladder/models/items/item_shared_models.dart';
|
||||
import 'package:fladder/models/items/photos_model.dart';
|
||||
import 'package:fladder/models/library_filters_model.dart';
|
||||
import 'package:fladder/models/library_search/library_search_model.dart';
|
||||
import 'package:fladder/models/library_search/library_search_options.dart';
|
||||
import 'package:fladder/models/playlist_model.dart';
|
||||
import 'package:fladder/models/view_model.dart';
|
||||
import 'package:fladder/providers/api_provider.dart';
|
||||
import 'package:fladder/providers/library_filters_provider.dart';
|
||||
import 'package:fladder/providers/service_provider.dart';
|
||||
import 'package:fladder/providers/settings/client_settings_provider.dart';
|
||||
import 'package:fladder/providers/user_provider.dart';
|
||||
|
|
@ -40,6 +42,8 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
|
||||
int get pageSize => ref.read(clientSettingsProvider).libraryPageSize ?? 500;
|
||||
|
||||
LibraryFiltersProvider get filterProvider => libraryFiltersProvider(state.views.included.map((e) => e.id).toList());
|
||||
|
||||
late final JellyService api = ref.read(jellyApiProvider);
|
||||
|
||||
set loading(bool loading) => state = state.copyWith(loading: loading);
|
||||
|
|
@ -52,6 +56,8 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
List<String>? folderId,
|
||||
String? viewModelId,
|
||||
bool? favourites,
|
||||
SortingOrder? sortOrder,
|
||||
SortingOptions? sortingOptions,
|
||||
) async {
|
||||
loading = true;
|
||||
state = state.resetLazyLoad();
|
||||
|
|
@ -59,7 +65,7 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
if (folderId != null) {
|
||||
await loadFolders(folderId: folderId);
|
||||
} else {
|
||||
await loadViews(viewModelId, favourites);
|
||||
await loadViews(viewModelId, favourites, sortOrder, sortingOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -151,7 +157,12 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
}
|
||||
|
||||
//Pas viewmodel otherwise select first
|
||||
Future<void> loadViews(String? viewModelId, bool? favourites) async {
|
||||
Future<void> loadViews(
|
||||
String? viewModelId,
|
||||
bool? favourites,
|
||||
SortingOrder? sortOrder,
|
||||
SortingOptions? sortingOptions,
|
||||
) async {
|
||||
final response = await api.usersUserIdViewsGet(includeHidden: false);
|
||||
final createdViews = response.body?.items?.map((e) => ViewModel.fromBodyDto(e, ref));
|
||||
Map<ViewModel, bool> mappedModels =
|
||||
|
|
@ -159,12 +170,28 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
|
||||
final selectedModel = mappedModels.keys.firstWhereOrNull((element) => element.id == viewModelId);
|
||||
|
||||
final views = selectedModel != null
|
||||
? mappedModels.setKey(mappedModels.keys.firstWhere((element) => element.id == viewModelId), true)
|
||||
: mappedModels;
|
||||
|
||||
state = state.copyWith(
|
||||
views: selectedModel != null
|
||||
? mappedModels.setKey(mappedModels.keys.firstWhere((element) => element.id == viewModelId), true)
|
||||
: mappedModels,
|
||||
favourites: favourites,
|
||||
views: views,
|
||||
);
|
||||
|
||||
if (sortOrder == null && sortingOptions == null && favourites == null) {
|
||||
final findFavouriteFilter = ref
|
||||
.read(libraryFiltersProvider(views.included.map((e) => e.id).toList()))
|
||||
.firstWhereOrNull((element) => element.isFavourite);
|
||||
if (findFavouriteFilter != null) {
|
||||
loadModel(findFavouriteFilter);
|
||||
}
|
||||
} else {
|
||||
state = state.copyWith(
|
||||
sortOrder: sortOrder,
|
||||
sortingOption: sortingOptions,
|
||||
favourites: favourites,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadFolders({List<String>? folderId}) async {
|
||||
|
|
@ -348,7 +375,7 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
recursive: false,
|
||||
studios: state.studios.setAll(false),
|
||||
filters: state.filters.setAll(false),
|
||||
hideEmtpyShows: false,
|
||||
hideEmptyShows: false,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -356,7 +383,7 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
|
||||
void setSortOrder(SortingOrder e) => state = state.copyWith(sortOrder: e);
|
||||
|
||||
void setHideEmpty(bool value) => state = state.copyWith(hideEmtpyShows: value);
|
||||
void setHideEmpty(bool value) => state = state.copyWith(hideEmptyShows: value);
|
||||
void setGroupBy(GroupBy groupBy) => state = state.copyWith(groupBy: groupBy);
|
||||
|
||||
void setFolderId(ItemBaseModel item) {
|
||||
|
|
@ -460,13 +487,6 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
state = state.copyWith(posters: currentItems);
|
||||
}
|
||||
|
||||
void setDefaultOptions(SortingOrder? sortOrder, SortingOptions? sortingOptions) {
|
||||
state = state.copyWith(
|
||||
sortOrder: sortOrder,
|
||||
sortingOption: sortingOptions,
|
||||
);
|
||||
}
|
||||
|
||||
void updateUserDataMain(UserData? userData) {
|
||||
state = state.copyWith(
|
||||
folderOverwrite: [state.folderOverwrite.lastOrNull?.copyWith(userData: userData)].whereNotNull().toList(),
|
||||
|
|
@ -657,6 +677,34 @@ class LibrarySearchNotifier extends StateNotifier<LibrarySearchModel> {
|
|||
void updateEverything() {
|
||||
state = state.copyWith();
|
||||
}
|
||||
|
||||
void loadModel(LibraryFiltersModel model) {
|
||||
state = state.copyWith(
|
||||
genres: state.genres.replaceMap(model.genres),
|
||||
filters: state.filters.replaceMap(model.filters),
|
||||
studios: state.studios.replaceMap(model.studios),
|
||||
tags: state.tags.replaceMap(model.tags),
|
||||
years: state.years.replaceMap(model.years),
|
||||
officialRatings: state.officialRatings.replaceMap(model.officialRatings),
|
||||
types: state.types.replaceMap(model.types),
|
||||
sortingOption: model.sortingOption,
|
||||
sortOrder: model.sortOrder,
|
||||
favourites: model.favourites,
|
||||
hideEmptyShows: model.hideEmptyShows,
|
||||
recursive: model.recursive,
|
||||
groupBy: model.groupBy,
|
||||
);
|
||||
}
|
||||
|
||||
void saveFiltersNew(String newName) =>
|
||||
ref.read(filterProvider.notifier).saveFilter(LibraryFiltersModel.fromLibrarySearch(newName, state));
|
||||
|
||||
void updateFilter(LibraryFiltersModel model) {
|
||||
ref.read(filterProvider.notifier).saveFilter(LibraryFiltersModel.fromLibrarySearch(model.name, state).copyWith(
|
||||
isFavourite: model.isFavourite,
|
||||
id: model.id,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
extension SimpleSorter on List<ItemBaseModel> {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
import 'package:chopper/chopper.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
import 'package:fladder/jellyfin/enum_models.dart';
|
||||
import 'package:fladder/models/account_model.dart';
|
||||
import 'package:fladder/models/items/item_shared_models.dart';
|
||||
import 'package:fladder/models/library_filters_model.dart';
|
||||
import 'package:fladder/providers/api_provider.dart';
|
||||
import 'package:fladder/providers/service_provider.dart';
|
||||
import 'package:fladder/providers/shared_provider.dart';
|
||||
import 'package:fladder/providers/sync_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'user_provider.g.dart';
|
||||
|
||||
|
|
@ -142,4 +145,30 @@ class User extends _$User {
|
|||
AccountModel? build() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void removeFilter(LibraryFiltersModel model) {
|
||||
final currentList = ((state?.savedFilters ?? [])).toList(growable: true);
|
||||
currentList.remove(model);
|
||||
state = state?.copyWith(savedFilters: currentList);
|
||||
}
|
||||
|
||||
void saveFilter(LibraryFiltersModel model) {
|
||||
final currentList = (state?.savedFilters ?? []).toList(growable: true);
|
||||
if (currentList.firstWhereOrNull((value) => value.id == model.id) != null) {
|
||||
state = state?.copyWith(
|
||||
savedFilters: currentList.map(
|
||||
(e) {
|
||||
if (e.id == model.id) {
|
||||
return model;
|
||||
} else {
|
||||
return e.copyWith(isFavourite: model.isFavourite && model.containsSameIds(e.ids) ? false : e.isFavourite);
|
||||
}
|
||||
},
|
||||
).toList());
|
||||
} else {
|
||||
state = state?.copyWith(savedFilters: [model, ...currentList]);
|
||||
}
|
||||
}
|
||||
|
||||
void deleteAllFilters() => state = state?.copyWith(savedFilters: []);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ final showSyncButtonProviderProvider = AutoDisposeProvider<bool>.internal(
|
|||
);
|
||||
|
||||
typedef ShowSyncButtonProviderRef = AutoDisposeProviderRef<bool>;
|
||||
String _$userHash() => r'4a4302c819d26fc7c28d04b9274d0dfd0dc8e201';
|
||||
String _$userHash() => r'418b3d4ade830479db9f48c7793ac5b646778b82';
|
||||
|
||||
/// See also [User].
|
||||
@ProviderFor(User)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue