mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-02 16:20:57 +02:00
fix(extensions): resume metadata after verification
This commit is contained in:
@@ -26,6 +26,7 @@ import 'package:spotiflac_android/services/cover_download_service.dart';
|
||||
import 'package:spotiflac_android/services/downloaded_embedded_cover_resolver.dart';
|
||||
import 'package:spotiflac_android/services/platform_bridge.dart';
|
||||
import 'package:spotiflac_android/utils/adaptive_layout.dart';
|
||||
import 'package:spotiflac_android/utils/extension_auth_launcher.dart';
|
||||
import 'package:spotiflac_android/utils/nav_bar_inset.dart';
|
||||
import 'package:spotiflac_android/utils/file_access.dart';
|
||||
import 'package:spotiflac_android/utils/string_utils.dart';
|
||||
|
||||
@@ -932,10 +932,16 @@ class _ExtensionAlbumScreenState extends ConsumerState<ExtensionAlbumScreen> {
|
||||
});
|
||||
|
||||
try {
|
||||
final result = await PlatformBridge.getProviderMetadata(
|
||||
widget.extensionId,
|
||||
'album',
|
||||
widget.albumId,
|
||||
final result = await runExtensionOperationWithVerificationRetry(
|
||||
extensionId: widget.extensionId,
|
||||
browserMode: ref
|
||||
.read(settingsProvider)
|
||||
.extensionVerificationBrowserMode,
|
||||
operation: () => PlatformBridge.getProviderMetadata(
|
||||
widget.extensionId,
|
||||
'album',
|
||||
widget.albumId,
|
||||
),
|
||||
);
|
||||
if (!mounted) return;
|
||||
|
||||
@@ -1106,10 +1112,16 @@ class _ExtensionPlaylistScreenState
|
||||
});
|
||||
|
||||
try {
|
||||
final result = await PlatformBridge.getProviderMetadata(
|
||||
widget.extensionId,
|
||||
'playlist',
|
||||
widget.playlistId,
|
||||
final result = await runExtensionOperationWithVerificationRetry(
|
||||
extensionId: widget.extensionId,
|
||||
browserMode: ref
|
||||
.read(settingsProvider)
|
||||
.extensionVerificationBrowserMode,
|
||||
operation: () => PlatformBridge.getProviderMetadata(
|
||||
widget.extensionId,
|
||||
'playlist',
|
||||
widget.playlistId,
|
||||
),
|
||||
);
|
||||
if (!mounted) return;
|
||||
|
||||
@@ -1251,10 +1263,16 @@ class _ExtensionArtistScreenState extends ConsumerState<ExtensionArtistScreen>
|
||||
});
|
||||
|
||||
try {
|
||||
final result = await PlatformBridge.getProviderMetadata(
|
||||
widget.extensionId,
|
||||
'artist',
|
||||
widget.artistId,
|
||||
final result = await runExtensionOperationWithVerificationRetry(
|
||||
extensionId: widget.extensionId,
|
||||
browserMode: ref
|
||||
.read(settingsProvider)
|
||||
.extensionVerificationBrowserMode,
|
||||
operation: () => PlatformBridge.getProviderMetadata(
|
||||
widget.extensionId,
|
||||
'artist',
|
||||
widget.artistId,
|
||||
),
|
||||
);
|
||||
if (!mounted) return;
|
||||
|
||||
|
||||
@@ -25,6 +25,29 @@ bool isExtensionVerificationRequired(Object error) {
|
||||
_containsHttpStatusCode(message, '428');
|
||||
}
|
||||
|
||||
Future<T> runExtensionOperationWithVerificationRetry<T>({
|
||||
required String extensionId,
|
||||
required String browserMode,
|
||||
required Future<T> Function() operation,
|
||||
Future<bool> Function()? verify,
|
||||
}) async {
|
||||
try {
|
||||
return await operation();
|
||||
} catch (error) {
|
||||
if (!isExtensionVerificationRequired(error)) rethrow;
|
||||
|
||||
final verified =
|
||||
await (verify ??
|
||||
() => openVerificationAndAwaitGrant(
|
||||
extensionId,
|
||||
browserMode: browserMode,
|
||||
))();
|
||||
if (!verified) rethrow;
|
||||
|
||||
return operation();
|
||||
}
|
||||
}
|
||||
|
||||
String? extensionIdFromVerificationError(
|
||||
Object error,
|
||||
Iterable<String> knownExtensionIds,
|
||||
|
||||
@@ -24,6 +24,51 @@ void main() {
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'retries an extension operation after successful verification',
|
||||
() async {
|
||||
var operationCalls = 0;
|
||||
var verificationCalls = 0;
|
||||
|
||||
final result = await runExtensionOperationWithVerificationRetry(
|
||||
extensionId: 'qobuz-web',
|
||||
browserMode: 'in_app_first',
|
||||
operation: () async {
|
||||
operationCalls++;
|
||||
if (operationCalls == 1) throw Exception('VERIFY_REQUIRED');
|
||||
return 'artist metadata';
|
||||
},
|
||||
verify: () async {
|
||||
verificationCalls++;
|
||||
return true;
|
||||
},
|
||||
);
|
||||
|
||||
expect(result, 'artist metadata');
|
||||
expect(operationCalls, 2);
|
||||
expect(verificationCalls, 1);
|
||||
},
|
||||
);
|
||||
|
||||
test('does not retry when extension verification is not completed', () async {
|
||||
var operationCalls = 0;
|
||||
|
||||
await expectLater(
|
||||
runExtensionOperationWithVerificationRetry(
|
||||
extensionId: 'qobuz-web',
|
||||
browserMode: 'in_app_first',
|
||||
operation: () async {
|
||||
operationCalls++;
|
||||
throw Exception('VERIFY_REQUIRED');
|
||||
},
|
||||
verify: () async => false,
|
||||
),
|
||||
throwsA(isA<Exception>()),
|
||||
);
|
||||
|
||||
expect(operationCalls, 1);
|
||||
});
|
||||
|
||||
test('verification wait can be cancelled before foreground resume', () async {
|
||||
final foreground = Completer<void>();
|
||||
final cancellation = Completer<void>();
|
||||
|
||||
Reference in New Issue
Block a user