mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-07-28 23:08:59 +02:00
feat(settings): toggle to disable Hero animations
A single HeroMode above the router disables shared-element flights app-wide (mini player expand, track metadata cover) for users who prefer no motion or want to save the overlay rendering cost. On by default; persisted in AppSettings.
This commit is contained in:
+9
-1
@@ -98,6 +98,9 @@ class SpotiFLACApp extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final router = ref.watch(_routerProvider);
|
||||
final localeString = ref.watch(settingsProvider.select((s) => s.locale));
|
||||
final heroAnimationsEnabled = ref.watch(
|
||||
settingsProvider.select((s) => s.heroAnimationsEnabled),
|
||||
);
|
||||
final scrollBehavior = disableOverscrollEffects
|
||||
? const MaterialScrollBehavior().copyWith(overscroll: false)
|
||||
: const _FluidScrollBehavior();
|
||||
@@ -133,7 +136,12 @@ class SpotiFLACApp extends ConsumerWidget {
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
return MediaQuery(
|
||||
data: mediaQuery.copyWith(displayFeatures: const []),
|
||||
child: child ?? const SizedBox.shrink(),
|
||||
// Global Hero kill switch: heroes below a disabled HeroMode
|
||||
// never register, so no flights run on any navigator.
|
||||
child: HeroMode(
|
||||
enabled: heroAnimationsEnabled,
|
||||
child: child ?? const SizedBox.shrink(),
|
||||
),
|
||||
);
|
||||
},
|
||||
routerConfig: router,
|
||||
|
||||
@@ -2834,6 +2834,18 @@ abstract class AppLocalizations {
|
||||
/// **'Pure black background'**
|
||||
String get appearanceAmoledDarkSubtitle;
|
||||
|
||||
/// Toggle for shared-element (Hero) transitions
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Hero animations'**
|
||||
String get appearanceHeroAnimations;
|
||||
|
||||
/// Subtitle for the Hero animations toggle
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Fly covers between screens, e.g. when opening the player'**
|
||||
String get appearanceHeroAnimationsSubtitle;
|
||||
|
||||
/// Button - clear all queue items
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -1522,6 +1522,13 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'خلفية سوداء تامة';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'مسح الكل';
|
||||
|
||||
|
||||
@@ -1545,6 +1545,13 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'AMOLED Hintergrund';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Alles löschen';
|
||||
|
||||
|
||||
@@ -1523,6 +1523,13 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Pure black background';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Clear All';
|
||||
|
||||
|
||||
@@ -1523,6 +1523,13 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Pure black background';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Clear All';
|
||||
|
||||
|
||||
@@ -1567,6 +1567,13 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Fond noir pur';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Tout effacer';
|
||||
|
||||
|
||||
@@ -1523,6 +1523,13 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Pure black background';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Clear All';
|
||||
|
||||
|
||||
@@ -1532,6 +1532,13 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Latar belakang hitam murni';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Hapus Semua';
|
||||
|
||||
|
||||
@@ -1514,6 +1514,13 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'ピュアブラックの背景';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'すべて消去';
|
||||
|
||||
|
||||
@@ -1490,6 +1490,13 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => '순수 검정 배경화면';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => '모두 지우기';
|
||||
|
||||
|
||||
@@ -1523,6 +1523,13 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Pure black background';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Clear All';
|
||||
|
||||
|
||||
@@ -1523,6 +1523,13 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Pure black background';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Clear All';
|
||||
|
||||
|
||||
@@ -1538,6 +1538,13 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Глубокий чёрный фон';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Очистить всё';
|
||||
|
||||
|
||||
@@ -1540,6 +1540,13 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Saf siyah arka plan';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Tümünü Temizle';
|
||||
|
||||
|
||||
@@ -1546,6 +1546,13 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Чисто чорний фон';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Усі';
|
||||
|
||||
|
||||
@@ -1523,6 +1523,13 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
@override
|
||||
String get appearanceAmoledDarkSubtitle => 'Pure black background';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimations => 'Hero animations';
|
||||
|
||||
@override
|
||||
String get appearanceHeroAnimationsSubtitle =>
|
||||
'Fly covers between screens, e.g. when opening the player';
|
||||
|
||||
@override
|
||||
String get queueClearAll => 'Clear All';
|
||||
|
||||
|
||||
@@ -2010,6 +2010,14 @@
|
||||
"@appearanceAmoledDarkSubtitle": {
|
||||
"description": "Subtitle for AMOLED dark"
|
||||
},
|
||||
"appearanceHeroAnimations": "Hero animations",
|
||||
"@appearanceHeroAnimations": {
|
||||
"description": "Toggle for shared-element (Hero) transitions"
|
||||
},
|
||||
"appearanceHeroAnimationsSubtitle": "Fly covers between screens, e.g. when opening the player",
|
||||
"@appearanceHeroAnimationsSubtitle": {
|
||||
"description": "Subtitle for the Hero animations toggle"
|
||||
},
|
||||
"queueClearAll": "Clear All",
|
||||
"@queueClearAll": {
|
||||
"description": "Button - clear all queue items"
|
||||
|
||||
@@ -43,6 +43,10 @@ class AppSettings {
|
||||
final String singleFilenameFormat;
|
||||
final String albumFolderStructure;
|
||||
final bool showExtensionStore;
|
||||
|
||||
/// Shared-element (Hero) flights, e.g. the mini player artwork expanding
|
||||
/// into the full player. Off skips the flights entirely.
|
||||
final bool heroAnimationsEnabled;
|
||||
final String
|
||||
extensionVerificationBrowserMode; // 'external_first' or 'in_app_first'
|
||||
final String locale;
|
||||
@@ -131,6 +135,7 @@ class AppSettings {
|
||||
this.singleFilenameFormat = '{title} - {artist}',
|
||||
this.albumFolderStructure = 'artist_album',
|
||||
this.showExtensionStore = true,
|
||||
this.heroAnimationsEnabled = true,
|
||||
this.extensionVerificationBrowserMode = 'in_app_first',
|
||||
this.locale = 'system',
|
||||
this.lyricsMode = 'embed',
|
||||
@@ -200,6 +205,7 @@ class AppSettings {
|
||||
String? singleFilenameFormat,
|
||||
String? albumFolderStructure,
|
||||
bool? showExtensionStore,
|
||||
bool? heroAnimationsEnabled,
|
||||
String? extensionVerificationBrowserMode,
|
||||
String? locale,
|
||||
String? lyricsMode,
|
||||
@@ -277,6 +283,8 @@ class AppSettings {
|
||||
singleFilenameFormat: singleFilenameFormat ?? this.singleFilenameFormat,
|
||||
albumFolderStructure: albumFolderStructure ?? this.albumFolderStructure,
|
||||
showExtensionStore: showExtensionStore ?? this.showExtensionStore,
|
||||
heroAnimationsEnabled:
|
||||
heroAnimationsEnabled ?? this.heroAnimationsEnabled,
|
||||
extensionVerificationBrowserMode:
|
||||
extensionVerificationBrowserMode ??
|
||||
this.extensionVerificationBrowserMode,
|
||||
|
||||
@@ -48,6 +48,7 @@ AppSettings _$AppSettingsFromJson(Map<String, dynamic> json) => AppSettings(
|
||||
albumFolderStructure:
|
||||
json['albumFolderStructure'] as String? ?? 'artist_album',
|
||||
showExtensionStore: json['showExtensionStore'] as bool? ?? true,
|
||||
heroAnimationsEnabled: json['heroAnimationsEnabled'] as bool? ?? true,
|
||||
extensionVerificationBrowserMode:
|
||||
json['extensionVerificationBrowserMode'] as String? ?? 'in_app_first',
|
||||
locale: json['locale'] as String? ?? 'system',
|
||||
@@ -128,6 +129,7 @@ Map<String, dynamic> _$AppSettingsToJson(
|
||||
'singleFilenameFormat': instance.singleFilenameFormat,
|
||||
'albumFolderStructure': instance.albumFolderStructure,
|
||||
'showExtensionStore': instance.showExtensionStore,
|
||||
'heroAnimationsEnabled': instance.heroAnimationsEnabled,
|
||||
'extensionVerificationBrowserMode': instance.extensionVerificationBrowserMode,
|
||||
'locale': instance.locale,
|
||||
'lyricsMode': instance.lyricsMode,
|
||||
|
||||
@@ -580,6 +580,11 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void setHeroAnimationsEnabled(bool enabled) {
|
||||
state = state.copyWith(heroAnimationsEnabled: enabled);
|
||||
_saveSettings();
|
||||
}
|
||||
|
||||
void setExtensionVerificationBrowserMode(String mode) {
|
||||
state = state.copyWith(
|
||||
extensionVerificationBrowserMode:
|
||||
|
||||
@@ -90,6 +90,23 @@ class AppearanceSettingsPage extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.animation,
|
||||
title: context.l10n.appearanceHeroAnimations,
|
||||
subtitle: context.l10n.appearanceHeroAnimationsSubtitle,
|
||||
value: settings.heroAnimationsEnabled,
|
||||
onChanged: (value) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setHeroAnimationsEnabled(value),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(title: context.l10n.sectionLanguage),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user