fix(notifications): restore verification alert sound

This commit is contained in:
zarzet
2026-07-23 13:23:54 +07:00
parent c9114fef01
commit cdbb0d6bd7
3 changed files with 130 additions and 8 deletions
+14 -1
View File
@@ -443,8 +443,21 @@ class DownloadQueueNotifier extends Notifier<DownloadQueueState> {
'Verification required for $normalizedExtensionId while app is in '
'background; deferring challenge until the app is foregrounded',
);
unawaited(_notificationService.showVerificationRequired());
try {
await _notificationService.showVerificationRequired();
} catch (error) {
_log.w(
'Failed to show the verification-required notification: $error',
);
}
await _waitForForeground();
try {
await _notificationService.cancelVerificationRequired();
} catch (error) {
_log.w(
'Failed to clear the verification-required notification: $error',
);
}
}
},
);
+42 -7
View File
@@ -30,9 +30,14 @@ class NotificationService {
static const int downloadProgressId = 1;
static const int updateDownloadId = 2;
static const int libraryScanId = 3;
static const int verificationRequiredId = 4;
static const String channelId = 'download_progress';
static const String channelName = 'Download Progress';
static const String channelDescription = 'Shows download progress for tracks';
static const String alertChannelId = 'download_alerts_v1';
static const String alertChannelName = 'Download Alerts';
static const String alertChannelDescription =
'Important download status and actions that need attention';
static const String libraryChannelId = 'library_scan';
static const String libraryChannelName = 'Library Scan';
static const String libraryChannelDescription =
@@ -57,7 +62,7 @@ class NotificationService {
await _notifications.initialize(settings: initSettings);
if (Platform.isAndroid) {
if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) {
final androidImpl = _notifications
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
@@ -73,6 +78,16 @@ class NotificationService {
enableVibration: false,
),
);
await androidImpl?.createNotificationChannel(
const AndroidNotificationChannel(
alertChannelId,
alertChannelName,
description: alertChannelDescription,
importance: Importance.defaultImportance,
playSound: true,
enableVibration: true,
),
);
await androidImpl?.createNotificationChannel(
const AndroidNotificationChannel(
libraryChannelId,
@@ -147,14 +162,30 @@ class NotificationService {
bool presentBadge = false,
bool presentSound = false,
}) {
assert(!library || !playSound);
final inProgress = progress != null;
assert(!inProgress || !playSound);
final androidChannelId = library
? libraryChannelId
: playSound
? alertChannelId
: channelId;
final androidChannelName = library
? libraryChannelName
: playSound
? alertChannelName
: channelName;
final androidChannelDescription = library
? libraryChannelDescription
: playSound
? alertChannelDescription
: channelDescription;
return NotificationDetails(
android: AndroidNotificationDetails(
library ? libraryChannelId : channelId,
library ? libraryChannelName : channelName,
channelDescription: library
? libraryChannelDescription
: channelDescription,
androidChannelId,
androidChannelName,
channelDescription: androidChannelDescription,
importance: inProgress ? Importance.low : Importance.defaultImportance,
priority: inProgress ? Priority.low : Priority.defaultPriority,
showProgress: inProgress,
@@ -285,7 +316,7 @@ class NotificationService {
'Open the app to complete verification and resume downloads';
await _showSafely(
id: downloadProgressId,
id: verificationRequiredId,
title: title,
body: body,
details: _details(
@@ -296,6 +327,10 @@ class NotificationService {
);
}
Future<void> cancelVerificationRequired() async {
await _notifications.cancel(id: verificationRequiredId);
}
Future<void> showQueueCanceled({required int canceledCount}) async {
if (!_isInitialized) await initialize();
if (canceledCount <= 0) return;
+74
View File
@@ -0,0 +1,74 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:spotiflac_android/services/notification_service.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
AndroidFlutterLocalNotificationsPlugin.registerWith();
const channel = MethodChannel('dexterous.com/flutter/local_notifications');
final methodCalls = <MethodCall>[];
setUp(() {
debugDefaultTargetPlatformOverride = TargetPlatform.android;
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, (call) async {
methodCalls.add(call);
if (call.method == 'initialize') return true;
return null;
});
});
tearDown(() {
debugDefaultTargetPlatformOverride = null;
methodCalls.clear();
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(channel, null);
});
test('verification uses a distinct audible Android alert channel', () async {
final notificationService = NotificationService();
await notificationService.showVerificationRequired();
final alertChannelCall = methodCalls.firstWhere(
(call) =>
call.method == 'createNotificationChannel' &&
(call.arguments as Map<Object?, Object?>)['id'] ==
NotificationService.alertChannelId,
);
final alertChannel = alertChannelCall.arguments as Map<Object?, Object?>;
expect(alertChannel['importance'], Importance.defaultImportance.value);
expect(alertChannel['playSound'], isTrue);
expect(alertChannel['enableVibration'], isTrue);
final showCall = methodCalls.lastWhere((call) => call.method == 'show');
final showArguments = showCall.arguments as Map<Object?, Object?>;
final androidDetails =
showArguments['platformSpecifics'] as Map<Object?, Object?>;
expect(
NotificationService.verificationRequiredId,
isNot(NotificationService.downloadProgressId),
);
expect(showArguments['id'], NotificationService.verificationRequiredId);
expect(androidDetails['channelId'], NotificationService.alertChannelId);
expect(androidDetails['importance'], Importance.defaultImportance.value);
expect(androidDetails['playSound'], isTrue);
expect(androidDetails['enableVibration'], isTrue);
await notificationService.cancelVerificationRequired();
expect(
methodCalls.last,
isMethodCall(
'cancel',
arguments: <String, Object?>{
'id': NotificationService.verificationRequiredId,
'tag': null,
},
),
);
});
}