feat: add file format library quality label

This commit is contained in:
zarzet
2026-08-27 16:50:46 +07:00
parent 4609e59806
commit 2b117415ae
20 changed files with 137 additions and 5 deletions
+6
View File
@@ -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:
+3
View File
@@ -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';
+3
View File
@@ -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';
+3
View File
@@ -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';
+3
View File
@@ -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';
+3
View File
@@ -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';
+3
View File
@@ -1183,6 +1183,9 @@ class AppLocalizationsJa extends AppLocalizations {
@override
String get trackAudioQuality => 'オーディオ品質';
@override
String get libraryQualityLabelFileFormat => 'File format';
@override
String get trackReleaseDate => 'リリース日';
+3
View File
@@ -1162,6 +1162,9 @@ class AppLocalizationsKo extends AppLocalizations {
@override
String get trackAudioQuality => '오디오 음질';
@override
String get libraryQualityLabelFileFormat => 'File format';
@override
String get trackReleaseDate => '발매일자';
+3
View File
@@ -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';
+3
View File
@@ -1194,6 +1194,9 @@ class AppLocalizationsRu extends AppLocalizations {
@override
String get trackAudioQuality => 'Качество записи';
@override
String get libraryQualityLabelFileFormat => 'File format';
@override
String get trackReleaseDate => 'Дата выхода';
+3
View File
@@ -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';
+3
View File
@@ -1203,6 +1203,9 @@ class AppLocalizationsUk extends AppLocalizations {
@override
String get trackAudioQuality => 'Якість звуку';
@override
String get libraryQualityLabelFileFormat => 'File format';
@override
String get trackReleaseDate => 'Дата випуску';
+4
View File
@@ -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"
+1
View File
@@ -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",
+3 -2
View File
@@ -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;
+2
View File
@@ -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,
+28 -2
View File
@@ -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;
}
+42
View File
@@ -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(