Merge pull request #345 from Amonoman/main
Refactor settings into dedicated pages and update icons
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 954 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 647 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 429 B After Width: | Height: | Size: 603 B |
|
Before Width: | Height: | Size: 905 B After Width: | Height: | Size: 966 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 783 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 905 B After Width: | Height: | Size: 966 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.3 KiB |
@@ -121,7 +121,7 @@
|
||||
"@appearanceDynamicColor": {
|
||||
"description": "Material You dynamic colors"
|
||||
},
|
||||
"appearanceDynamicColorSubtitle": "Farben von Ihrem Hintergrundbild verwenden",
|
||||
"appearanceDynamicColorSubtitle": "Farben deines Hintergrundbilds verwenden",
|
||||
"@appearanceDynamicColorSubtitle": {
|
||||
"description": "Subtitle for dynamic color"
|
||||
},
|
||||
@@ -178,7 +178,7 @@
|
||||
"@optionsAutoFallbackSubtitle": {
|
||||
"description": "Subtitle for auto fallback"
|
||||
},
|
||||
"optionsUseExtensionProviders": "Erweiterungs-Anbieter verwenden",
|
||||
"optionsUseExtensionProviders": "Erweiterungsanbieter verwenden",
|
||||
"@optionsUseExtensionProviders": {
|
||||
"description": "Enable extension download providers"
|
||||
},
|
||||
@@ -194,7 +194,7 @@
|
||||
"@optionsEmbedLyrics": {
|
||||
"description": "Embed lyrics in audio files"
|
||||
},
|
||||
"optionsEmbedLyricsSubtitle": "Synchronisierte Lyrics in FLAC-Dateien einbetten",
|
||||
"optionsEmbedLyricsSubtitle": "Synchronisierte Songtexte neben heruntergeladenen Titeln speichern",
|
||||
"@optionsEmbedLyricsSubtitle": {
|
||||
"description": "Subtitle for embed lyrics"
|
||||
},
|
||||
@@ -230,7 +230,7 @@
|
||||
"@optionsArtistTagModeJoined": {
|
||||
"description": "Artist tag mode option that joins multiple artists into one value"
|
||||
},
|
||||
"optionsArtistTagModeJoinedSubtitle": "Einen Künstler wert wie \"Artist A, Artist B\" für maximale Spieler-Kompatibilität schreiben.",
|
||||
"optionsArtistTagModeJoinedSubtitle": "Einen Künstler-Wert wie \"Künstler A, Künstler B\" für maximale Player-Kompatibilität schreiben.",
|
||||
"@optionsArtistTagModeJoinedSubtitle": {
|
||||
"description": "Subtitle for joined artist tag mode"
|
||||
},
|
||||
@@ -438,7 +438,7 @@
|
||||
"@aboutReportIssue": {
|
||||
"description": "Link to report bugs"
|
||||
},
|
||||
"aboutReportIssueSubtitle": "Melde jedes Problem, die dir auftreten",
|
||||
"aboutReportIssueSubtitle": "Melde Probleme, die dir auffallen",
|
||||
"@aboutReportIssueSubtitle": {
|
||||
"description": "Subtitle for report issue"
|
||||
},
|
||||
@@ -486,7 +486,7 @@
|
||||
"@aboutSachinsenalDesc": {
|
||||
"description": "Credit description for sachinsenal0x64"
|
||||
},
|
||||
"aboutSjdonadoDesc": "Ersteller von I Don't Have Spotify (IDHS). Der Fallback-Link-Resolver, der den Tag rettete!",
|
||||
"aboutSjdonadoDesc": "Ersteller von I Don't Have Spotify (IDHS). Der Fallback-Link-Resolver, der den Tag rettet!",
|
||||
"@aboutSjdonadoDesc": {
|
||||
"description": "Credit description for sjdonado"
|
||||
},
|
||||
@@ -576,7 +576,7 @@
|
||||
"@setupPermissionDeniedMessage": {
|
||||
"description": "Error when permission denied"
|
||||
},
|
||||
"setupPermissionRequired": "{permissionType} Zugriff verweigert",
|
||||
"setupPermissionRequired": "{permissionType}-Berechtigung erforderlich",
|
||||
"@setupPermissionRequired": {
|
||||
"description": "Generic permission required title",
|
||||
"placeholders": {
|
||||
@@ -586,7 +586,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"setupPermissionRequiredMessage": "{permissionType} Berechtigung ist erforderlich für\ndie beste Benutzererfahrung. Für kannst dies später in den Einstellungen ändern.",
|
||||
"setupPermissionRequiredMessage": "{permissionType}-Berechtigung ist erforderlich für\ndie beste Benutzererfahrung. Du kannst dies später in den Einstellungen ändern.",
|
||||
"@setupPermissionRequiredMessage": {
|
||||
"description": "Generic permission required message",
|
||||
"placeholders": {
|
||||
@@ -603,7 +603,7 @@
|
||||
"@setupNoFolderSelected": {
|
||||
"description": "Prompt when no folder selected"
|
||||
},
|
||||
"setupUseDefault": "Standart benutzen",
|
||||
"setupUseDefault": "Standard verwenden",
|
||||
"@setupUseDefault": {
|
||||
"description": "Button to use default folder"
|
||||
},
|
||||
@@ -663,7 +663,7 @@
|
||||
"@setupNotificationEnable": {
|
||||
"description": "Button to enable notifications"
|
||||
},
|
||||
"setupFolderChoose": "Speicherort auwählen",
|
||||
"setupFolderChoose": "Speicherort auswählen",
|
||||
"@setupFolderChoose": {
|
||||
"description": "Button to choose folder"
|
||||
},
|
||||
@@ -747,7 +747,7 @@
|
||||
"@dialogDiscardChanges": {
|
||||
"description": "Dialog title - unsaved changes warning"
|
||||
},
|
||||
"dialogUnsavedChanges": "Hast du noch nicht alle Änderungen gespeichert. Möchtest du die Änderungen verwerfen?",
|
||||
"dialogUnsavedChanges": "Du hast ungespeicherte Änderungen. Möchtest du sie verwerfen?",
|
||||
"@dialogUnsavedChanges": {
|
||||
"description": "Dialog message - unsaved changes"
|
||||
},
|
||||
@@ -759,7 +759,7 @@
|
||||
"@dialogRemoveExtension": {
|
||||
"description": "Dialog title - uninstall extension"
|
||||
},
|
||||
"dialogRemoveExtensionMessage": "Bist Du sicher, dass Du diese Erweiterung entfernen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"dialogRemoveExtensionMessage": "Bist du sicher, dass du diese Erweiterung entfernen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"@dialogRemoveExtensionMessage": {
|
||||
"description": "Dialog message - uninstall confirmation"
|
||||
},
|
||||
@@ -767,7 +767,7 @@
|
||||
"@dialogUninstallExtension": {
|
||||
"description": "Dialog title - uninstall extension"
|
||||
},
|
||||
"dialogUninstallExtensionMessage": "Bist du dir sicher, dass du {extensionName} entfernen möchtest?",
|
||||
"dialogUninstallExtensionMessage": "Bist du sicher, dass du {extensionName} entfernen möchtest?",
|
||||
"@dialogUninstallExtensionMessage": {
|
||||
"description": "Dialog message - uninstall specific extension",
|
||||
"placeholders": {
|
||||
@@ -780,7 +780,7 @@
|
||||
"@dialogClearHistoryTitle": {
|
||||
"description": "Dialog title - clear download history"
|
||||
},
|
||||
"dialogClearHistoryMessage": "Bist du dir sicher, dass du den gesamten Download verlauf löschen möchten? Dies kann nicht rückgängig gemacht werden.",
|
||||
"dialogClearHistoryMessage": "Bist du sicher, dass du den gesamten Downloadverlauf löschen möchtest? Dies kann nicht rückgängig gemacht werden.",
|
||||
"@dialogClearHistoryMessage": {
|
||||
"description": "Dialog message - clear history confirmation"
|
||||
},
|
||||
@@ -846,7 +846,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"snackbarAlreadyInLibrary": "\"{trackName}\" existiert bereits in Ihrer Bibliothek",
|
||||
"snackbarAlreadyInLibrary": "\"{trackName}\" existiert bereits in deiner Bibliothek",
|
||||
"@snackbarAlreadyInLibrary": {
|
||||
"description": "Snackbar - track already exists in local library",
|
||||
"placeholders": {
|
||||
@@ -867,7 +867,7 @@
|
||||
"@snackbarCredentialsCleared": {
|
||||
"description": "Snackbar - Spotify credentials removed"
|
||||
},
|
||||
"snackbarDeletedTracks": "{count} {count, plural, one {}=1{Titel} other{Titel}}",
|
||||
"snackbarDeletedTracks": "{count} {count, plural, =1{Titel gelöscht} other{Titel gelöscht}}",
|
||||
"@snackbarDeletedTracks": {
|
||||
"description": "Snackbar - tracks deleted",
|
||||
"placeholders": {
|
||||
@@ -969,7 +969,7 @@
|
||||
"@errorUrlFetchFailed": {
|
||||
"description": "Error message - generic URL fetch failure"
|
||||
},
|
||||
"errorMissingExtensionSource": "Kann {item} nicht lade wegen fehlender Erweiterungsquelle",
|
||||
"errorMissingExtensionSource": "Kann {item} nicht laden wegen fehlender Erweiterungsquelle",
|
||||
"@errorMissingExtensionSource": {
|
||||
"description": "Error - extension source not available",
|
||||
"placeholders": {
|
||||
@@ -1287,7 +1287,7 @@
|
||||
"@logClearLogsTitle": {
|
||||
"description": "Clear logs dialog title"
|
||||
},
|
||||
"logClearLogsMessage": "Bist du dir sicher, dass Sie alle Protokolle löschen möchtest?",
|
||||
"logClearLogsMessage": "Bist du sicher, dass du alle Protokolle löschen möchtest?",
|
||||
"@logClearLogsMessage": {
|
||||
"description": "Clear logs confirmation message"
|
||||
},
|
||||
@@ -2462,7 +2462,7 @@
|
||||
"@libraryClearConfirmTitle": {
|
||||
"description": "Dialog title for clear confirmation"
|
||||
},
|
||||
"libraryClearConfirmMessage": "Dadurch werden alle gescannten Titel aus Ihrer Bibliothek entfernt. Ihre eigentlichen Musikdateien werden nicht gelöscht.",
|
||||
"libraryClearConfirmMessage": "Dadurch werden alle gescannten Titel aus deiner Bibliothek entfernt. Deine eigentlichen Musikdateien werden nicht gelöscht.",
|
||||
"@libraryClearConfirmMessage": {
|
||||
"description": "Dialog message for clear confirmation"
|
||||
},
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"@@locale": "en",
|
||||
"@@last_modified": "2026-01-16",
|
||||
"@@last_modified": "2026-04-28",
|
||||
"appName": "SpotiFLAC",
|
||||
"@appName": {
|
||||
"description": "App name - DO NOT TRANSLATE"
|
||||
@@ -99,7 +99,7 @@
|
||||
},
|
||||
"downloadFolderOrganization": "Folder Organization",
|
||||
"@downloadFolderOrganization": {
|
||||
"description": "Setting for folder structure"
|
||||
"description": "Title of the folder organization picker bottom sheet"
|
||||
},
|
||||
"appearanceTitle": "Appearance",
|
||||
"@appearanceTitle": {
|
||||
@@ -145,7 +145,7 @@
|
||||
"@optionsPrimaryProvider": {
|
||||
"description": "Main search provider setting"
|
||||
},
|
||||
"optionsPrimaryProviderSubtitle": "Service used when searching by track name.",
|
||||
"optionsPrimaryProviderSubtitle": "Service used for searching by track or album name",
|
||||
"@optionsPrimaryProviderSubtitle": {
|
||||
"description": "Subtitle for primary provider"
|
||||
},
|
||||
@@ -194,7 +194,7 @@
|
||||
"@optionsEmbedLyrics": {
|
||||
"description": "Embed lyrics in audio files"
|
||||
},
|
||||
"optionsEmbedLyricsSubtitle": "Embed synced lyrics into FLAC files",
|
||||
"optionsEmbedLyricsSubtitle": "Save synced lyrics alongside your downloaded tracks",
|
||||
"@optionsEmbedLyricsSubtitle": {
|
||||
"description": "Subtitle for embed lyrics"
|
||||
},
|
||||
@@ -729,7 +729,7 @@
|
||||
},
|
||||
"dialogDownload": "Download",
|
||||
"@dialogDownload": {
|
||||
"description": "Dialog button - download action"
|
||||
"description": "Confirm button in Download All dialog"
|
||||
},
|
||||
"dialogDiscard": "Discard",
|
||||
"@dialogDiscard": {
|
||||
@@ -1449,11 +1449,11 @@
|
||||
"@settingsAppearanceSubtitle": {
|
||||
"description": "Appearance settings description"
|
||||
},
|
||||
"settingsDownloadSubtitle": "Service, quality, filename format",
|
||||
"settingsDownloadSubtitle": "Service, quality, fallback",
|
||||
"@settingsDownloadSubtitle": {
|
||||
"description": "Download settings description"
|
||||
},
|
||||
"settingsOptionsSubtitle": "Fallback, lyrics, cover art, updates",
|
||||
"settingsOptionsSubtitle": "Fallback, metadata, lyrics, cover art",
|
||||
"@settingsOptionsSubtitle": {
|
||||
"description": "Options settings description"
|
||||
},
|
||||
@@ -3592,18 +3592,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"downloadUseAlbumArtistForFoldersAlbumSubtitle": "Artist folders use Album Artist when available",
|
||||
"downloadUseAlbumArtistForFoldersAlbumSubtitle": "Folder named after Album Artist tag",
|
||||
"@downloadUseAlbumArtistForFoldersAlbumSubtitle": {
|
||||
"description": "Subtitle when Album Artist is used for folder naming"
|
||||
"description": "Subtitle when album artist is used for folder names"
|
||||
},
|
||||
"downloadUseAlbumArtistForFoldersTrackSubtitle": "Artist folders use Track Artist only",
|
||||
"downloadUseAlbumArtistForFoldersTrackSubtitle": "Folder named after Track Artist tag",
|
||||
"@downloadUseAlbumArtistForFoldersTrackSubtitle": {
|
||||
"description": "Subtitle when Track Artist is used for folder naming"
|
||||
"description": "Subtitle when track artist is used for folder names"
|
||||
},
|
||||
|
||||
"lyricsProvidersTitle": "Lyrics Providers",
|
||||
"lyricsProvidersTitle": "Lyrics Provider Priority",
|
||||
"@lyricsProvidersTitle": {
|
||||
"description": "Title for the lyrics provider priority page"
|
||||
"description": "Settings item title for lyrics provider order"
|
||||
},
|
||||
"lyricsProvidersDescription": "Enable, disable and reorder lyrics sources. Providers are tried top-to-bottom until lyrics are found.",
|
||||
"@lyricsProvidersDescription": {
|
||||
@@ -3667,7 +3666,6 @@
|
||||
"@lyricsProviderExtensionDesc": {
|
||||
"description": "Generic description for extension-based lyrics providers"
|
||||
},
|
||||
|
||||
"safMigrationTitle": "Storage Update Required",
|
||||
"@safMigrationTitle": {
|
||||
"description": "Title of SAF migration dialog"
|
||||
@@ -3684,16 +3682,14 @@
|
||||
"@safMigrationSuccess": {
|
||||
"description": "Snackbar after successfully migrating to SAF"
|
||||
},
|
||||
|
||||
"settingsDonate": "Donate",
|
||||
"settingsDonate": "Support Development",
|
||||
"@settingsDonate": {
|
||||
"description": "Settings menu item - donate"
|
||||
"description": "Settings menu item - donate page"
|
||||
},
|
||||
"settingsDonateSubtitle": "Support SpotiFLAC-Mobile development",
|
||||
"settingsDonateSubtitle": "Buy the developer a coffee",
|
||||
"@settingsDonateSubtitle": {
|
||||
"description": "Subtitle for donate menu item"
|
||||
},
|
||||
|
||||
"tooltipLoveAll": "Love All",
|
||||
"@tooltipLoveAll": {
|
||||
"description": "Tooltip for the Love All button on album/playlist screens"
|
||||
@@ -3720,10 +3716,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"dialogDownloadAllTitle": "Download All",
|
||||
"@dialogDownloadAllTitle": {
|
||||
"description": "Title of the Download All confirmation dialog"
|
||||
"description": "Dialog title for bulk download confirmation"
|
||||
},
|
||||
"dialogDownloadAllMessage": "Download {count} tracks?",
|
||||
"@dialogDownloadAllMessage": {
|
||||
@@ -3734,11 +3729,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dialogDownload": "Download",
|
||||
"@dialogDownload": {
|
||||
"description": "Confirm button in Download All dialog"
|
||||
},
|
||||
|
||||
"homeSkipAlreadyDownloaded": "Skip already downloaded songs",
|
||||
"@homeSkipAlreadyDownloaded": {
|
||||
"description": "Checkbox label in import dialog to skip already-downloaded songs"
|
||||
@@ -3751,7 +3741,6 @@
|
||||
"@homeAlbumInfoUnavailable": {
|
||||
"description": "Snackbar when album info cannot be loaded"
|
||||
},
|
||||
|
||||
"snackbarLoadingCueSheet": "Loading CUE sheet...",
|
||||
"@snackbarLoadingCueSheet": {
|
||||
"description": "Snackbar while loading a CUE sheet file"
|
||||
@@ -3781,190 +3770,181 @@
|
||||
"@snackbarNoActionDefined": {
|
||||
"description": "Snackbar when an extension button has no action configured"
|
||||
},
|
||||
|
||||
"noTracksFoundForAlbum": "No tracks found for this album",
|
||||
"@noTracksFoundForAlbum": {
|
||||
"description": "Empty state message when an album has no tracks"
|
||||
},
|
||||
|
||||
"downloadLocationSubtitle": "Choose storage mode for downloaded files.",
|
||||
"downloadLocationSubtitle": "Choose where to save your downloaded tracks",
|
||||
"@downloadLocationSubtitle": {
|
||||
"description": "Subtitle text in Android download location bottom sheet"
|
||||
"description": "Subtitle shown in the download location picker sheet"
|
||||
},
|
||||
"storageModeAppFolder": "App folder (non-SAF)",
|
||||
"storageModeAppFolder": "App Folder (Recommended)",
|
||||
"@storageModeAppFolder": {
|
||||
"description": "Storage mode option - use legacy app folder"
|
||||
"description": "Storage mode option - app-managed folder"
|
||||
},
|
||||
"storageModeAppFolderSubtitle": "Use default Music/SpotiFLAC path",
|
||||
"storageModeAppFolderSubtitle": "Saves to Music/SpotiFLAC by default",
|
||||
"@storageModeAppFolderSubtitle": {
|
||||
"description": "Subtitle for app folder storage mode"
|
||||
},
|
||||
"storageModeSaf": "SAF folder",
|
||||
"storageModeSaf": "Custom Folder (SAF)",
|
||||
"@storageModeSaf": {
|
||||
"description": "Storage mode option - use Android SAF picker"
|
||||
"description": "Storage mode option - Storage Access Framework"
|
||||
},
|
||||
"storageModeSafSubtitle": "Pick folder via Android Storage Access Framework",
|
||||
"storageModeSafSubtitle": "Pick any folder, including SD card",
|
||||
"@storageModeSafSubtitle": {
|
||||
"description": "Subtitle for SAF storage mode"
|
||||
},
|
||||
"downloadFilenameDescription": "Customize how your files are named.",
|
||||
"downloadFilenameDescription": "Use {artist}, {title}, {album}, {track}, {year}, {date}, {disc} as placeholders.",
|
||||
"@downloadFilenameDescription": {
|
||||
"description": "Description text in filename format bottom sheet"
|
||||
"description": "Description shown in filename format editor"
|
||||
},
|
||||
"downloadFilenameInsertTag": "Tap to insert tag:",
|
||||
"@downloadFilenameInsertTag": {
|
||||
"description": "Label above filename tag chips"
|
||||
},
|
||||
"downloadSeparateSinglesEnabled": "Albums/ and Singles/ folders",
|
||||
"downloadSeparateSinglesEnabled": "Singles and EPs saved in a separate folder",
|
||||
"@downloadSeparateSinglesEnabled": {
|
||||
"description": "Subtitle when separate singles folder is enabled"
|
||||
"description": "Subtitle when separate singles folder is on"
|
||||
},
|
||||
"downloadSeparateSinglesDisabled": "All files in same structure",
|
||||
"downloadSeparateSinglesDisabled": "Singles and albums saved in the same folder",
|
||||
"@downloadSeparateSinglesDisabled": {
|
||||
"description": "Subtitle when separate singles folder is disabled"
|
||||
"description": "Subtitle when separate singles folder is off"
|
||||
},
|
||||
"downloadArtistNameFilters": "Artist Name Filters",
|
||||
"@downloadArtistNameFilters": {
|
||||
"description": "Setting title for artist folder filter options"
|
||||
},
|
||||
"downloadCreatePlaylistSourceFolder": "Create playlist source folder",
|
||||
"downloadCreatePlaylistSourceFolder": "Playlist Source Folder",
|
||||
"@downloadCreatePlaylistSourceFolder": {
|
||||
"description": "Setting title for adding a playlist folder prefix before the normal organization structure"
|
||||
"description": "Setting to create a subfolder per playlist source"
|
||||
},
|
||||
"downloadCreatePlaylistSourceFolderEnabled": "Playlist downloads use Playlist/ plus your normal folder structure.",
|
||||
"downloadCreatePlaylistSourceFolderEnabled": "A subfolder is created for each playlist",
|
||||
"@downloadCreatePlaylistSourceFolderEnabled": {
|
||||
"description": "Subtitle when playlist source folder prefix is enabled"
|
||||
"description": "Subtitle when playlist folder is enabled"
|
||||
},
|
||||
"downloadCreatePlaylistSourceFolderDisabled": "Playlist downloads use the normal folder structure only.",
|
||||
"downloadCreatePlaylistSourceFolderDisabled": "All tracks saved directly to download folder",
|
||||
"@downloadCreatePlaylistSourceFolderDisabled": {
|
||||
"description": "Subtitle when playlist source folder prefix is disabled"
|
||||
"description": "Subtitle when playlist folder is disabled"
|
||||
},
|
||||
"downloadCreatePlaylistSourceFolderRedundant": "By Playlist already places downloads inside a playlist folder.",
|
||||
"downloadCreatePlaylistSourceFolderRedundant": "Handled by folder organization setting",
|
||||
"@downloadCreatePlaylistSourceFolderRedundant": {
|
||||
"description": "Subtitle when playlist folder prefix setting is redundant because folder organization is already by playlist"
|
||||
"description": "Subtitle when folder organization is already set to playlist"
|
||||
},
|
||||
"downloadSongLinkRegion": "SongLink Region",
|
||||
"@downloadSongLinkRegion": {
|
||||
"description": "Setting title for SongLink country region"
|
||||
"description": "Setting for SongLink region used during fallback resolution"
|
||||
},
|
||||
"downloadNetworkCompatibilityMode": "Network compatibility mode",
|
||||
"downloadNetworkCompatibilityMode": "Network Compatibility Mode",
|
||||
"@downloadNetworkCompatibilityMode": {
|
||||
"description": "Setting title for network compatibility toggle"
|
||||
"description": "Setting for legacy TLS/network handling"
|
||||
},
|
||||
"downloadNetworkCompatibilityModeEnabled": "Enabled: try HTTP + accept invalid TLS certificates (unsafe)",
|
||||
"downloadNetworkCompatibilityModeEnabled": "Using legacy TLS settings for older networks",
|
||||
"@downloadNetworkCompatibilityModeEnabled": {
|
||||
"description": "Subtitle when network compatibility mode is enabled"
|
||||
"description": "Subtitle when network compatibility mode is on"
|
||||
},
|
||||
"downloadNetworkCompatibilityModeDisabled": "Off: strict HTTPS certificate validation (recommended)",
|
||||
"downloadNetworkCompatibilityModeDisabled": "Using standard network settings",
|
||||
"@downloadNetworkCompatibilityModeDisabled": {
|
||||
"description": "Subtitle when network compatibility mode is disabled"
|
||||
"description": "Subtitle when network compatibility mode is off"
|
||||
},
|
||||
"downloadSelectServiceToEnable": "Select a built-in service to enable",
|
||||
"downloadSelectServiceToEnable": "Select Tidal or Qobuz to enable this option",
|
||||
"@downloadSelectServiceToEnable": {
|
||||
"description": "Hint shown instead of Ask-quality subtitle when no built-in service selected"
|
||||
"description": "Subtitle when quality picker is disabled due to extension service"
|
||||
},
|
||||
|
||||
"downloadSelectTidalQobuz": "Select Tidal or Qobuz above to configure quality",
|
||||
"downloadSelectTidalQobuz": "Select Tidal or Qobuz to choose audio quality",
|
||||
"@downloadSelectTidalQobuz": {
|
||||
"description": "Info hint when non-Tidal/Qobuz service is selected"
|
||||
"description": "Info shown when a non-built-in service is selected"
|
||||
},
|
||||
"downloadEmbedLyricsDisabled": "Disabled while Embed Metadata is turned off",
|
||||
"downloadEmbedLyricsDisabled": "Enable metadata embedding first",
|
||||
"@downloadEmbedLyricsDisabled": {
|
||||
"description": "Subtitle for Embed Lyrics when Embed Metadata is disabled"
|
||||
"description": "Subtitle when lyrics embedding is blocked by metadata toggle"
|
||||
},
|
||||
"downloadNeteaseIncludeTranslation": "Netease: Include Translation",
|
||||
"@downloadNeteaseIncludeTranslation": {
|
||||
"description": "Toggle title for including Netease translated lyrics"
|
||||
"description": "Setting to include translated lyrics from Netease"
|
||||
},
|
||||
"downloadNeteaseIncludeTranslationEnabled": "Append translated lyrics when available",
|
||||
"downloadNeteaseIncludeTranslationEnabled": "Chinese translation lines included",
|
||||
"@downloadNeteaseIncludeTranslationEnabled": {
|
||||
"description": "Subtitle when Netease translation is enabled"
|
||||
"description": "Subtitle when Netease translation is on"
|
||||
},
|
||||
"downloadNeteaseIncludeTranslationDisabled": "Use original lyrics only",
|
||||
"downloadNeteaseIncludeTranslationDisabled": "Original lyrics only",
|
||||
"@downloadNeteaseIncludeTranslationDisabled": {
|
||||
"description": "Subtitle when Netease translation is disabled"
|
||||
"description": "Subtitle when Netease translation is off"
|
||||
},
|
||||
"downloadNeteaseIncludeRomanization": "Netease: Include Romanization",
|
||||
"@downloadNeteaseIncludeRomanization": {
|
||||
"description": "Toggle title for including Netease romanized lyrics"
|
||||
"description": "Setting to include romanized lyrics from Netease"
|
||||
},
|
||||
"downloadNeteaseIncludeRomanizationEnabled": "Append romanized lyrics when available",
|
||||
"downloadNeteaseIncludeRomanizationEnabled": "Romanization lines included",
|
||||
"@downloadNeteaseIncludeRomanizationEnabled": {
|
||||
"description": "Subtitle when Netease romanization is enabled"
|
||||
"description": "Subtitle when Netease romanization is on"
|
||||
},
|
||||
"downloadNeteaseIncludeRomanizationDisabled": "Disabled",
|
||||
"downloadNeteaseIncludeRomanizationDisabled": "No romanization",
|
||||
"@downloadNeteaseIncludeRomanizationDisabled": {
|
||||
"description": "Subtitle when Netease romanization is disabled"
|
||||
"description": "Subtitle when Netease romanization is off"
|
||||
},
|
||||
"downloadAppleQqMultiPerson": "Apple/QQ Multi-Person Word-by-Word",
|
||||
"downloadAppleQqMultiPerson": "Apple / QQ: Multi-Person Lyrics",
|
||||
"@downloadAppleQqMultiPerson": {
|
||||
"description": "Toggle title for Apple/QQ multi-person word-by-word lyrics"
|
||||
"description": "Setting for word-by-word multi-person lyrics from Apple Music and QQ Music"
|
||||
},
|
||||
"downloadAppleQqMultiPersonEnabled": "Enable v1/v2 speaker and [bg:] tags",
|
||||
"downloadAppleQqMultiPersonEnabled": "Speaker labels included for duets and group tracks",
|
||||
"@downloadAppleQqMultiPersonEnabled": {
|
||||
"description": "Subtitle when multi-person word-by-word is enabled"
|
||||
"description": "Subtitle when multi-person lyrics is on"
|
||||
},
|
||||
"downloadAppleQqMultiPersonDisabled": "Simplified word-by-word formatting",
|
||||
"downloadAppleQqMultiPersonDisabled": "Standard lyrics without speaker labels",
|
||||
"@downloadAppleQqMultiPersonDisabled": {
|
||||
"description": "Subtitle when multi-person word-by-word is disabled"
|
||||
"description": "Subtitle when multi-person lyrics is off"
|
||||
},
|
||||
"downloadMusixmatchLanguage": "Musixmatch Language",
|
||||
"@downloadMusixmatchLanguage": {
|
||||
"description": "Setting title for Musixmatch language preference"
|
||||
"description": "Setting for Musixmatch lyrics translation language"
|
||||
},
|
||||
"downloadMusixmatchLanguageAuto": "Auto (original)",
|
||||
"downloadMusixmatchLanguageAuto": "Auto (original language)",
|
||||
"@downloadMusixmatchLanguageAuto": {
|
||||
"description": "Option label when Musixmatch uses original language"
|
||||
"description": "Subtitle when no language is set"
|
||||
},
|
||||
"downloadFilterContributing": "Filter contributing artists in Album Artist",
|
||||
"downloadFilterContributing": "Filter Contributing Artists",
|
||||
"@downloadFilterContributing": {
|
||||
"description": "Toggle title for filtering contributing artists in Album Artist metadata"
|
||||
"description": "Setting to strip contributing artists from Album Artist folder name"
|
||||
},
|
||||
"downloadFilterContributingEnabled": "Album Artist metadata uses primary artist only",
|
||||
"downloadFilterContributingEnabled": "Contributing artists removed from Album Artist folder name",
|
||||
"@downloadFilterContributingEnabled": {
|
||||
"description": "Subtitle when contributing artist filter is enabled"
|
||||
"description": "Subtitle when contributing artist filter is on"
|
||||
},
|
||||
"downloadFilterContributingDisabled": "Keep full Album Artist metadata value",
|
||||
"downloadFilterContributingDisabled": "Full Album Artist string used",
|
||||
"@downloadFilterContributingDisabled": {
|
||||
"description": "Subtitle when contributing artist filter is disabled"
|
||||
"description": "Subtitle when contributing artist filter is off"
|
||||
},
|
||||
|
||||
"downloadProvidersNoneEnabled": "None enabled",
|
||||
"downloadProvidersNoneEnabled": "No providers enabled",
|
||||
"@downloadProvidersNoneEnabled": {
|
||||
"description": "Subtitle for lyrics providers setting when no providers are enabled"
|
||||
"description": "Shown when no lyrics providers are active"
|
||||
},
|
||||
"downloadMusixmatchLanguageCode": "Language code",
|
||||
"@downloadMusixmatchLanguageCode": {
|
||||
"description": "Label for the Musixmatch language code text field"
|
||||
"description": "Label for Musixmatch language input field"
|
||||
},
|
||||
"downloadMusixmatchLanguageHint": "auto / en / es / ja",
|
||||
"downloadMusixmatchLanguageHint": "e.g. en, de, ja",
|
||||
"@downloadMusixmatchLanguageHint": {
|
||||
"description": "Hint text for the Musixmatch language code field"
|
||||
"description": "Placeholder for Musixmatch language input"
|
||||
},
|
||||
"downloadMusixmatchLanguageDesc": "Set preferred language code (example: en, es, ja). Leave empty for auto.",
|
||||
"downloadMusixmatchLanguageDesc": "Enter a BCP-47 language code (e.g. en, de, ja) to request translated lyrics from Musixmatch.",
|
||||
"@downloadMusixmatchLanguageDesc": {
|
||||
"description": "Description in the Musixmatch language picker"
|
||||
"description": "Description in Musixmatch language picker"
|
||||
},
|
||||
"downloadMusixmatchAuto": "Auto",
|
||||
"@downloadMusixmatchAuto": {
|
||||
"description": "Button to reset Musixmatch language to automatic"
|
||||
"description": "Button to clear Musixmatch language (use auto)"
|
||||
},
|
||||
|
||||
"downloadNetworkAnySubtitle": "WiFi + Mobile Data",
|
||||
"downloadNetworkAnySubtitle": "Use WiFi or mobile data",
|
||||
"@downloadNetworkAnySubtitle": {
|
||||
"description": "Subtitle for 'Any' network mode option"
|
||||
"description": "Subtitle for any-network option in picker"
|
||||
},
|
||||
"downloadNetworkWifiOnlySubtitle": "Pause downloads on mobile data",
|
||||
"downloadNetworkWifiOnlySubtitle": "Downloads pause when on mobile data",
|
||||
"@downloadNetworkWifiOnlySubtitle": {
|
||||
"description": "Subtitle for 'WiFi only' network mode option"
|
||||
"description": "Subtitle for WiFi-only option in picker"
|
||||
},
|
||||
"downloadSongLinkRegionDesc": "Used as userCountry for SongLink API lookup.",
|
||||
"downloadSongLinkRegionDesc": "Region used when resolving track links via SongLink. Choose the country where your streaming services are available.",
|
||||
"@downloadSongLinkRegionDesc": {
|
||||
"description": "Description in the SongLink region picker"
|
||||
},
|
||||
"downloadFolderOrganization": "Folder Organization",
|
||||
"@downloadFolderOrganization": {
|
||||
"description": "Title of the folder organization picker bottom sheet"
|
||||
"description": "Description in SongLink region picker"
|
||||
},
|
||||
"snackbarUnsupportedAudioFormat": "Unsupported audio format",
|
||||
"@snackbarUnsupportedAudioFormat": {
|
||||
@@ -3974,10 +3954,6 @@
|
||||
"@cacheRefresh": {
|
||||
"description": "Tooltip for refresh button on cache management page"
|
||||
},
|
||||
"dialogDownloadAllTitle": "Download All",
|
||||
"@dialogDownloadAllTitle": {
|
||||
"description": "Dialog title for bulk download confirmation"
|
||||
},
|
||||
"dialogDownloadPlaylistsMessage": "Download {trackCount} {trackCount, plural, =1{track} other{tracks}} from {playlistCount} {playlistCount, plural, =1{playlist} other{playlists}}?",
|
||||
"@dialogDownloadPlaylistsMessage": {
|
||||
"description": "Dialog message for bulk playlist download confirmation",
|
||||
@@ -4105,7 +4081,6 @@
|
||||
"@editMetadataSelectEmpty": {
|
||||
"description": "Button to select only fields that are currently empty"
|
||||
},
|
||||
|
||||
"queueDownloadingCount": "Downloading ({count})",
|
||||
"@queueDownloadingCount": {
|
||||
"description": "Header for active downloads section with count",
|
||||
@@ -4229,7 +4204,6 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
@@ -4249,7 +4223,7 @@
|
||||
},
|
||||
"extensionsHomeFeedAuto": "Auto",
|
||||
"@extensionsHomeFeedAuto": {
|
||||
"description": "Extensions page - home feed provider option: auto"
|
||||
"description": "Label for auto-selected search provider"
|
||||
},
|
||||
"extensionsHomeFeedAutoSubtitle": "Automatically select the best available",
|
||||
"@extensionsHomeFeedAutoSubtitle": {
|
||||
@@ -4268,7 +4242,6 @@
|
||||
"@extensionsNoHomeFeedExtensions": {
|
||||
"description": "Extensions page - shown when no installed extension has home feed"
|
||||
},
|
||||
|
||||
"sortAlphaAsc": "A-Z",
|
||||
"@sortAlphaAsc": {
|
||||
"description": "Sort option - alphabetical ascending"
|
||||
@@ -4294,7 +4267,6 @@
|
||||
"@cancelDownloadKeep": {
|
||||
"description": "Dialog button - keep the active download (do not cancel)"
|
||||
},
|
||||
|
||||
"metadataSaveFailedFfmpeg": "Failed to save metadata via FFmpeg",
|
||||
"@metadataSaveFailedFfmpeg": {
|
||||
"description": "Snackbar error when FFmpeg fails to write metadata"
|
||||
@@ -4303,7 +4275,6 @@
|
||||
"@metadataSaveFailedStorage": {
|
||||
"description": "Snackbar error when writing metadata file back to storage fails"
|
||||
},
|
||||
|
||||
"snackbarFolderPickerFailed": "Failed to open folder picker: {error}",
|
||||
"@snackbarFolderPickerFailed": {
|
||||
"description": "Snackbar shown when folder picker fails to open",
|
||||
@@ -4313,7 +4284,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"errorLoadAlbum": "Failed to load album",
|
||||
"@errorLoadAlbum": {
|
||||
"description": "Error state shown when album fails to load"
|
||||
@@ -4326,7 +4296,6 @@
|
||||
"@errorLoadArtist": {
|
||||
"description": "Error state shown when artist fails to load"
|
||||
},
|
||||
|
||||
"notifChannelDownloadName": "Download Progress",
|
||||
"@notifChannelDownloadName": {
|
||||
"description": "Android notification channel name for download progress"
|
||||
@@ -4540,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Не вдалося завантажити оновлення. Спробуйте пізніше.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4509,5 +4509,77 @@
|
||||
"notifUpdateFailedBody": "Could not download update. Try again later.",
|
||||
"@notifUpdateFailedBody": {
|
||||
"description": "Notification body when app update download fails"
|
||||
},
|
||||
"settingsFiles": "Files & Folders",
|
||||
"@settingsFiles": {
|
||||
"description": "Settings menu item - file and folder settings"
|
||||
},
|
||||
"settingsFilesSubtitle": "Download location, filename, folder structure",
|
||||
"@settingsFilesSubtitle": {
|
||||
"description": "Subtitle for files & folders settings"
|
||||
},
|
||||
"settingsMetadata": "Metadata",
|
||||
"@settingsMetadata": {
|
||||
"description": "Settings menu item - metadata settings"
|
||||
},
|
||||
"settingsMetadataSubtitle": "Cover art, tags, ReplayGain, providers",
|
||||
"@settingsMetadataSubtitle": {
|
||||
"description": "Subtitle for metadata settings"
|
||||
},
|
||||
"settingsLyrics": "Lyrics",
|
||||
"@settingsLyrics": {
|
||||
"description": "Settings menu item - lyrics settings"
|
||||
},
|
||||
"settingsLyricsSubtitle": "Embed, mode, providers, language options",
|
||||
"@settingsLyricsSubtitle": {
|
||||
"description": "Subtitle for lyrics settings"
|
||||
},
|
||||
"settingsApp": "App",
|
||||
"@settingsApp": {
|
||||
"description": "Settings menu item - app settings"
|
||||
},
|
||||
"settingsAppSubtitle": "Updates, data, extension repo, debug",
|
||||
"@settingsAppSubtitle": {
|
||||
"description": "Subtitle for app settings"
|
||||
},
|
||||
"sectionMetadataProviders": "Providers",
|
||||
"@sectionMetadataProviders": {
|
||||
"description": "Settings section header for metadata providers"
|
||||
},
|
||||
"sectionDuplicates": "Duplicates",
|
||||
"@sectionDuplicates": {
|
||||
"description": "Settings section header for deduplication"
|
||||
},
|
||||
"sectionLyricsProviderOptions": "Provider Options",
|
||||
"@sectionLyricsProviderOptions": {
|
||||
"description": "Settings section header for per-provider lyrics options"
|
||||
},
|
||||
"metadataProvidersTitle": "Metadata Provider Priority",
|
||||
"@metadataProvidersTitle": {
|
||||
"description": "Settings item title for metadata provider order"
|
||||
},
|
||||
"metadataProvidersSubtitle": "Drag to set search and metadata source order",
|
||||
"@metadataProvidersSubtitle": {
|
||||
"description": "Subtitle for metadata provider priority item"
|
||||
},
|
||||
"downloadDeduplication": "Skip Duplicate Downloads",
|
||||
"@downloadDeduplication": {
|
||||
"description": "Setting - skip tracks already in download history"
|
||||
},
|
||||
"downloadDeduplicationEnabled": "Already-downloaded tracks will be skipped",
|
||||
"@downloadDeduplicationEnabled": {
|
||||
"description": "Subtitle when deduplication is on"
|
||||
},
|
||||
"downloadDeduplicationDisabled": "All tracks will be downloaded regardless of history",
|
||||
"@downloadDeduplicationDisabled": {
|
||||
"description": "Subtitle when deduplication is off"
|
||||
},
|
||||
"downloadFallbackExtensions": "Fallback Extensions",
|
||||
"@downloadFallbackExtensions": {
|
||||
"description": "Settings item for configuring fallback extension providers"
|
||||
},
|
||||
"downloadFallbackExtensionsSubtitle": "Choose which extensions can be used as fallback",
|
||||
"@downloadFallbackExtensionsSubtitle": {
|
||||
"description": "Subtitle for fallback extensions item"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,372 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/providers/download_queue_provider.dart';
|
||||
import 'package:spotiflac_android/providers/settings_provider.dart';
|
||||
import 'package:spotiflac_android/utils/app_bar_layout.dart';
|
||||
import 'package:spotiflac_android/widgets/settings_group.dart';
|
||||
|
||||
class AppSettingsPage extends ConsumerWidget {
|
||||
const AppSettingsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final settings = ref.watch(settingsProvider);
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final topPadding = normalizedHeaderTopPadding(context);
|
||||
|
||||
return PopScope(
|
||||
canPop: true,
|
||||
child: Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
expandedHeight: 120 + topPadding,
|
||||
collapsedHeight: kToolbarHeight,
|
||||
floating: false,
|
||||
pinned: true,
|
||||
backgroundColor: colorScheme.surface,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
leading: IconButton(
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
flexibleSpace: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxHeight = 120 + topPadding;
|
||||
final minHeight = kToolbarHeight + topPadding;
|
||||
final expandRatio =
|
||||
((constraints.maxHeight - minHeight) /
|
||||
(maxHeight - minHeight))
|
||||
.clamp(0.0, 1.0);
|
||||
final leftPadding = 56 - (32 * expandRatio);
|
||||
return FlexibleSpaceBar(
|
||||
expandedTitleScale: 1.0,
|
||||
titlePadding: EdgeInsets.only(
|
||||
left: leftPadding,
|
||||
bottom: 16,
|
||||
),
|
||||
title: Text(
|
||||
context.l10n.settingsApp,
|
||||
style: TextStyle(
|
||||
fontSize: 20 + (8 * expandRatio),
|
||||
fontWeight: FontWeight.bold,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// ── Updates ────────────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(title: context.l10n.sectionApp),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.extension,
|
||||
title: context.l10n.optionsExtensionStore,
|
||||
subtitle: context.l10n.optionsExtensionStoreSubtitle,
|
||||
value: settings.showExtensionStore,
|
||||
onChanged: (v) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setShowExtensionStore(v),
|
||||
),
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.system_update,
|
||||
title: context.l10n.optionsCheckUpdates,
|
||||
subtitle: context.l10n.optionsCheckUpdatesSubtitle,
|
||||
value: settings.checkForUpdates,
|
||||
onChanged: (v) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setCheckForUpdates(v),
|
||||
showDivider: settings.checkForUpdates,
|
||||
),
|
||||
if (settings.checkForUpdates)
|
||||
_UpdateChannelSelector(
|
||||
currentChannel: settings.updateChannel,
|
||||
onChanged: (v) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setUpdateChannel(v),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ── Data ───────────────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(title: context.l10n.sectionData),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsItem(
|
||||
icon: Icons.cleaning_services_outlined,
|
||||
title: context.l10n.cleanupOrphanedDownloads,
|
||||
subtitle: context.l10n.cleanupOrphanedDownloadsSubtitle,
|
||||
onTap: () => _cleanupOrphanedDownloads(context, ref),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.delete_forever,
|
||||
title: context.l10n.optionsClearHistory,
|
||||
subtitle: context.l10n.optionsClearHistorySubtitle,
|
||||
onTap: () =>
|
||||
_showClearHistoryDialog(context, ref, colorScheme),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ── Debug ──────────────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(title: context.l10n.sectionDebug),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.bug_report,
|
||||
title: context.l10n.optionsDetailedLogging,
|
||||
subtitle: settings.enableLogging
|
||||
? context.l10n.optionsDetailedLoggingOn
|
||||
: context.l10n.optionsDetailedLoggingOff,
|
||||
value: settings.enableLogging,
|
||||
onChanged: (v) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setEnableLogging(v),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 32)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showClearHistoryDialog(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
ColorScheme colorScheme,
|
||||
) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(context.l10n.dialogClearHistoryTitle),
|
||||
content: Text(context.l10n.dialogClearHistoryMessage),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(context.l10n.dialogCancel),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ref.read(downloadHistoryProvider.notifier).clearHistory();
|
||||
Navigator.pop(context);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(context.l10n.snackbarHistoryCleared)),
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
context.l10n.dialogClear,
|
||||
style: TextStyle(color: colorScheme.error),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _cleanupOrphanedDownloads(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
) async {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AlertDialog(
|
||||
content: Row(
|
||||
children: [
|
||||
const CircularProgressIndicator(),
|
||||
const SizedBox(width: 16),
|
||||
Text(context.l10n.cleanupOrphanedDownloads),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
try {
|
||||
final removed = await ref
|
||||
.read(downloadHistoryProvider.notifier)
|
||||
.cleanupOrphanedDownloads();
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
removed > 0
|
||||
? context.l10n.cleanupOrphanedDownloadsResult(removed)
|
||||
: context.l10n.cleanupOrphanedDownloadsNone,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
Navigator.pop(context);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(context.l10n.snackbarError(e.toString()))),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _UpdateChannelSelector extends StatelessWidget {
|
||||
final String currentChannel;
|
||||
final ValueChanged<String> onChanged;
|
||||
const _UpdateChannelSelector({
|
||||
required this.currentChannel,
|
||||
required this.onChanged,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final unselectedColor = isDark
|
||||
? Color.alphaBlend(
|
||||
Colors.white.withValues(alpha: 0.05),
|
||||
colorScheme.surface,
|
||||
)
|
||||
: colorScheme.surfaceContainerHigh;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(20),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.new_releases,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
size: 24,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.l10n.optionsUpdateChannel,
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
currentChannel == 'preview'
|
||||
? context.l10n.optionsUpdateChannelPreview
|
||||
: context.l10n.optionsUpdateChannelStable,
|
||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
_ChannelChip(
|
||||
label: context.l10n.channelStable,
|
||||
isSelected: currentChannel == 'stable',
|
||||
onTap: () => onChanged('stable'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
_ChannelChip(
|
||||
label: context.l10n.channelPreview,
|
||||
isSelected: currentChannel == 'preview',
|
||||
onTap: () => onChanged('preview'),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.info_outline,
|
||||
size: 16,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
context.l10n.optionsUpdateChannelWarning,
|
||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ChannelChip extends StatelessWidget {
|
||||
final String label;
|
||||
final bool isSelected;
|
||||
final VoidCallback onTap;
|
||||
const _ChannelChip({
|
||||
required this.label,
|
||||
required this.isSelected,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
||||
final unselectedColor = isDark
|
||||
? Color.alphaBlend(
|
||||
Colors.white.withValues(alpha: 0.05),
|
||||
colorScheme.surface,
|
||||
)
|
||||
: colorScheme.surfaceContainerHigh;
|
||||
return Expanded(
|
||||
child: Material(
|
||||
color: isSelected ? colorScheme.primaryContainer : unselectedColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||
child: Center(
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
|
||||
color: isSelected
|
||||
? colorScheme.onPrimaryContainer
|
||||
: colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/providers/settings_provider.dart';
|
||||
import 'package:spotiflac_android/utils/app_bar_layout.dart';
|
||||
import 'package:spotiflac_android/screens/settings/lyrics_provider_priority_page.dart';
|
||||
import 'package:spotiflac_android/widgets/settings_group.dart';
|
||||
|
||||
class LyricsSettingsPage extends ConsumerWidget {
|
||||
const LyricsSettingsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final settings = ref.watch(settingsProvider);
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final topPadding = normalizedHeaderTopPadding(context);
|
||||
|
||||
return PopScope(
|
||||
canPop: true,
|
||||
child: Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
expandedHeight: 120 + topPadding,
|
||||
collapsedHeight: kToolbarHeight,
|
||||
floating: false,
|
||||
pinned: true,
|
||||
backgroundColor: colorScheme.surface,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
leading: IconButton(
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
flexibleSpace: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxHeight = 120 + topPadding;
|
||||
final minHeight = kToolbarHeight + topPadding;
|
||||
final expandRatio =
|
||||
((constraints.maxHeight - minHeight) /
|
||||
(maxHeight - minHeight))
|
||||
.clamp(0.0, 1.0);
|
||||
final leftPadding = 56 - (32 * expandRatio);
|
||||
return FlexibleSpaceBar(
|
||||
expandedTitleScale: 1.0,
|
||||
titlePadding: EdgeInsets.only(
|
||||
left: leftPadding,
|
||||
bottom: 16,
|
||||
),
|
||||
title: Text(
|
||||
context.l10n.settingsLyrics,
|
||||
style: TextStyle(
|
||||
fontSize: 20 + (8 * expandRatio),
|
||||
fontWeight: FontWeight.bold,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// ── Lyrics Embedding ───────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(title: context.l10n.sectionLyrics),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.subtitles_outlined,
|
||||
title: context.l10n.optionsEmbedLyrics,
|
||||
subtitle: settings.embedMetadata
|
||||
? context.l10n.optionsEmbedLyricsSubtitle
|
||||
: context.l10n.downloadEmbedLyricsDisabled,
|
||||
value: settings.embedLyrics,
|
||||
enabled: settings.embedMetadata,
|
||||
onChanged: (value) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setEmbedLyrics(value),
|
||||
showDivider:
|
||||
settings.embedMetadata && settings.embedLyrics,
|
||||
),
|
||||
if (settings.embedMetadata && settings.embedLyrics) ...[
|
||||
SettingsItem(
|
||||
icon: Icons.lyrics_outlined,
|
||||
title: context.l10n.lyricsMode,
|
||||
subtitle: _getLyricsModeLabel(
|
||||
context,
|
||||
settings.lyricsMode,
|
||||
),
|
||||
onTap: () =>
|
||||
_showLyricsModePicker(context, ref, settings.lyricsMode),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.source_outlined,
|
||||
title: context.l10n.lyricsProvidersTitle,
|
||||
subtitle: _getLyricsProvidersSubtitle(
|
||||
context,
|
||||
settings.lyricsProviders,
|
||||
),
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const LyricsProviderPriorityPage(),
|
||||
),
|
||||
),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ── Provider Options ───────────────────────────────────────
|
||||
if (settings.embedMetadata && settings.embedLyrics) ...[
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(
|
||||
title: context.l10n.sectionLyricsProviderOptions,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.translate_outlined,
|
||||
title: context.l10n.downloadNeteaseIncludeTranslation,
|
||||
subtitle: settings.lyricsIncludeTranslationNetease
|
||||
? context.l10n.downloadNeteaseIncludeTranslationEnabled
|
||||
: context.l10n.downloadNeteaseIncludeTranslationDisabled,
|
||||
value: settings.lyricsIncludeTranslationNetease,
|
||||
onChanged: (value) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setLyricsIncludeTranslationNetease(value),
|
||||
),
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.text_fields_outlined,
|
||||
title: context.l10n.downloadNeteaseIncludeRomanization,
|
||||
subtitle: settings.lyricsIncludeRomanizationNetease
|
||||
? context
|
||||
.l10n
|
||||
.downloadNeteaseIncludeRomanizationEnabled
|
||||
: context
|
||||
.l10n
|
||||
.downloadNeteaseIncludeRomanizationDisabled,
|
||||
value: settings.lyricsIncludeRomanizationNetease,
|
||||
onChanged: (value) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setLyricsIncludeRomanizationNetease(value),
|
||||
),
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.record_voice_over_outlined,
|
||||
title: context.l10n.downloadAppleQqMultiPerson,
|
||||
subtitle: settings.lyricsMultiPersonWordByWord
|
||||
? context.l10n.downloadAppleQqMultiPersonEnabled
|
||||
: context.l10n.downloadAppleQqMultiPersonDisabled,
|
||||
value: settings.lyricsMultiPersonWordByWord,
|
||||
onChanged: (value) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setLyricsMultiPersonWordByWord(value),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.language_outlined,
|
||||
title: context.l10n.downloadMusixmatchLanguage,
|
||||
subtitle: settings.musixmatchLanguage.isEmpty
|
||||
? context.l10n.downloadMusixmatchLanguageAuto
|
||||
: settings.musixmatchLanguage.toUpperCase(),
|
||||
onTap: () => _showMusixmatchLanguagePicker(
|
||||
context,
|
||||
ref,
|
||||
settings.musixmatchLanguage,
|
||||
),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 32)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _getLyricsModeLabel(BuildContext context, String mode) {
|
||||
switch (mode) {
|
||||
case 'external':
|
||||
return context.l10n.lyricsModeExternal;
|
||||
case 'both':
|
||||
return context.l10n.lyricsModeBoth;
|
||||
default:
|
||||
return context.l10n.lyricsModeEmbed;
|
||||
}
|
||||
}
|
||||
|
||||
static const _providerDisplayNames = <String, String>{
|
||||
'lrclib': 'LRCLIB',
|
||||
'netease': 'Netease',
|
||||
'musixmatch': 'Musixmatch',
|
||||
'apple_music': 'Apple Music',
|
||||
'qqmusic': 'QQ Music',
|
||||
};
|
||||
|
||||
String _getLyricsProvidersSubtitle(
|
||||
BuildContext context,
|
||||
List<String> providers,
|
||||
) {
|
||||
if (providers.isEmpty) return context.l10n.downloadProvidersNoneEnabled;
|
||||
return providers
|
||||
.map((p) => _providerDisplayNames[p] ?? p)
|
||||
.join(' > ');
|
||||
}
|
||||
|
||||
void _showLyricsModePicker(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
String current,
|
||||
) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28)),
|
||||
),
|
||||
builder: (context) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 8),
|
||||
child: Text(
|
||||
context.l10n.lyricsMode,
|
||||
style: Theme.of(context).textTheme.titleLarge
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 16),
|
||||
child: Text(
|
||||
context.l10n.lyricsModeDescription,
|
||||
style: Theme.of(context).textTheme.bodyMedium
|
||||
?.copyWith(color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.audiotrack),
|
||||
title: Text(context.l10n.lyricsModeEmbed),
|
||||
subtitle: Text(context.l10n.lyricsModeEmbedSubtitle),
|
||||
trailing: current == 'embed' ? const Icon(Icons.check) : null,
|
||||
onTap: () {
|
||||
ref.read(settingsProvider.notifier).setLyricsMode('embed');
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.insert_drive_file_outlined),
|
||||
title: Text(context.l10n.lyricsModeExternal),
|
||||
subtitle: Text(context.l10n.lyricsModeExternalSubtitle),
|
||||
trailing: current == 'external' ? const Icon(Icons.check) : null,
|
||||
onTap: () {
|
||||
ref.read(settingsProvider.notifier).setLyricsMode('external');
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.library_music_outlined),
|
||||
title: Text(context.l10n.lyricsModeBoth),
|
||||
subtitle: Text(context.l10n.lyricsModeBothSubtitle),
|
||||
trailing: current == 'both' ? const Icon(Icons.check) : null,
|
||||
onTap: () {
|
||||
ref.read(settingsProvider.notifier).setLyricsMode('both');
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showMusixmatchLanguagePicker(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
String currentLanguage,
|
||||
) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final controller = TextEditingController(text: currentLanguage);
|
||||
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28)),
|
||||
),
|
||||
isScrollControlled: true,
|
||||
builder: (context) => Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 24,
|
||||
right: 24,
|
||||
top: 24,
|
||||
bottom: 24 + MediaQuery.of(context).viewInsets.bottom,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.l10n.downloadMusixmatchLanguage,
|
||||
style: Theme.of(context).textTheme.titleLarge
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
context.l10n.downloadMusixmatchLanguageDesc,
|
||||
style: Theme.of(context).textTheme.bodyMedium
|
||||
?.copyWith(color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextField(
|
||||
controller: controller,
|
||||
textInputAction: TextInputAction.done,
|
||||
decoration: InputDecoration(
|
||||
labelText: context.l10n.downloadMusixmatchLanguageCode,
|
||||
hintText: context.l10n.downloadMusixmatchLanguageHint,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(context.l10n.dialogCancel),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setMusixmatchLanguage('');
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(context.l10n.downloadMusixmatchAuto),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
FilledButton(
|
||||
onPressed: () {
|
||||
final normalized = controller.text
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replaceAll(RegExp(r'[^a-z0-9\-_]'), '');
|
||||
ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setMusixmatchLanguage(normalized);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
child: Text(context.l10n.dialogSave),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/providers/settings_provider.dart';
|
||||
import 'package:spotiflac_android/utils/app_bar_layout.dart';
|
||||
import 'package:spotiflac_android/utils/artist_utils.dart';
|
||||
import 'package:spotiflac_android/screens/settings/metadata_provider_priority_page.dart';
|
||||
import 'package:spotiflac_android/widgets/settings_group.dart';
|
||||
|
||||
class MetadataSettingsPage extends ConsumerWidget {
|
||||
const MetadataSettingsPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final settings = ref.watch(settingsProvider);
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
final topPadding = normalizedHeaderTopPadding(context);
|
||||
|
||||
return PopScope(
|
||||
canPop: true,
|
||||
child: Scaffold(
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
SliverAppBar(
|
||||
expandedHeight: 120 + topPadding,
|
||||
collapsedHeight: kToolbarHeight,
|
||||
floating: false,
|
||||
pinned: true,
|
||||
backgroundColor: colorScheme.surface,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
leading: IconButton(
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
flexibleSpace: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final maxHeight = 120 + topPadding;
|
||||
final minHeight = kToolbarHeight + topPadding;
|
||||
final expandRatio =
|
||||
((constraints.maxHeight - minHeight) /
|
||||
(maxHeight - minHeight))
|
||||
.clamp(0.0, 1.0);
|
||||
final leftPadding = 56 - (32 * expandRatio);
|
||||
return FlexibleSpaceBar(
|
||||
expandedTitleScale: 1.0,
|
||||
titlePadding: EdgeInsets.only(
|
||||
left: leftPadding,
|
||||
bottom: 16,
|
||||
),
|
||||
title: Text(
|
||||
context.l10n.settingsMetadata,
|
||||
style: TextStyle(
|
||||
fontSize: 20 + (8 * expandRatio),
|
||||
fontWeight: FontWeight.bold,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// ── Embedding ──────────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(title: context.l10n.sectionDownload),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.sell_outlined,
|
||||
title: 'Embed Metadata',
|
||||
subtitle: settings.embedMetadata
|
||||
? 'Write metadata, cover art, and lyrics to files'
|
||||
: 'Disabled (advanced): skip all metadata embedding',
|
||||
value: settings.embedMetadata,
|
||||
onChanged: (v) =>
|
||||
ref.read(settingsProvider.notifier).setEmbedMetadata(v),
|
||||
showDivider: settings.embedMetadata,
|
||||
),
|
||||
if (settings.embedMetadata) ...[
|
||||
SettingsItem(
|
||||
icon: Icons.people_alt_outlined,
|
||||
title: context.l10n.optionsArtistTagMode,
|
||||
subtitle: _getArtistTagModeLabel(
|
||||
context,
|
||||
settings.artistTagMode,
|
||||
),
|
||||
onTap: () =>
|
||||
_showArtistTagModePicker(context, ref, settings.artistTagMode),
|
||||
),
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.image,
|
||||
title: context.l10n.optionsMaxQualityCover,
|
||||
subtitle: context.l10n.optionsMaxQualityCoverSubtitle,
|
||||
value: settings.maxQualityCover,
|
||||
onChanged: (v) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setMaxQualityCover(v),
|
||||
),
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.graphic_eq,
|
||||
title: context.l10n.optionsReplayGain,
|
||||
subtitle: settings.embedReplayGain
|
||||
? context.l10n.optionsReplayGainSubtitleOn
|
||||
: context.l10n.optionsReplayGainSubtitleOff,
|
||||
value: settings.embedReplayGain,
|
||||
onChanged: (v) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setEmbedReplayGain(v),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ── Providers ─────────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(
|
||||
title: context.l10n.sectionMetadataProviders,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsItem(
|
||||
icon: Icons.source_outlined,
|
||||
title: context.l10n.metadataProvidersTitle,
|
||||
subtitle: context.l10n.metadataProvidersSubtitle,
|
||||
onTap: () => Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const MetadataProviderPriorityPage(),
|
||||
),
|
||||
),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// ── Deduplication ──────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsSectionHeader(
|
||||
title: context.l10n.sectionDuplicates,
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SettingsGroup(
|
||||
children: [
|
||||
SettingsSwitchItem(
|
||||
icon: Icons.filter_list_outlined,
|
||||
title: context.l10n.downloadDeduplication,
|
||||
subtitle: settings.deduplicateDownloads
|
||||
? context.l10n.downloadDeduplicationEnabled
|
||||
: context.l10n.downloadDeduplicationDisabled,
|
||||
value: settings.deduplicateDownloads,
|
||||
onChanged: (value) => ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setDeduplicateDownloads(value),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SliverToBoxAdapter(child: SizedBox(height: 32)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String _getArtistTagModeLabel(BuildContext context, String mode) {
|
||||
switch (mode) {
|
||||
case artistTagModeSplitVorbis:
|
||||
return context.l10n.optionsArtistTagModeSplitVorbis;
|
||||
default:
|
||||
return context.l10n.optionsArtistTagModeJoined;
|
||||
}
|
||||
}
|
||||
|
||||
void _showArtistTagModePicker(
|
||||
BuildContext context,
|
||||
WidgetRef ref,
|
||||
String currentMode,
|
||||
) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(28)),
|
||||
),
|
||||
builder: (context) => SafeArea(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 8),
|
||||
child: Text(
|
||||
context.l10n.optionsArtistTagMode,
|
||||
style: Theme.of(context).textTheme.titleLarge
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 16),
|
||||
child: Text(
|
||||
context.l10n.optionsArtistTagModeDescription,
|
||||
style: Theme.of(context).textTheme.bodyMedium
|
||||
?.copyWith(color: colorScheme.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.segment_outlined),
|
||||
title: Text(context.l10n.optionsArtistTagModeJoined),
|
||||
subtitle: Text(context.l10n.optionsArtistTagModeJoinedSubtitle),
|
||||
trailing: currentMode == artistTagModeJoined
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setArtistTagMode(artistTagModeJoined);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.library_music_outlined),
|
||||
title: Text(context.l10n.optionsArtistTagModeSplitVorbis),
|
||||
subtitle: Text(context.l10n.optionsArtistTagModeSplitVorbisSubtitle),
|
||||
trailing: currentMode == artistTagModeSplitVorbis
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onTap: () {
|
||||
ref
|
||||
.read(settingsProvider.notifier)
|
||||
.setArtistTagMode(artistTagModeSplitVorbis);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,12 @@ import 'package:spotiflac_android/constants/app_info.dart';
|
||||
import 'package:spotiflac_android/l10n/l10n.dart';
|
||||
import 'package:spotiflac_android/screens/settings/appearance_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/download_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/files_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/lyrics_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/metadata_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/extensions_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/library_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/options_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/app_settings_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/about_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/cache_management_page.dart';
|
||||
import 'package:spotiflac_android/screens/settings/donate_page.dart';
|
||||
@@ -48,7 +51,7 @@ class SettingsTab extends ConsumerWidget {
|
||||
title: Text(
|
||||
context.l10n.settingsTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 20 + (14 * expandRatio), // 20 -> 34
|
||||
fontSize: 20 + (14 * expandRatio),
|
||||
fontWeight: FontWeight.bold,
|
||||
color: colorScheme.onSurface,
|
||||
),
|
||||
@@ -58,6 +61,7 @@ class SettingsTab extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
|
||||
// ── Group 1: Appearance & Content ──────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
@@ -72,6 +76,34 @@ class SettingsTab extends ConsumerWidget {
|
||||
onTap: () =>
|
||||
_navigateTo(context, const AppearanceSettingsPage()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.library_music_outlined,
|
||||
title: l10n.settingsLocalLibrary,
|
||||
subtitle: l10n.settingsLocalLibrarySubtitle,
|
||||
onTap: () =>
|
||||
_navigateTo(context, const LibrarySettingsPage()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.extension_outlined,
|
||||
title: l10n.settingsExtensions,
|
||||
subtitle: l10n.settingsExtensionsSubtitle,
|
||||
onTap: () => _navigateTo(context, const ExtensionsPage()),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// ── Group 2: Download ──────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final l10n = context.l10n;
|
||||
return SettingsGroup(
|
||||
margin: const EdgeInsets.fromLTRB(16, 4, 16, 4),
|
||||
children: [
|
||||
SettingsItem(
|
||||
icon: Icons.download_outlined,
|
||||
title: l10n.settingsDownload,
|
||||
@@ -80,12 +112,41 @@ class SettingsTab extends ConsumerWidget {
|
||||
_navigateTo(context, const DownloadSettingsPage()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.library_music_outlined,
|
||||
title: l10n.settingsLocalLibrary,
|
||||
subtitle: l10n.settingsLocalLibrarySubtitle,
|
||||
icon: Icons.folder_outlined,
|
||||
title: l10n.settingsFiles,
|
||||
subtitle: l10n.settingsFilesSubtitle,
|
||||
onTap: () =>
|
||||
_navigateTo(context, const LibrarySettingsPage()),
|
||||
_navigateTo(context, const FilesSettingsPage()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.sell_outlined,
|
||||
title: l10n.settingsMetadata,
|
||||
subtitle: l10n.settingsMetadataSubtitle,
|
||||
onTap: () =>
|
||||
_navigateTo(context, const MetadataSettingsPage()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.lyrics_outlined,
|
||||
title: l10n.settingsLyrics,
|
||||
subtitle: l10n.settingsLyricsSubtitle,
|
||||
onTap: () =>
|
||||
_navigateTo(context, const LyricsSettingsPage()),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
// ── Group 3: App ───────────────────────────────────────────────
|
||||
SliverToBoxAdapter(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final l10n = context.l10n;
|
||||
return SettingsGroup(
|
||||
margin: const EdgeInsets.fromLTRB(16, 4, 16, 4),
|
||||
children: [
|
||||
SettingsItem(
|
||||
icon: Icons.storage_outlined,
|
||||
title: l10n.settingsCache,
|
||||
@@ -95,41 +156,22 @@ class SettingsTab extends ConsumerWidget {
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.tune_outlined,
|
||||
title: l10n.settingsOptions,
|
||||
subtitle: l10n.settingsOptionsSubtitle,
|
||||
title: l10n.settingsApp,
|
||||
subtitle: l10n.settingsAppSubtitle,
|
||||
onTap: () =>
|
||||
_navigateTo(context, const OptionsSettingsPage()),
|
||||
_navigateTo(context, const AppSettingsPage()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.extension_outlined,
|
||||
title: l10n.settingsExtensions,
|
||||
subtitle: l10n.settingsExtensionsSubtitle,
|
||||
onTap: () => _navigateTo(context, const ExtensionsPage()),
|
||||
icon: Icons.article_outlined,
|
||||
title: l10n.logTitle,
|
||||
subtitle: l10n.settingsLogsSubtitle,
|
||||
onTap: () => _navigateTo(context, const LogScreen()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.favorite_outline,
|
||||
title: l10n.settingsDonate,
|
||||
subtitle: l10n.settingsDonateSubtitle,
|
||||
onTap: () => _navigateTo(context, const DonatePage()),
|
||||
showDivider: false,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
SliverToBoxAdapter(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final l10n = context.l10n;
|
||||
return SettingsGroup(
|
||||
children: [
|
||||
SettingsItem(
|
||||
icon: Icons.article_outlined,
|
||||
title: l10n.logTitle,
|
||||
subtitle: l10n.settingsLogsSubtitle,
|
||||
onTap: () => _navigateTo(context, const LogScreen()),
|
||||
),
|
||||
SettingsItem(
|
||||
icon: Icons.info_outline,
|
||||
|
||||
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 71 KiB |