feat(metadata): display saved ReplayGain values and refresh after analysis

This commit is contained in:
zarzet
2026-09-15 21:44:59 +07:00
parent 0ad17f0caa
commit e063e6d5da
9 changed files with 224 additions and 2 deletions
+16
View File
@@ -1593,6 +1593,22 @@
"@trackAudioQuality": {
"description": "Metadata label - audio quality"
},
"trackReplayGainTrackGain": "ReplayGain Track Gain",
"@trackReplayGainTrackGain": {
"description": "Metadata label - ReplayGain track gain"
},
"trackReplayGainTrackPeak": "ReplayGain Track Peak",
"@trackReplayGainTrackPeak": {
"description": "Metadata label - ReplayGain track peak"
},
"trackReplayGainAlbumGain": "ReplayGain Album Gain",
"@trackReplayGainAlbumGain": {
"description": "Metadata label - ReplayGain album gain"
},
"trackReplayGainAlbumPeak": "ReplayGain Album Peak",
"@trackReplayGainAlbumPeak": {
"description": "Metadata label - ReplayGain album peak"
},
"libraryQualityLabelFileFormat": "File format",
"@libraryQualityLabelFileFormat": {
"description": "Library audio quality label mode that shows the detected file format"
+16
View File
@@ -2169,6 +2169,22 @@
"@trackAudioQuality": {
"description": "Metadata label - audio quality"
},
"trackReplayGainTrackGain": "ReplayGain Track Gain",
"@trackReplayGainTrackGain": {
"description": "Metadata label - ReplayGain track gain"
},
"trackReplayGainTrackPeak": "ReplayGain Track Peak",
"@trackReplayGainTrackPeak": {
"description": "Metadata label - ReplayGain track peak"
},
"trackReplayGainAlbumGain": "ReplayGain Album Gain",
"@trackReplayGainAlbumGain": {
"description": "Metadata label - ReplayGain album gain"
},
"trackReplayGainAlbumPeak": "ReplayGain Album Peak",
"@trackReplayGainAlbumPeak": {
"description": "Metadata label - ReplayGain album peak"
},
"libraryQualityLabelFileFormat": "Format berkas",
"libraryRemovedMissingFiles": "Removed {count} missing files from library",
"@libraryRemovedMissingFiles": {
+32
View File
@@ -456,6 +456,18 @@ extension _TrackMetadataCards on _TrackMetadataScreenState {
Widget _buildMetadataGrid(BuildContext context, ColorScheme colorScheme) {
final audioQualityStr = _displayAudioQuality;
final replayGainTrackGain = normalizeOptionalString(
_editedMetadata?['replaygain_track_gain']?.toString(),
);
final replayGainTrackPeak = normalizeOptionalString(
_editedMetadata?['replaygain_track_peak']?.toString(),
);
final replayGainAlbumGain = normalizeOptionalString(
_editedMetadata?['replaygain_album_gain']?.toString(),
);
final replayGainAlbumPeak = normalizeOptionalString(
_editedMetadata?['replaygain_album_peak']?.toString(),
);
final items = <_MetadataItem>[
_MetadataItem(context.l10n.trackTrackName, trackName),
@@ -481,6 +493,26 @@ extension _TrackMetadataCards on _TrackMetadataScreenState {
_MetadataItem(context.l10n.trackDuration, formatClock(duration!)),
if (audioQualityStr != null)
_MetadataItem(context.l10n.trackAudioQuality, audioQualityStr),
if (replayGainTrackGain != null)
_MetadataItem(
context.l10n.trackReplayGainTrackGain,
replayGainTrackGain,
),
if (replayGainTrackPeak != null)
_MetadataItem(
context.l10n.trackReplayGainTrackPeak,
replayGainTrackPeak,
),
if (replayGainAlbumGain != null)
_MetadataItem(
context.l10n.trackReplayGainAlbumGain,
replayGainAlbumGain,
),
if (replayGainAlbumPeak != null)
_MetadataItem(
context.l10n.trackReplayGainAlbumPeak,
replayGainAlbumPeak,
),
if (_embeddedCoverDimensions case final dimensions?)
_MetadataItem(
context.l10n.trackCoverResolution,
+10 -1
View File
@@ -193,6 +193,8 @@ extension _TrackMetadataConvertAndCueSplit on _TrackMetadataScreenState {
Future<void> _rescanReplayGain() async {
if (!_fileExists) return;
final sourcePath = cleanFilePath;
final generation = _metadataLoadGeneration;
final messenger = ScaffoldMessenger.of(context);
messenger.clearSnackBars();
messenger.showSnackBar(
@@ -203,11 +205,18 @@ extension _TrackMetadataConvertAndCueSplit on _TrackMetadataScreenState {
);
bool ok = false;
try {
ok = await ReplayGainService.applyToFile(cleanFilePath);
ok = await ReplayGainService.applyToFile(sourcePath);
} catch (e) {
_log.w('ReplayGain rescan failed: $e');
}
if (!mounted) return;
if (ok &&
generation == _metadataLoadGeneration &&
sourcePath == cleanFilePath) {
_hasLoadedResolvedAudioMetadata = false;
await _refreshResolvedAudioMetadataFromFile();
}
if (!mounted) return;
messenger.hideCurrentSnackBar();
messenger.showSnackBar(
SnackBar(
+17 -1
View File
@@ -125,6 +125,12 @@ class TrackMetadataScreen extends ConsumerStatefulWidget {
class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen>
with CollapsingHeaderScrollMixin<TrackMetadataScreen> {
static const int _maxCoverPreviewCacheEntries = 96;
static const _replayGainFields = [
'replaygain_track_gain',
'replaygain_track_peak',
'replaygain_album_gain',
'replaygain_album_peak',
];
static final Map<String, _EmbeddedCoverPreviewCacheEntry>
_embeddedCoverPreviewCache = {};
@@ -299,6 +305,14 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen>
return;
}
final replayGainMetadata = {
for (final key in _replayGainFields)
key: normalizeOptionalString(metadata[key]?.toString()),
};
final replayGainChanged = replayGainMetadata.entries.any(
(entry) => entry.value != _editedMetadata?[entry.key],
);
final resolvedBitDepth = readPositiveInt(metadata['bit_depth']);
final resolvedSampleRate = readPositiveInt(metadata['sample_rate']);
final resolvedFormat = detectedAudioFormatFromMetadata(metadata);
@@ -437,7 +451,8 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen>
needsDuration ||
formatChanged);
if ((resolvedBitDepth != null ||
if ((replayGainChanged ||
resolvedBitDepth != null ||
resolvedSampleRate != null ||
resolvedFormat != null ||
fileHasTitle ||
@@ -465,6 +480,7 @@ class _TrackMetadataScreenState extends ConsumerState<TrackMetadataScreen>
_resolvedAudioFormat = resolvedFormat;
_editedMetadata = {
...?_editedMetadata,
...replayGainMetadata,
// ignore: use_null_aware_elements
if (resolvedBitDepth != null) 'bit_depth': resolvedBitDepth,
// ignore: use_null_aware_elements