Merge pull request #345 from Amonoman/main

Refactor settings into dedicated pages and update icons
This commit is contained in:
Zarz Eleutherius
2026-05-02 23:14:41 +07:00
committed by GitHub
57 changed files with 12298 additions and 2813 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 429 B

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 624 B

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 905 B

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

+91 -19
View File
@@ -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"
}
}
+165 -124
View File
@@ -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"
}
}
}
File diff suppressed because it is too large Load Diff
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
File diff suppressed because it is too large Load Diff
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
File diff suppressed because it is too large Load Diff
+72
View File
@@ -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"
}
}
+72
View File
@@ -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"
}
}
+372
View File
@@ -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,
),
),
),
),
),
),
);
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -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),
],
),
),
);
}
}
File diff suppressed because it is too large Load Diff
+74 -32
View File
@@ -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,
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 71 KiB