mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-02 16:20:57 +02:00
feat: add file format library quality label
This commit is contained in:
@@ -2206,6 +2206,12 @@ abstract class AppLocalizations {
|
||||
/// **'Audio quality'**
|
||||
String get trackAudioQuality;
|
||||
|
||||
/// Library audio quality label mode that shows the detected file format
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'File format'**
|
||||
String get libraryQualityLabelFileFormat;
|
||||
|
||||
/// Metadata label - release date
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -1203,6 +1203,9 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Audioqualität';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Erscheinungsdatum';
|
||||
|
||||
|
||||
@@ -1188,6 +1188,9 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Audio quality';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Release date';
|
||||
|
||||
|
||||
@@ -1188,6 +1188,9 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Audio quality';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Release date';
|
||||
|
||||
|
||||
@@ -1217,6 +1217,9 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Qualité audio';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Date de sortie';
|
||||
|
||||
|
||||
@@ -1193,6 +1193,9 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Kualitas audio';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'Format berkas';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Tanggal rilis';
|
||||
|
||||
|
||||
@@ -1183,6 +1183,9 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'オーディオ品質';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'リリース日';
|
||||
|
||||
|
||||
@@ -1162,6 +1162,9 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => '오디오 음질';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => '발매일자';
|
||||
|
||||
|
||||
@@ -1188,6 +1188,9 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Audio quality';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Release date';
|
||||
|
||||
|
||||
@@ -1194,6 +1194,9 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Качество записи';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Дата выхода';
|
||||
|
||||
|
||||
@@ -1199,6 +1199,9 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Ses kalitesi';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Yayın tarihi';
|
||||
|
||||
|
||||
@@ -1203,6 +1203,9 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
@override
|
||||
String get trackAudioQuality => 'Якість звуку';
|
||||
|
||||
@override
|
||||
String get libraryQualityLabelFileFormat => 'File format';
|
||||
|
||||
@override
|
||||
String get trackReleaseDate => 'Дата випуску';
|
||||
|
||||
|
||||
@@ -1568,6 +1568,10 @@
|
||||
"@trackAudioQuality": {
|
||||
"description": "Metadata label - audio quality"
|
||||
},
|
||||
"libraryQualityLabelFileFormat": "File format",
|
||||
"@libraryQualityLabelFileFormat": {
|
||||
"description": "Library audio quality label mode that shows the detected file format"
|
||||
},
|
||||
"trackReleaseDate": "Release date",
|
||||
"@trackReleaseDate": {
|
||||
"description": "Metadata label - release date"
|
||||
|
||||
@@ -2164,6 +2164,7 @@
|
||||
"@trackAudioQuality": {
|
||||
"description": "Metadata label - audio quality"
|
||||
},
|
||||
"libraryQualityLabelFileFormat": "Format berkas",
|
||||
"libraryRemovedMissingFiles": "Removed {count} missing files from library",
|
||||
"@libraryRemovedMissingFiles": {
|
||||
"description": "Snackbar after cleanup",
|
||||
|
||||
@@ -7,6 +7,7 @@ part 'settings.g.dart';
|
||||
class AppSettings {
|
||||
static const String homeFeedProviderOff = '__off__';
|
||||
static const String libraryQualityLabelBitrate = 'bitrate';
|
||||
static const String libraryQualityLabelFileFormat = 'file_format';
|
||||
static const String libraryQualityLabelBitDepthOnly = 'bit_depth_only';
|
||||
static const String libraryQualityLabelBitDepth = 'bit_depth';
|
||||
static const String libraryQualityLabelBitDepthBitrate = 'bit_depth_bitrate';
|
||||
@@ -42,8 +43,8 @@ class AppSettings {
|
||||
/// 'last' (keep last used), 'all', 'albums', 'singles', or 'playlists'.
|
||||
final String defaultLibraryView;
|
||||
|
||||
/// Library badge text: measured bitrate, bit depth, bit depth/sample rate,
|
||||
/// or the combined bit depth/bitrate label.
|
||||
/// Library badge text: measured bitrate, file format, bit depth,
|
||||
/// bit depth/sample rate, or the combined bit depth/bitrate label.
|
||||
final String libraryQualityLabelMode;
|
||||
final bool askQualityBeforeDownload;
|
||||
final bool enableLogging;
|
||||
|
||||
@@ -381,6 +381,8 @@ class SettingsNotifier extends Notifier<AppSettings> {
|
||||
|
||||
String _normalizeLibraryQualityLabelMode(String value) {
|
||||
return switch (value) {
|
||||
AppSettings.libraryQualityLabelFileFormat =>
|
||||
AppSettings.libraryQualityLabelFileFormat,
|
||||
AppSettings.libraryQualityLabelBitDepthOnly =>
|
||||
AppSettings.libraryQualityLabelBitDepthOnly,
|
||||
AppSettings.libraryQualityLabelBitDepth =>
|
||||
|
||||
@@ -435,6 +435,9 @@ class _LibrarySettingsPageState extends ConsumerState<LibrarySettingsPage> {
|
||||
}
|
||||
|
||||
String _getQualityLabelModeLabel(BuildContext context, String mode) {
|
||||
if (mode == AppSettings.libraryQualityLabelFileFormat) {
|
||||
return context.l10n.libraryQualityLabelFileFormat;
|
||||
}
|
||||
if (mode == AppSettings.libraryQualityLabelBitDepthOnly) {
|
||||
return context.l10n.audioAnalysisBitDepth;
|
||||
}
|
||||
@@ -474,6 +477,11 @@ class _LibrarySettingsPageState extends ConsumerState<LibrarySettingsPage> {
|
||||
'${context.l10n.audioAnalysisBitDepth} & '
|
||||
'${context.l10n.trackConvertBitrate}',
|
||||
),
|
||||
(
|
||||
AppSettings.libraryQualityLabelFileFormat,
|
||||
Icons.audio_file_rounded,
|
||||
context.l10n.libraryQualityLabelFileFormat,
|
||||
),
|
||||
];
|
||||
showModalBottomSheet<void>(
|
||||
context: context,
|
||||
|
||||
@@ -149,7 +149,16 @@ class SettingsSearchCatalog {
|
||||
SettingsSearchEntry(
|
||||
icon: Icons.graphic_eq_rounded,
|
||||
title: l10n.trackAudioQuality,
|
||||
keywords: const ['quality label', 'bitrate', 'bit depth', 'kbps'],
|
||||
keywords: const [
|
||||
'quality label',
|
||||
'bitrate',
|
||||
'bit depth',
|
||||
'file format',
|
||||
'codec',
|
||||
'flac',
|
||||
'mp3',
|
||||
'kbps',
|
||||
],
|
||||
),
|
||||
SettingsSearchEntry(
|
||||
icon: Icons.library_music_outlined,
|
||||
|
||||
@@ -11,6 +11,8 @@ final RegExp _bitDepthQualityPattern = RegExp(
|
||||
|
||||
String normalizeLibraryQualityLabelMode(String? mode) {
|
||||
return switch (mode) {
|
||||
AppSettings.libraryQualityLabelFileFormat =>
|
||||
AppSettings.libraryQualityLabelFileFormat,
|
||||
AppSettings.libraryQualityLabelBitDepthOnly =>
|
||||
AppSettings.libraryQualityLabelBitDepthOnly,
|
||||
AppSettings.libraryQualityLabelBitDepth =>
|
||||
@@ -21,9 +23,29 @@ String normalizeLibraryQualityLabelMode(String? mode) {
|
||||
};
|
||||
}
|
||||
|
||||
String? _libraryFileFormatLabel(String? format) {
|
||||
final rawFormat = normalizeOptionalString(format);
|
||||
if (rawFormat == null) return null;
|
||||
|
||||
return switch (normalizeAudioFormatValue(rawFormat)) {
|
||||
'flac' => 'FLAC',
|
||||
'alac' => 'ALAC',
|
||||
'wav' => 'WAV',
|
||||
'aiff' => 'AIFF',
|
||||
'aac' => 'AAC',
|
||||
'eac3' => 'EAC3',
|
||||
'ac3' => 'AC3',
|
||||
'ac4' => 'AC4',
|
||||
'mp3' => 'MP3',
|
||||
'opus' => 'OPUS',
|
||||
'm4a' => 'M4A',
|
||||
_ => rawFormat.replaceFirst(RegExp(r'^\.'), '').toUpperCase(),
|
||||
};
|
||||
}
|
||||
|
||||
/// Builds a Library label from metadata already held in memory. Lossy formats
|
||||
/// keep their bitrate label because bit depth is not a useful quality signal
|
||||
/// for encoded MP3/AAC/Opus audio.
|
||||
/// keep their bitrate label in quality modes because bit depth is not a useful
|
||||
/// quality signal for encoded MP3/AAC/Opus audio.
|
||||
String? buildLibraryAudioQualityLabel({
|
||||
required String mode,
|
||||
String? format,
|
||||
@@ -53,6 +75,10 @@ String? buildLibraryAudioQualityLabel({
|
||||
: null;
|
||||
final normalizedMode = normalizeLibraryQualityLabelMode(mode);
|
||||
|
||||
if (normalizedMode == AppSettings.libraryQualityLabelFileFormat) {
|
||||
return _libraryFileFormatLabel(format);
|
||||
}
|
||||
|
||||
if (isLossyAudioFormat(format)) {
|
||||
return bitrateLabel;
|
||||
}
|
||||
|
||||
@@ -54,6 +54,48 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test('shows detected file format without quality metrics', () {
|
||||
expect(
|
||||
normalizeLibraryQualityLabelMode(
|
||||
AppSettings.libraryQualityLabelFileFormat,
|
||||
),
|
||||
AppSettings.libraryQualityLabelFileFormat,
|
||||
);
|
||||
expect(
|
||||
buildLibraryAudioQualityLabel(
|
||||
mode: AppSettings.libraryQualityLabelFileFormat,
|
||||
format: 'flac',
|
||||
bitrateKbps: 1760,
|
||||
bitDepth: 24,
|
||||
sampleRate: 96000,
|
||||
),
|
||||
'FLAC',
|
||||
);
|
||||
expect(
|
||||
buildLibraryAudioQualityLabel(
|
||||
mode: AppSettings.libraryQualityLabelFileFormat,
|
||||
format: 'm4a',
|
||||
bitrateKbps: 256,
|
||||
),
|
||||
'M4A',
|
||||
);
|
||||
expect(
|
||||
buildLibraryAudioQualityLabel(
|
||||
mode: AppSettings.libraryQualityLabelFileFormat,
|
||||
format: 'mp3',
|
||||
bitrateKbps: 320,
|
||||
),
|
||||
'MP3',
|
||||
);
|
||||
expect(
|
||||
buildLibraryAudioQualityLabel(
|
||||
mode: AppSettings.libraryQualityLabelFileFormat,
|
||||
format: 'ape',
|
||||
),
|
||||
'APE',
|
||||
);
|
||||
});
|
||||
|
||||
test('shows only bit depth when requested', () {
|
||||
expect(
|
||||
buildLibraryAudioQualityLabel(
|
||||
|
||||
Reference in New Issue
Block a user