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": { "@appearanceDynamicColor": {
"description": "Material You dynamic colors" "description": "Material You dynamic colors"
}, },
"appearanceDynamicColorSubtitle": "Farben von Ihrem Hintergrundbild verwenden", "appearanceDynamicColorSubtitle": "Farben deines Hintergrundbilds verwenden",
"@appearanceDynamicColorSubtitle": { "@appearanceDynamicColorSubtitle": {
"description": "Subtitle for dynamic color" "description": "Subtitle for dynamic color"
}, },
@@ -178,7 +178,7 @@
"@optionsAutoFallbackSubtitle": { "@optionsAutoFallbackSubtitle": {
"description": "Subtitle for auto fallback" "description": "Subtitle for auto fallback"
}, },
"optionsUseExtensionProviders": "Erweiterungs-Anbieter verwenden", "optionsUseExtensionProviders": "Erweiterungsanbieter verwenden",
"@optionsUseExtensionProviders": { "@optionsUseExtensionProviders": {
"description": "Enable extension download providers" "description": "Enable extension download providers"
}, },
@@ -194,7 +194,7 @@
"@optionsEmbedLyrics": { "@optionsEmbedLyrics": {
"description": "Embed lyrics in audio files" "description": "Embed lyrics in audio files"
}, },
"optionsEmbedLyricsSubtitle": "Synchronisierte Lyrics in FLAC-Dateien einbetten", "optionsEmbedLyricsSubtitle": "Synchronisierte Songtexte neben heruntergeladenen Titeln speichern",
"@optionsEmbedLyricsSubtitle": { "@optionsEmbedLyricsSubtitle": {
"description": "Subtitle for embed lyrics" "description": "Subtitle for embed lyrics"
}, },
@@ -230,7 +230,7 @@
"@optionsArtistTagModeJoined": { "@optionsArtistTagModeJoined": {
"description": "Artist tag mode option that joins multiple artists into one value" "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": { "@optionsArtistTagModeJoinedSubtitle": {
"description": "Subtitle for joined artist tag mode" "description": "Subtitle for joined artist tag mode"
}, },
@@ -438,7 +438,7 @@
"@aboutReportIssue": { "@aboutReportIssue": {
"description": "Link to report bugs" "description": "Link to report bugs"
}, },
"aboutReportIssueSubtitle": "Melde jedes Problem, die dir auftreten", "aboutReportIssueSubtitle": "Melde Probleme, die dir auffallen",
"@aboutReportIssueSubtitle": { "@aboutReportIssueSubtitle": {
"description": "Subtitle for report issue" "description": "Subtitle for report issue"
}, },
@@ -486,7 +486,7 @@
"@aboutSachinsenalDesc": { "@aboutSachinsenalDesc": {
"description": "Credit description for sachinsenal0x64" "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": { "@aboutSjdonadoDesc": {
"description": "Credit description for sjdonado" "description": "Credit description for sjdonado"
}, },
@@ -576,7 +576,7 @@
"@setupPermissionDeniedMessage": { "@setupPermissionDeniedMessage": {
"description": "Error when permission denied" "description": "Error when permission denied"
}, },
"setupPermissionRequired": "{permissionType} Zugriff verweigert", "setupPermissionRequired": "{permissionType}-Berechtigung erforderlich",
"@setupPermissionRequired": { "@setupPermissionRequired": {
"description": "Generic permission required title", "description": "Generic permission required title",
"placeholders": { "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": { "@setupPermissionRequiredMessage": {
"description": "Generic permission required message", "description": "Generic permission required message",
"placeholders": { "placeholders": {
@@ -603,7 +603,7 @@
"@setupNoFolderSelected": { "@setupNoFolderSelected": {
"description": "Prompt when no folder selected" "description": "Prompt when no folder selected"
}, },
"setupUseDefault": "Standart benutzen", "setupUseDefault": "Standard verwenden",
"@setupUseDefault": { "@setupUseDefault": {
"description": "Button to use default folder" "description": "Button to use default folder"
}, },
@@ -663,7 +663,7 @@
"@setupNotificationEnable": { "@setupNotificationEnable": {
"description": "Button to enable notifications" "description": "Button to enable notifications"
}, },
"setupFolderChoose": "Speicherort auwählen", "setupFolderChoose": "Speicherort auswählen",
"@setupFolderChoose": { "@setupFolderChoose": {
"description": "Button to choose folder" "description": "Button to choose folder"
}, },
@@ -747,7 +747,7 @@
"@dialogDiscardChanges": { "@dialogDiscardChanges": {
"description": "Dialog title - unsaved changes warning" "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": { "@dialogUnsavedChanges": {
"description": "Dialog message - unsaved changes" "description": "Dialog message - unsaved changes"
}, },
@@ -759,7 +759,7 @@
"@dialogRemoveExtension": { "@dialogRemoveExtension": {
"description": "Dialog title - uninstall extension" "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": { "@dialogRemoveExtensionMessage": {
"description": "Dialog message - uninstall confirmation" "description": "Dialog message - uninstall confirmation"
}, },
@@ -767,7 +767,7 @@
"@dialogUninstallExtension": { "@dialogUninstallExtension": {
"description": "Dialog title - uninstall extension" "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": { "@dialogUninstallExtensionMessage": {
"description": "Dialog message - uninstall specific extension", "description": "Dialog message - uninstall specific extension",
"placeholders": { "placeholders": {
@@ -780,7 +780,7 @@
"@dialogClearHistoryTitle": { "@dialogClearHistoryTitle": {
"description": "Dialog title - clear download history" "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": { "@dialogClearHistoryMessage": {
"description": "Dialog message - clear history confirmation" "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": { "@snackbarAlreadyInLibrary": {
"description": "Snackbar - track already exists in local library", "description": "Snackbar - track already exists in local library",
"placeholders": { "placeholders": {
@@ -867,7 +867,7 @@
"@snackbarCredentialsCleared": { "@snackbarCredentialsCleared": {
"description": "Snackbar - Spotify credentials removed" "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": { "@snackbarDeletedTracks": {
"description": "Snackbar - tracks deleted", "description": "Snackbar - tracks deleted",
"placeholders": { "placeholders": {
@@ -969,7 +969,7 @@
"@errorUrlFetchFailed": { "@errorUrlFetchFailed": {
"description": "Error message - generic URL fetch failure" "description": "Error message - generic URL fetch failure"
}, },
"errorMissingExtensionSource": "Kann {item} nicht lade wegen fehlender Erweiterungsquelle", "errorMissingExtensionSource": "Kann {item} nicht laden wegen fehlender Erweiterungsquelle",
"@errorMissingExtensionSource": { "@errorMissingExtensionSource": {
"description": "Error - extension source not available", "description": "Error - extension source not available",
"placeholders": { "placeholders": {
@@ -1287,7 +1287,7 @@
"@logClearLogsTitle": { "@logClearLogsTitle": {
"description": "Clear logs dialog title" "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": { "@logClearLogsMessage": {
"description": "Clear logs confirmation message" "description": "Clear logs confirmation message"
}, },
@@ -2462,7 +2462,7 @@
"@libraryClearConfirmTitle": { "@libraryClearConfirmTitle": {
"description": "Dialog title for clear confirmation" "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": { "@libraryClearConfirmMessage": {
"description": "Dialog message for clear confirmation" "description": "Dialog message for clear confirmation"
}, },
@@ -4509,5 +4509,77 @@
"notifUpdateFailedBody": "Could not download update. Try again later.", "notifUpdateFailedBody": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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", "@@locale": "en",
"@@last_modified": "2026-01-16", "@@last_modified": "2026-04-28",
"appName": "SpotiFLAC", "appName": "SpotiFLAC",
"@appName": { "@appName": {
"description": "App name - DO NOT TRANSLATE" "description": "App name - DO NOT TRANSLATE"
@@ -99,7 +99,7 @@
}, },
"downloadFolderOrganization": "Folder Organization", "downloadFolderOrganization": "Folder Organization",
"@downloadFolderOrganization": { "@downloadFolderOrganization": {
"description": "Setting for folder structure" "description": "Title of the folder organization picker bottom sheet"
}, },
"appearanceTitle": "Appearance", "appearanceTitle": "Appearance",
"@appearanceTitle": { "@appearanceTitle": {
@@ -145,7 +145,7 @@
"@optionsPrimaryProvider": { "@optionsPrimaryProvider": {
"description": "Main search provider setting" "description": "Main search provider setting"
}, },
"optionsPrimaryProviderSubtitle": "Service used when searching by track name.", "optionsPrimaryProviderSubtitle": "Service used for searching by track or album name",
"@optionsPrimaryProviderSubtitle": { "@optionsPrimaryProviderSubtitle": {
"description": "Subtitle for primary provider" "description": "Subtitle for primary provider"
}, },
@@ -194,7 +194,7 @@
"@optionsEmbedLyrics": { "@optionsEmbedLyrics": {
"description": "Embed lyrics in audio files" "description": "Embed lyrics in audio files"
}, },
"optionsEmbedLyricsSubtitle": "Embed synced lyrics into FLAC files", "optionsEmbedLyricsSubtitle": "Save synced lyrics alongside your downloaded tracks",
"@optionsEmbedLyricsSubtitle": { "@optionsEmbedLyricsSubtitle": {
"description": "Subtitle for embed lyrics" "description": "Subtitle for embed lyrics"
}, },
@@ -729,7 +729,7 @@
}, },
"dialogDownload": "Download", "dialogDownload": "Download",
"@dialogDownload": { "@dialogDownload": {
"description": "Dialog button - download action" "description": "Confirm button in Download All dialog"
}, },
"dialogDiscard": "Discard", "dialogDiscard": "Discard",
"@dialogDiscard": { "@dialogDiscard": {
@@ -1449,11 +1449,11 @@
"@settingsAppearanceSubtitle": { "@settingsAppearanceSubtitle": {
"description": "Appearance settings description" "description": "Appearance settings description"
}, },
"settingsDownloadSubtitle": "Service, quality, filename format", "settingsDownloadSubtitle": "Service, quality, fallback",
"@settingsDownloadSubtitle": { "@settingsDownloadSubtitle": {
"description": "Download settings description" "description": "Download settings description"
}, },
"settingsOptionsSubtitle": "Fallback, lyrics, cover art, updates", "settingsOptionsSubtitle": "Fallback, metadata, lyrics, cover art",
"@settingsOptionsSubtitle": { "@settingsOptionsSubtitle": {
"description": "Options settings description" "description": "Options settings description"
}, },
@@ -3592,18 +3592,17 @@
} }
} }
}, },
"downloadUseAlbumArtistForFoldersAlbumSubtitle": "Artist folders use Album Artist when available", "downloadUseAlbumArtistForFoldersAlbumSubtitle": "Folder named after Album Artist tag",
"@downloadUseAlbumArtistForFoldersAlbumSubtitle": { "@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": { "@downloadUseAlbumArtistForFoldersTrackSubtitle": {
"description": "Subtitle when Track Artist is used for folder naming" "description": "Subtitle when track artist is used for folder names"
}, },
"lyricsProvidersTitle": "Lyrics Provider Priority",
"lyricsProvidersTitle": "Lyrics Providers",
"@lyricsProvidersTitle": { "@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": "Enable, disable and reorder lyrics sources. Providers are tried top-to-bottom until lyrics are found.",
"@lyricsProvidersDescription": { "@lyricsProvidersDescription": {
@@ -3667,7 +3666,6 @@
"@lyricsProviderExtensionDesc": { "@lyricsProviderExtensionDesc": {
"description": "Generic description for extension-based lyrics providers" "description": "Generic description for extension-based lyrics providers"
}, },
"safMigrationTitle": "Storage Update Required", "safMigrationTitle": "Storage Update Required",
"@safMigrationTitle": { "@safMigrationTitle": {
"description": "Title of SAF migration dialog" "description": "Title of SAF migration dialog"
@@ -3684,16 +3682,14 @@
"@safMigrationSuccess": { "@safMigrationSuccess": {
"description": "Snackbar after successfully migrating to SAF" "description": "Snackbar after successfully migrating to SAF"
}, },
"settingsDonate": "Support Development",
"settingsDonate": "Donate",
"@settingsDonate": { "@settingsDonate": {
"description": "Settings menu item - donate" "description": "Settings menu item - donate page"
}, },
"settingsDonateSubtitle": "Support SpotiFLAC-Mobile development", "settingsDonateSubtitle": "Buy the developer a coffee",
"@settingsDonateSubtitle": { "@settingsDonateSubtitle": {
"description": "Subtitle for donate menu item" "description": "Subtitle for donate menu item"
}, },
"tooltipLoveAll": "Love All", "tooltipLoveAll": "Love All",
"@tooltipLoveAll": { "@tooltipLoveAll": {
"description": "Tooltip for the Love All button on album/playlist screens" "description": "Tooltip for the Love All button on album/playlist screens"
@@ -3720,10 +3716,9 @@
} }
} }
}, },
"dialogDownloadAllTitle": "Download All", "dialogDownloadAllTitle": "Download All",
"@dialogDownloadAllTitle": { "@dialogDownloadAllTitle": {
"description": "Title of the Download All confirmation dialog" "description": "Dialog title for bulk download confirmation"
}, },
"dialogDownloadAllMessage": "Download {count} tracks?", "dialogDownloadAllMessage": "Download {count} tracks?",
"@dialogDownloadAllMessage": { "@dialogDownloadAllMessage": {
@@ -3734,11 +3729,6 @@
} }
} }
}, },
"dialogDownload": "Download",
"@dialogDownload": {
"description": "Confirm button in Download All dialog"
},
"homeSkipAlreadyDownloaded": "Skip already downloaded songs", "homeSkipAlreadyDownloaded": "Skip already downloaded songs",
"@homeSkipAlreadyDownloaded": { "@homeSkipAlreadyDownloaded": {
"description": "Checkbox label in import dialog to skip already-downloaded songs" "description": "Checkbox label in import dialog to skip already-downloaded songs"
@@ -3751,7 +3741,6 @@
"@homeAlbumInfoUnavailable": { "@homeAlbumInfoUnavailable": {
"description": "Snackbar when album info cannot be loaded" "description": "Snackbar when album info cannot be loaded"
}, },
"snackbarLoadingCueSheet": "Loading CUE sheet...", "snackbarLoadingCueSheet": "Loading CUE sheet...",
"@snackbarLoadingCueSheet": { "@snackbarLoadingCueSheet": {
"description": "Snackbar while loading a CUE sheet file" "description": "Snackbar while loading a CUE sheet file"
@@ -3781,190 +3770,181 @@
"@snackbarNoActionDefined": { "@snackbarNoActionDefined": {
"description": "Snackbar when an extension button has no action configured" "description": "Snackbar when an extension button has no action configured"
}, },
"noTracksFoundForAlbum": "No tracks found for this album", "noTracksFoundForAlbum": "No tracks found for this album",
"@noTracksFoundForAlbum": { "@noTracksFoundForAlbum": {
"description": "Empty state message when an album has no tracks" "description": "Empty state message when an album has no tracks"
}, },
"downloadLocationSubtitle": "Choose where to save your downloaded tracks",
"downloadLocationSubtitle": "Choose storage mode for downloaded files.",
"@downloadLocationSubtitle": { "@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": { "@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": { "@storageModeAppFolderSubtitle": {
"description": "Subtitle for app folder storage mode" "description": "Subtitle for app folder storage mode"
}, },
"storageModeSaf": "SAF folder", "storageModeSaf": "Custom Folder (SAF)",
"@storageModeSaf": { "@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": { "@storageModeSafSubtitle": {
"description": "Subtitle for SAF storage mode" "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": { "@downloadFilenameDescription": {
"description": "Description text in filename format bottom sheet" "description": "Description shown in filename format editor"
}, },
"downloadFilenameInsertTag": "Tap to insert tag:", "downloadFilenameInsertTag": "Tap to insert tag:",
"@downloadFilenameInsertTag": { "@downloadFilenameInsertTag": {
"description": "Label above filename tag chips" "description": "Label above filename tag chips"
}, },
"downloadSeparateSinglesEnabled": "Albums/ and Singles/ folders", "downloadSeparateSinglesEnabled": "Singles and EPs saved in a separate folder",
"@downloadSeparateSinglesEnabled": { "@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": { "@downloadSeparateSinglesDisabled": {
"description": "Subtitle when separate singles folder is disabled" "description": "Subtitle when separate singles folder is off"
}, },
"downloadArtistNameFilters": "Artist Name Filters", "downloadArtistNameFilters": "Artist Name Filters",
"@downloadArtistNameFilters": { "@downloadArtistNameFilters": {
"description": "Setting title for artist folder filter options" "description": "Setting title for artist folder filter options"
}, },
"downloadCreatePlaylistSourceFolder": "Create playlist source folder", "downloadCreatePlaylistSourceFolder": "Playlist Source Folder",
"@downloadCreatePlaylistSourceFolder": { "@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": { "@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": { "@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": { "@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": "SongLink Region",
"@downloadSongLinkRegion": { "@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": { "@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": { "@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": { "@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": { "@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 to choose audio quality",
"downloadSelectTidalQobuz": "Select Tidal or Qobuz above to configure quality",
"@downloadSelectTidalQobuz": { "@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": { "@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": "Netease: Include Translation",
"@downloadNeteaseIncludeTranslation": { "@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": { "@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": { "@downloadNeteaseIncludeTranslationDisabled": {
"description": "Subtitle when Netease translation is disabled" "description": "Subtitle when Netease translation is off"
}, },
"downloadNeteaseIncludeRomanization": "Netease: Include Romanization", "downloadNeteaseIncludeRomanization": "Netease: Include Romanization",
"@downloadNeteaseIncludeRomanization": { "@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": { "@downloadNeteaseIncludeRomanizationEnabled": {
"description": "Subtitle when Netease romanization is enabled" "description": "Subtitle when Netease romanization is on"
}, },
"downloadNeteaseIncludeRomanizationDisabled": "Disabled", "downloadNeteaseIncludeRomanizationDisabled": "No romanization",
"@downloadNeteaseIncludeRomanizationDisabled": { "@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": { "@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": { "@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": { "@downloadAppleQqMultiPersonDisabled": {
"description": "Subtitle when multi-person word-by-word is disabled" "description": "Subtitle when multi-person lyrics is off"
}, },
"downloadMusixmatchLanguage": "Musixmatch Language", "downloadMusixmatchLanguage": "Musixmatch Language",
"@downloadMusixmatchLanguage": { "@downloadMusixmatchLanguage": {
"description": "Setting title for Musixmatch language preference" "description": "Setting for Musixmatch lyrics translation language"
}, },
"downloadMusixmatchLanguageAuto": "Auto (original)", "downloadMusixmatchLanguageAuto": "Auto (original language)",
"@downloadMusixmatchLanguageAuto": { "@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": { "@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": { "@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": { "@downloadFilterContributingDisabled": {
"description": "Subtitle when contributing artist filter is disabled" "description": "Subtitle when contributing artist filter is off"
}, },
"downloadProvidersNoneEnabled": "No providers enabled",
"downloadProvidersNoneEnabled": "None enabled",
"@downloadProvidersNoneEnabled": { "@downloadProvidersNoneEnabled": {
"description": "Subtitle for lyrics providers setting when no providers are enabled" "description": "Shown when no lyrics providers are active"
}, },
"downloadMusixmatchLanguageCode": "Language code", "downloadMusixmatchLanguageCode": "Language code",
"@downloadMusixmatchLanguageCode": { "@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": { "@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": { "@downloadMusixmatchLanguageDesc": {
"description": "Description in the Musixmatch language picker" "description": "Description in Musixmatch language picker"
}, },
"downloadMusixmatchAuto": "Auto", "downloadMusixmatchAuto": "Auto",
"@downloadMusixmatchAuto": { "@downloadMusixmatchAuto": {
"description": "Button to reset Musixmatch language to automatic" "description": "Button to clear Musixmatch language (use auto)"
}, },
"downloadNetworkAnySubtitle": "Use WiFi or mobile data",
"downloadNetworkAnySubtitle": "WiFi + Mobile Data",
"@downloadNetworkAnySubtitle": { "@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": { "@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": { "@downloadSongLinkRegionDesc": {
"description": "Description in the SongLink region picker" "description": "Description in SongLink region picker"
},
"downloadFolderOrganization": "Folder Organization",
"@downloadFolderOrganization": {
"description": "Title of the folder organization picker bottom sheet"
}, },
"snackbarUnsupportedAudioFormat": "Unsupported audio format", "snackbarUnsupportedAudioFormat": "Unsupported audio format",
"@snackbarUnsupportedAudioFormat": { "@snackbarUnsupportedAudioFormat": {
@@ -3974,10 +3954,6 @@
"@cacheRefresh": { "@cacheRefresh": {
"description": "Tooltip for refresh button on cache management page" "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": "Download {trackCount} {trackCount, plural, =1{track} other{tracks}} from {playlistCount} {playlistCount, plural, =1{playlist} other{playlists}}?",
"@dialogDownloadPlaylistsMessage": { "@dialogDownloadPlaylistsMessage": {
"description": "Dialog message for bulk playlist download confirmation", "description": "Dialog message for bulk playlist download confirmation",
@@ -4105,7 +4081,6 @@
"@editMetadataSelectEmpty": { "@editMetadataSelectEmpty": {
"description": "Button to select only fields that are currently empty" "description": "Button to select only fields that are currently empty"
}, },
"queueDownloadingCount": "Downloading ({count})", "queueDownloadingCount": "Downloading ({count})",
"@queueDownloadingCount": { "@queueDownloadingCount": {
"description": "Header for active downloads section with count", "description": "Header for active downloads section with count",
@@ -4229,7 +4204,6 @@
"@audioAnalysisSamples": { "@audioAnalysisSamples": {
"description": "Total samples metric label" "description": "Total samples metric label"
}, },
"extensionsSearchWith": "Search with {providerName}", "extensionsSearchWith": "Search with {providerName}",
"@extensionsSearchWith": { "@extensionsSearchWith": {
"description": "Extensions page - subtitle for built-in search provider option", "description": "Extensions page - subtitle for built-in search provider option",
@@ -4249,7 +4223,7 @@
}, },
"extensionsHomeFeedAuto": "Auto", "extensionsHomeFeedAuto": "Auto",
"@extensionsHomeFeedAuto": { "@extensionsHomeFeedAuto": {
"description": "Extensions page - home feed provider option: auto" "description": "Label for auto-selected search provider"
}, },
"extensionsHomeFeedAutoSubtitle": "Automatically select the best available", "extensionsHomeFeedAutoSubtitle": "Automatically select the best available",
"@extensionsHomeFeedAutoSubtitle": { "@extensionsHomeFeedAutoSubtitle": {
@@ -4268,7 +4242,6 @@
"@extensionsNoHomeFeedExtensions": { "@extensionsNoHomeFeedExtensions": {
"description": "Extensions page - shown when no installed extension has home feed" "description": "Extensions page - shown when no installed extension has home feed"
}, },
"sortAlphaAsc": "A-Z", "sortAlphaAsc": "A-Z",
"@sortAlphaAsc": { "@sortAlphaAsc": {
"description": "Sort option - alphabetical ascending" "description": "Sort option - alphabetical ascending"
@@ -4294,7 +4267,6 @@
"@cancelDownloadKeep": { "@cancelDownloadKeep": {
"description": "Dialog button - keep the active download (do not cancel)" "description": "Dialog button - keep the active download (do not cancel)"
}, },
"metadataSaveFailedFfmpeg": "Failed to save metadata via FFmpeg", "metadataSaveFailedFfmpeg": "Failed to save metadata via FFmpeg",
"@metadataSaveFailedFfmpeg": { "@metadataSaveFailedFfmpeg": {
"description": "Snackbar error when FFmpeg fails to write metadata" "description": "Snackbar error when FFmpeg fails to write metadata"
@@ -4303,7 +4275,6 @@
"@metadataSaveFailedStorage": { "@metadataSaveFailedStorage": {
"description": "Snackbar error when writing metadata file back to storage fails" "description": "Snackbar error when writing metadata file back to storage fails"
}, },
"snackbarFolderPickerFailed": "Failed to open folder picker: {error}", "snackbarFolderPickerFailed": "Failed to open folder picker: {error}",
"@snackbarFolderPickerFailed": { "@snackbarFolderPickerFailed": {
"description": "Snackbar shown when folder picker fails to open", "description": "Snackbar shown when folder picker fails to open",
@@ -4313,7 +4284,6 @@
} }
} }
}, },
"errorLoadAlbum": "Failed to load album", "errorLoadAlbum": "Failed to load album",
"@errorLoadAlbum": { "@errorLoadAlbum": {
"description": "Error state shown when album fails to load" "description": "Error state shown when album fails to load"
@@ -4326,7 +4296,6 @@
"@errorLoadArtist": { "@errorLoadArtist": {
"description": "Error state shown when artist fails to load" "description": "Error state shown when artist fails to load"
}, },
"notifChannelDownloadName": "Download Progress", "notifChannelDownloadName": "Download Progress",
"@notifChannelDownloadName": { "@notifChannelDownloadName": {
"description": "Android notification channel name for download progress" "description": "Android notification channel name for download progress"
@@ -4540,5 +4509,77 @@
"notifUpdateFailedBody": "Could not download update. Try again later.", "notifUpdateFailedBody": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Не вдалося завантажити оновлення. Спробуйте пізніше.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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": "Could not download update. Try again later.",
"@notifUpdateFailedBody": { "@notifUpdateFailedBody": {
"description": "Notification body when app update download fails" "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/l10n/l10n.dart';
import 'package:spotiflac_android/screens/settings/appearance_settings_page.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/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/extensions_page.dart';
import 'package:spotiflac_android/screens/settings/library_settings_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/about_page.dart';
import 'package:spotiflac_android/screens/settings/cache_management_page.dart'; import 'package:spotiflac_android/screens/settings/cache_management_page.dart';
import 'package:spotiflac_android/screens/settings/donate_page.dart'; import 'package:spotiflac_android/screens/settings/donate_page.dart';
@@ -48,7 +51,7 @@ class SettingsTab extends ConsumerWidget {
title: Text( title: Text(
context.l10n.settingsTitle, context.l10n.settingsTitle,
style: TextStyle( style: TextStyle(
fontSize: 20 + (14 * expandRatio), // 20 -> 34 fontSize: 20 + (14 * expandRatio),
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: colorScheme.onSurface, color: colorScheme.onSurface,
), ),
@@ -58,6 +61,7 @@ class SettingsTab extends ConsumerWidget {
), ),
), ),
// ── Group 1: Appearance & Content ──────────────────────────────
SliverToBoxAdapter( SliverToBoxAdapter(
child: Builder( child: Builder(
builder: (context) { builder: (context) {
@@ -72,6 +76,34 @@ class SettingsTab extends ConsumerWidget {
onTap: () => onTap: () =>
_navigateTo(context, const AppearanceSettingsPage()), _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( SettingsItem(
icon: Icons.download_outlined, icon: Icons.download_outlined,
title: l10n.settingsDownload, title: l10n.settingsDownload,
@@ -80,12 +112,41 @@ class SettingsTab extends ConsumerWidget {
_navigateTo(context, const DownloadSettingsPage()), _navigateTo(context, const DownloadSettingsPage()),
), ),
SettingsItem( SettingsItem(
icon: Icons.library_music_outlined, icon: Icons.folder_outlined,
title: l10n.settingsLocalLibrary, title: l10n.settingsFiles,
subtitle: l10n.settingsLocalLibrarySubtitle, subtitle: l10n.settingsFilesSubtitle,
onTap: () => 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( SettingsItem(
icon: Icons.storage_outlined, icon: Icons.storage_outlined,
title: l10n.settingsCache, title: l10n.settingsCache,
@@ -95,41 +156,22 @@ class SettingsTab extends ConsumerWidget {
), ),
SettingsItem( SettingsItem(
icon: Icons.tune_outlined, icon: Icons.tune_outlined,
title: l10n.settingsOptions, title: l10n.settingsApp,
subtitle: l10n.settingsOptionsSubtitle, subtitle: l10n.settingsAppSubtitle,
onTap: () => onTap: () =>
_navigateTo(context, const OptionsSettingsPage()), _navigateTo(context, const AppSettingsPage()),
), ),
SettingsItem( SettingsItem(
icon: Icons.extension_outlined, icon: Icons.article_outlined,
title: l10n.settingsExtensions, title: l10n.logTitle,
subtitle: l10n.settingsExtensionsSubtitle, subtitle: l10n.settingsLogsSubtitle,
onTap: () => _navigateTo(context, const ExtensionsPage()), onTap: () => _navigateTo(context, const LogScreen()),
), ),
SettingsItem( SettingsItem(
icon: Icons.favorite_outline, icon: Icons.favorite_outline,
title: l10n.settingsDonate, title: l10n.settingsDonate,
subtitle: l10n.settingsDonateSubtitle, subtitle: l10n.settingsDonateSubtitle,
onTap: () => _navigateTo(context, const DonatePage()), 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( SettingsItem(
icon: Icons.info_outline, icon: Icons.info_outline,
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 71 KiB