mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-05-15 05:10:28 +02:00
feat: allow re-running audio quality analysis after cached result
The audio analysis card used to read from a persistent cache but offered no way to refresh the result when the underlying file had been re-downloaded at a different quality (for example, re-downloading a track as FLAC after capturing it as AAC). Add an explicit rescan control that clears the cached JSON + spectrogram, reruns the FFmpeg probe and analysis pipeline, and swaps in the fresh data while keeping the loading copy distinct from first-run analysis. A retry button is also exposed in the error card so transient failures do not require navigating away. All audio_analysis strings now have a Re-analyze / Re-analyzing pair in the ARB catalog so every locale can translate them independently.
This commit is contained in:
@@ -5617,6 +5617,18 @@ abstract class AppLocalizations {
|
||||
/// **'Samples'**
|
||||
String get audioAnalysisSamples;
|
||||
|
||||
/// Tooltip/label for the button that re-runs the audio analysis, discarding cached results
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Re-analyze'**
|
||||
String get audioAnalysisRescan;
|
||||
|
||||
/// Loading text while audio is being re-analyzed after an explicit refresh
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Re-analyzing audio...'**
|
||||
String get audioAnalysisRescanning;
|
||||
|
||||
/// Extensions page - subtitle for built-in search provider option
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -3322,6 +3322,12 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Proben';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3287,6 +3287,12 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3287,6 +3287,12 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
@@ -7049,6 +7055,12 @@ class AppLocalizationsEsEs extends AppLocalizationsEs {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3291,6 +3291,12 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3288,6 +3288,12 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3297,6 +3297,12 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3275,6 +3275,12 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3268,6 +3268,12 @@ class AppLocalizationsKo extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3288,6 +3288,12 @@ class AppLocalizationsNl extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3287,6 +3287,12 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
@@ -7042,6 +7048,12 @@ class AppLocalizationsPtPt extends AppLocalizationsPt {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3347,6 +3347,12 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3314,6 +3314,12 @@ class AppLocalizationsTr extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -3343,6 +3343,12 @@ class AppLocalizationsUk extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Семпли';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Пошук за допомогою$providerName';
|
||||
|
||||
@@ -3287,6 +3287,12 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
@@ -7008,6 +7014,12 @@ class AppLocalizationsZhCn extends AppLocalizationsZh {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
@@ -10485,6 +10497,12 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
|
||||
@override
|
||||
String get audioAnalysisSamples => 'Samples';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescan => 'Re-analyze';
|
||||
|
||||
@override
|
||||
String get audioAnalysisRescanning => 'Re-analyzing audio...';
|
||||
|
||||
@override
|
||||
String extensionsSearchWith(String providerName) {
|
||||
return 'Search with $providerName';
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4279,6 +4279,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4204,6 +4204,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4027,6 +4027,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"downloadSingleFilenameFormat": "Single Dosya Adı Formatı",
|
||||
"@downloadSingleFilenameFormat": {
|
||||
"description": "Setting for output filename pattern for singles/EPs"
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Пошук за допомогою{providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -4196,6 +4196,14 @@
|
||||
"@audioAnalysisSamples": {
|
||||
"description": "Total samples metric label"
|
||||
},
|
||||
"audioAnalysisRescan": "Re-analyze",
|
||||
"@audioAnalysisRescan": {
|
||||
"description": "Tooltip/label for the button that re-runs the audio analysis, discarding cached results"
|
||||
},
|
||||
"audioAnalysisRescanning": "Re-analyzing audio...",
|
||||
"@audioAnalysisRescanning": {
|
||||
"description": "Loading text while audio is being re-analyzed after an explicit refresh"
|
||||
},
|
||||
"extensionsSearchWith": "Search with {providerName}",
|
||||
"@extensionsSearchWith": {
|
||||
"description": "Extensions page - subtitle for built-in search provider option",
|
||||
|
||||
@@ -165,15 +165,24 @@ class _AudioAnalysisCardState extends State<AudioAnalysisCard> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _analyze() async {
|
||||
Future<void> _analyze({bool forceRefresh = false}) async {
|
||||
if (_analyzing) return;
|
||||
setState(() {
|
||||
_analyzing = true;
|
||||
_error = null;
|
||||
if (forceRefresh) {
|
||||
_spectrogramImage?.dispose();
|
||||
_spectrogramImage = null;
|
||||
_data = null;
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
final cached = await _loadFromCache(widget.filePath);
|
||||
if (forceRefresh) {
|
||||
await _clearCache(widget.filePath);
|
||||
}
|
||||
|
||||
final cached = forceRefresh ? null : await _loadFromCache(widget.filePath);
|
||||
AudioAnalysisData data;
|
||||
bool fromCache = false;
|
||||
|
||||
@@ -214,6 +223,21 @@ class _AudioAnalysisCardState extends State<AudioAnalysisCard> {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> _clearCache(String filePath) async {
|
||||
try {
|
||||
final dir = await _cacheDir();
|
||||
final key = _cacheKey(filePath);
|
||||
final jsonFile = File('${dir.path}/$key.json');
|
||||
final imageFile = File('${dir.path}/$key.png');
|
||||
if (await jsonFile.exists()) {
|
||||
await jsonFile.delete();
|
||||
}
|
||||
if (await imageFile.exists()) {
|
||||
await imageFile.delete();
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
static String _cacheKey(String filePath) {
|
||||
var hash = 0xcbf29ce484222325;
|
||||
for (final byte in utf8.encode(filePath)) {
|
||||
@@ -499,6 +523,7 @@ class _AudioAnalysisCardState extends State<AudioAnalysisCard> {
|
||||
if (_checkingCache) return const SizedBox.shrink();
|
||||
|
||||
if (_analyzing) {
|
||||
final isRescan = _data != null || _spectrogramImage != null;
|
||||
return Card(
|
||||
color: cs.surfaceContainerLow,
|
||||
child: Padding(
|
||||
@@ -514,7 +539,9 @@ class _AudioAnalysisCardState extends State<AudioAnalysisCard> {
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.audioAnalysisAnalyzing,
|
||||
isRescan
|
||||
? l10n.audioAnalysisRescanning
|
||||
: l10n.audioAnalysisAnalyzing,
|
||||
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 13),
|
||||
),
|
||||
],
|
||||
@@ -539,6 +566,18 @@ class _AudioAnalysisCardState extends State<AudioAnalysisCard> {
|
||||
style: TextStyle(color: cs.onErrorContainer, fontSize: 13),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
tooltip: l10n.audioAnalysisRescan,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(
|
||||
minWidth: 32,
|
||||
minHeight: 32,
|
||||
),
|
||||
color: cs.onErrorContainer,
|
||||
onPressed: () => _analyze(forceRefresh: true),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -592,7 +631,10 @@ class _AudioAnalysisCardState extends State<AudioAnalysisCard> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_AudioInfoCard(data: data),
|
||||
_AudioInfoCard(
|
||||
data: data,
|
||||
onRescan: () => _analyze(forceRefresh: true),
|
||||
),
|
||||
if (_spectrogramImage != null) ...[
|
||||
const SizedBox(height: 12),
|
||||
_SpectrogramView(
|
||||
@@ -796,8 +838,9 @@ Float64List _fft(Float64List realInput) {
|
||||
|
||||
class _AudioInfoCard extends StatelessWidget {
|
||||
final AudioAnalysisData data;
|
||||
final VoidCallback? onRescan;
|
||||
|
||||
const _AudioInfoCard({required this.data});
|
||||
const _AudioInfoCard({required this.data, this.onRescan});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -815,14 +858,29 @@ class _AudioInfoCard extends StatelessWidget {
|
||||
children: [
|
||||
Icon(Icons.analytics_outlined, color: cs.primary, size: 20),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
context.l10n.audioAnalysisTitle,
|
||||
style: TextStyle(
|
||||
color: cs.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
Expanded(
|
||||
child: Text(
|
||||
context.l10n.audioAnalysisTitle,
|
||||
style: TextStyle(
|
||||
color: cs.onSurface,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (onRescan != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
tooltip: context.l10n.audioAnalysisRescan,
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(
|
||||
minWidth: 32,
|
||||
minHeight: 32,
|
||||
),
|
||||
color: cs.onSurfaceVariant,
|
||||
onPressed: onRescan,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
Reference in New Issue
Block a user