feature: Add option to disable background images (#380)

Co-authored-by: PartyDonut <PartyDonut@users.noreply.github.com>
This commit is contained in:
PartyDonut 2025-06-08 15:51:39 +02:00 committed by GitHub
parent d10dfdd09d
commit f2ed3d7f7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 72 additions and 24 deletions

View file

@ -721,6 +721,7 @@
"@settingsContinue": {}, "@settingsContinue": {},
"settingsEnableOsMediaControls": "Enable OS media controls", "settingsEnableOsMediaControls": "Enable OS media controls",
"@settingsEnableOsMediaControls": {}, "@settingsEnableOsMediaControls": {},
"settingsEnableOsMediaControlsDesc": "Allow for playback control using media-keys and show current playing media in OS",
"settingsHomeBannerDescription": "Display as a slideshow, carousel, or hide the banner", "settingsHomeBannerDescription": "Display as a slideshow, carousel, or hide the banner",
"@settingsHomeBannerDescription": {}, "@settingsHomeBannerDescription": {},
"settingsHomeBannerTitle": "Home banner", "settingsHomeBannerTitle": "Home banner",
@ -1235,5 +1236,7 @@
} }
} }
}, },
"newUpdateFoundOnGithub": "Found a new update on Github" "newUpdateFoundOnGithub": "Found a new update on Github",
"enableBackgroundPostersTitle": "Enable background posters",
"enableBackgroundPostersDesc": "Show random posters in applicable screens"
} }

View file

@ -34,6 +34,7 @@ class ClientSettingsModel with _$ClientSettingsModel {
@Default(false) bool showAllCollectionTypes, @Default(false) bool showAllCollectionTypes,
@Default(2) int maxConcurrentDownloads, @Default(2) int maxConcurrentDownloads,
@Default(DynamicSchemeVariant.rainbow) DynamicSchemeVariant schemeVariant, @Default(DynamicSchemeVariant.rainbow) DynamicSchemeVariant schemeVariant,
@Default(true) bool backgroundPosters,
@Default(true) bool checkForUpdates, @Default(true) bool checkForUpdates,
String? lastViewedUpdate, String? lastViewedUpdate,
int? libraryPageSize, int? libraryPageSize,

View file

@ -40,6 +40,7 @@ mixin _$ClientSettingsModel {
bool get showAllCollectionTypes => throw _privateConstructorUsedError; bool get showAllCollectionTypes => throw _privateConstructorUsedError;
int get maxConcurrentDownloads => throw _privateConstructorUsedError; int get maxConcurrentDownloads => throw _privateConstructorUsedError;
DynamicSchemeVariant get schemeVariant => throw _privateConstructorUsedError; DynamicSchemeVariant get schemeVariant => throw _privateConstructorUsedError;
bool get backgroundPosters => throw _privateConstructorUsedError;
bool get checkForUpdates => throw _privateConstructorUsedError; bool get checkForUpdates => throw _privateConstructorUsedError;
String? get lastViewedUpdate => throw _privateConstructorUsedError; String? get lastViewedUpdate => throw _privateConstructorUsedError;
int? get libraryPageSize => throw _privateConstructorUsedError; int? get libraryPageSize => throw _privateConstructorUsedError;
@ -80,6 +81,7 @@ abstract class $ClientSettingsModelCopyWith<$Res> {
bool showAllCollectionTypes, bool showAllCollectionTypes,
int maxConcurrentDownloads, int maxConcurrentDownloads,
DynamicSchemeVariant schemeVariant, DynamicSchemeVariant schemeVariant,
bool backgroundPosters,
bool checkForUpdates, bool checkForUpdates,
String? lastViewedUpdate, String? lastViewedUpdate,
int? libraryPageSize}); int? libraryPageSize});
@ -119,6 +121,7 @@ class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel>
Object? showAllCollectionTypes = null, Object? showAllCollectionTypes = null,
Object? maxConcurrentDownloads = null, Object? maxConcurrentDownloads = null,
Object? schemeVariant = null, Object? schemeVariant = null,
Object? backgroundPosters = null,
Object? checkForUpdates = null, Object? checkForUpdates = null,
Object? lastViewedUpdate = freezed, Object? lastViewedUpdate = freezed,
Object? libraryPageSize = freezed, Object? libraryPageSize = freezed,
@ -200,6 +203,10 @@ class _$ClientSettingsModelCopyWithImpl<$Res, $Val extends ClientSettingsModel>
? _value.schemeVariant ? _value.schemeVariant
: schemeVariant // ignore: cast_nullable_to_non_nullable : schemeVariant // ignore: cast_nullable_to_non_nullable
as DynamicSchemeVariant, as DynamicSchemeVariant,
backgroundPosters: null == backgroundPosters
? _value.backgroundPosters
: backgroundPosters // ignore: cast_nullable_to_non_nullable
as bool,
checkForUpdates: null == checkForUpdates checkForUpdates: null == checkForUpdates
? _value.checkForUpdates ? _value.checkForUpdates
: checkForUpdates // ignore: cast_nullable_to_non_nullable : checkForUpdates // ignore: cast_nullable_to_non_nullable
@ -244,6 +251,7 @@ abstract class _$$ClientSettingsModelImplCopyWith<$Res>
bool showAllCollectionTypes, bool showAllCollectionTypes,
int maxConcurrentDownloads, int maxConcurrentDownloads,
DynamicSchemeVariant schemeVariant, DynamicSchemeVariant schemeVariant,
bool backgroundPosters,
bool checkForUpdates, bool checkForUpdates,
String? lastViewedUpdate, String? lastViewedUpdate,
int? libraryPageSize}); int? libraryPageSize});
@ -281,6 +289,7 @@ class __$$ClientSettingsModelImplCopyWithImpl<$Res>
Object? showAllCollectionTypes = null, Object? showAllCollectionTypes = null,
Object? maxConcurrentDownloads = null, Object? maxConcurrentDownloads = null,
Object? schemeVariant = null, Object? schemeVariant = null,
Object? backgroundPosters = null,
Object? checkForUpdates = null, Object? checkForUpdates = null,
Object? lastViewedUpdate = freezed, Object? lastViewedUpdate = freezed,
Object? libraryPageSize = freezed, Object? libraryPageSize = freezed,
@ -362,6 +371,10 @@ class __$$ClientSettingsModelImplCopyWithImpl<$Res>
? _value.schemeVariant ? _value.schemeVariant
: schemeVariant // ignore: cast_nullable_to_non_nullable : schemeVariant // ignore: cast_nullable_to_non_nullable
as DynamicSchemeVariant, as DynamicSchemeVariant,
backgroundPosters: null == backgroundPosters
? _value.backgroundPosters
: backgroundPosters // ignore: cast_nullable_to_non_nullable
as bool,
checkForUpdates: null == checkForUpdates checkForUpdates: null == checkForUpdates
? _value.checkForUpdates ? _value.checkForUpdates
: checkForUpdates // ignore: cast_nullable_to_non_nullable : checkForUpdates // ignore: cast_nullable_to_non_nullable
@ -402,6 +415,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
this.showAllCollectionTypes = false, this.showAllCollectionTypes = false,
this.maxConcurrentDownloads = 2, this.maxConcurrentDownloads = 2,
this.schemeVariant = DynamicSchemeVariant.rainbow, this.schemeVariant = DynamicSchemeVariant.rainbow,
this.backgroundPosters = true,
this.checkForUpdates = true, this.checkForUpdates = true,
this.lastViewedUpdate, this.lastViewedUpdate,
this.libraryPageSize}) this.libraryPageSize})
@ -466,6 +480,9 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
final DynamicSchemeVariant schemeVariant; final DynamicSchemeVariant schemeVariant;
@override @override
@JsonKey() @JsonKey()
final bool backgroundPosters;
@override
@JsonKey()
final bool checkForUpdates; final bool checkForUpdates;
@override @override
final String? lastViewedUpdate; final String? lastViewedUpdate;
@ -474,7 +491,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
@override @override
String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, requireWifi: $requireWifi, showAllCollectionTypes: $showAllCollectionTypes, maxConcurrentDownloads: $maxConcurrentDownloads, schemeVariant: $schemeVariant, checkForUpdates: $checkForUpdates, lastViewedUpdate: $lastViewedUpdate, libraryPageSize: $libraryPageSize)'; return 'ClientSettingsModel(syncPath: $syncPath, position: $position, size: $size, timeOut: $timeOut, nextUpDateCutoff: $nextUpDateCutoff, themeMode: $themeMode, themeColor: $themeColor, amoledBlack: $amoledBlack, blurPlaceHolders: $blurPlaceHolders, blurUpcomingEpisodes: $blurUpcomingEpisodes, selectedLocale: $selectedLocale, enableMediaKeys: $enableMediaKeys, posterSize: $posterSize, pinchPosterZoom: $pinchPosterZoom, mouseDragSupport: $mouseDragSupport, requireWifi: $requireWifi, showAllCollectionTypes: $showAllCollectionTypes, maxConcurrentDownloads: $maxConcurrentDownloads, schemeVariant: $schemeVariant, backgroundPosters: $backgroundPosters, checkForUpdates: $checkForUpdates, lastViewedUpdate: $lastViewedUpdate, libraryPageSize: $libraryPageSize)';
} }
@override @override
@ -503,6 +520,7 @@ class _$ClientSettingsModelImpl extends _ClientSettingsModel
..add( ..add(
DiagnosticsProperty('maxConcurrentDownloads', maxConcurrentDownloads)) DiagnosticsProperty('maxConcurrentDownloads', maxConcurrentDownloads))
..add(DiagnosticsProperty('schemeVariant', schemeVariant)) ..add(DiagnosticsProperty('schemeVariant', schemeVariant))
..add(DiagnosticsProperty('backgroundPosters', backgroundPosters))
..add(DiagnosticsProperty('checkForUpdates', checkForUpdates)) ..add(DiagnosticsProperty('checkForUpdates', checkForUpdates))
..add(DiagnosticsProperty('lastViewedUpdate', lastViewedUpdate)) ..add(DiagnosticsProperty('lastViewedUpdate', lastViewedUpdate))
..add(DiagnosticsProperty('libraryPageSize', libraryPageSize)); ..add(DiagnosticsProperty('libraryPageSize', libraryPageSize));
@ -546,6 +564,7 @@ abstract class _ClientSettingsModel extends ClientSettingsModel {
final bool showAllCollectionTypes, final bool showAllCollectionTypes,
final int maxConcurrentDownloads, final int maxConcurrentDownloads,
final DynamicSchemeVariant schemeVariant, final DynamicSchemeVariant schemeVariant,
final bool backgroundPosters,
final bool checkForUpdates, final bool checkForUpdates,
final String? lastViewedUpdate, final String? lastViewedUpdate,
final int? libraryPageSize}) = _$ClientSettingsModelImpl; final int? libraryPageSize}) = _$ClientSettingsModelImpl;
@ -594,6 +613,8 @@ abstract class _ClientSettingsModel extends ClientSettingsModel {
@override @override
DynamicSchemeVariant get schemeVariant; DynamicSchemeVariant get schemeVariant;
@override @override
bool get backgroundPosters;
@override
bool get checkForUpdates; bool get checkForUpdates;
@override @override
String? get lastViewedUpdate; String? get lastViewedUpdate;

View file

@ -41,6 +41,7 @@ _$ClientSettingsModelImpl _$$ClientSettingsModelImplFromJson(
schemeVariant: $enumDecodeNullable( schemeVariant: $enumDecodeNullable(
_$DynamicSchemeVariantEnumMap, json['schemeVariant']) ?? _$DynamicSchemeVariantEnumMap, json['schemeVariant']) ??
DynamicSchemeVariant.rainbow, DynamicSchemeVariant.rainbow,
backgroundPosters: json['backgroundPosters'] as bool? ?? true,
checkForUpdates: json['checkForUpdates'] as bool? ?? true, checkForUpdates: json['checkForUpdates'] as bool? ?? true,
lastViewedUpdate: json['lastViewedUpdate'] as String?, lastViewedUpdate: json['lastViewedUpdate'] as String?,
libraryPageSize: (json['libraryPageSize'] as num?)?.toInt(), libraryPageSize: (json['libraryPageSize'] as num?)?.toInt(),
@ -68,6 +69,7 @@ Map<String, dynamic> _$$ClientSettingsModelImplToJson(
'showAllCollectionTypes': instance.showAllCollectionTypes, 'showAllCollectionTypes': instance.showAllCollectionTypes,
'maxConcurrentDownloads': instance.maxConcurrentDownloads, 'maxConcurrentDownloads': instance.maxConcurrentDownloads,
'schemeVariant': _$DynamicSchemeVariantEnumMap[instance.schemeVariant]!, 'schemeVariant': _$DynamicSchemeVariantEnumMap[instance.schemeVariant]!,
'backgroundPosters': instance.backgroundPosters,
'checkForUpdates': instance.checkForUpdates, 'checkForUpdates': instance.checkForUpdates,
'lastViewedUpdate': instance.lastViewedUpdate, 'lastViewedUpdate': instance.lastViewedUpdate,
'libraryPageSize': instance.libraryPageSize, 'libraryPageSize': instance.libraryPageSize,

View file

@ -1,8 +1,8 @@
import 'package:fladder/l10n/generated/app_localizations.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/l10n/generated/app_localizations.dart';
import 'package:fladder/providers/settings/client_settings_provider.dart'; import 'package:fladder/providers/settings/client_settings_provider.dart';
import 'package:fladder/screens/settings/settings_list_tile.dart'; import 'package:fladder/screens/settings/settings_list_tile.dart';
import 'package:fladder/screens/settings/widgets/settings_label_divider.dart'; import 'package:fladder/screens/settings/widgets/settings_label_divider.dart';
@ -80,12 +80,25 @@ List<Widget> buildClientSettingsVisual(
), ),
SettingsListTile( SettingsListTile(
label: Text(context.localized.settingsEnableOsMediaControls), label: Text(context.localized.settingsEnableOsMediaControls),
subLabel: Text(context.localized.settingsEnableOsMediaControlsDesc),
onTap: () => ref.read(clientSettingsProvider.notifier).setMediaKeys(!clientSettings.enableMediaKeys), onTap: () => ref.read(clientSettingsProvider.notifier).setMediaKeys(!clientSettings.enableMediaKeys),
trailing: Switch( trailing: Switch(
value: clientSettings.enableMediaKeys, value: clientSettings.enableMediaKeys,
onChanged: (value) => ref.read(clientSettingsProvider.notifier).setMediaKeys(value), onChanged: (value) => ref.read(clientSettingsProvider.notifier).setMediaKeys(value),
), ),
), ),
SettingsListTile(
label: Text(context.localized.enableBackgroundPostersTitle),
subLabel: Text(context.localized.enableBackgroundPostersDesc),
onTap: () => ref
.read(clientSettingsProvider.notifier)
.update((cb) => cb.copyWith(backgroundPosters: !clientSettings.backgroundPosters)),
trailing: Switch(
value: clientSettings.backgroundPosters,
onChanged: (value) =>
ref.read(clientSettingsProvider.notifier).update((cb) => cb.copyWith(backgroundPosters: value)),
),
),
SettingsListTile( SettingsListTile(
label: Text(context.localized.settingsNextUpCutoffDays), label: Text(context.localized.settingsNextUpCutoffDays),
trailing: SizedBox( trailing: SizedBox(

View file

@ -6,6 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:fladder/models/item_base_model.dart'; import 'package:fladder/models/item_base_model.dart';
import 'package:fladder/models/items/images_models.dart'; import 'package:fladder/models/items/images_models.dart';
import 'package:fladder/providers/api_provider.dart'; import 'package:fladder/providers/api_provider.dart';
import 'package:fladder/providers/settings/client_settings_provider.dart';
import 'package:fladder/util/fladder_image.dart'; import 'package:fladder/util/fladder_image.dart';
class BackgroundImage extends ConsumerStatefulWidget { class BackgroundImage extends ConsumerStatefulWidget {
@ -35,38 +36,45 @@ class _BackgroundImageState extends ConsumerState<BackgroundImage> {
} }
void updateItems() { void updateItems() {
final enabled = ref.read(clientSettingsProvider.select((value) => value.backgroundPosters));
WidgetsBinding.instance.addPostFrameCallback((value) async { WidgetsBinding.instance.addPostFrameCallback((value) async {
if (!enabled && mounted) return;
if (widget.images.isNotEmpty) { if (widget.images.isNotEmpty) {
setState(() { final image = widget.images.shuffled().firstOrNull?.primary;
backgroundImage = widget.images.shuffled().firstOrNull?.primary; if (mounted) setState(() => backgroundImage = image);
});
return; return;
} }
final randomItem = widget.items.shuffled().firstOrNull;
if (widget.items.isEmpty) return; if (widget.items.isEmpty) return;
final randomItem = widget.items.shuffled().firstOrNull;
final itemId = switch (randomItem?.type) { final itemId = switch (randomItem?.type) {
FladderItemType.folder => randomItem?.id, FladderItemType.folder => randomItem?.id,
FladderItemType.series => randomItem?.parentId ?? randomItem?.id, FladderItemType.series => randomItem?.parentId ?? randomItem?.id,
_ => randomItem?.id, _ => randomItem?.id,
} ?? };
randomItem?.id;
if (itemId == null) return; if (itemId == null) return;
final apiProvider = await ref.read(jellyApiProvider).usersUserIdItemsItemIdGet(
itemId: itemId, final apiResponse = await ref.read(jellyApiProvider).usersUserIdItemsItemIdGet(itemId: itemId);
); final image =
setState(() { apiResponse.body?.parentBaseModel.getPosters?.randomBackDrop ?? apiResponse.body?.getPosters?.randomBackDrop;
backgroundImage = apiProvider.body?.parentBaseModel.getPosters?.randomBackDrop ??
apiProvider.body?.getPosters?.randomBackDrop; if (mounted) setState(() => backgroundImage = image);
});
}); });
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FladderImage( final enabled = ref.watch(clientSettingsProvider.select((value) => value.backgroundPosters));
return enabled
? FladderImage(
image: backgroundImage, image: backgroundImage,
fit: BoxFit.cover, fit: BoxFit.cover,
blurOnly: false, blurOnly: false,
); )
: const SizedBox.shrink();
} }
} }