fix(notification): Prevent duplicate notifications during backup and restore processes (#933)

Avoid calling show() before returning builder for ForegroundInfo
This commit is contained in:
Cuong-Tran 2025-05-27 12:35:57 +07:00 committed by GitHub
parent 46c3f1ef2f
commit 068dc188ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 92 additions and 38 deletions

View file

@ -52,7 +52,7 @@ class BackupNotifier(private val context: Context) {
setAutoCancel(false) setAutoCancel(false)
} }
private fun NotificationCompat.Builder.show(id: Int) { internal fun NotificationCompat.Builder.show(id: Int) {
context.notify(id, build()) context.notify(id, build())
} }
@ -63,7 +63,11 @@ class BackupNotifier(private val context: Context) {
setProgress(0, 0, true) setProgress(0, 0, true)
} }
builder.show(Notifications.ID_BACKUP_PROGRESS) // KMK -->
// Avoid calling show() before returning builder for ForegroundInfo.
// Calling show() here can cause duplicate notifications, as setForegroundSafely will display the notification using the returned builder.
// builder.show(Notifications.ID_BACKUP_PROGRESS)
// KMK <--
return builder return builder
} }
@ -129,7 +133,11 @@ class BackupNotifier(private val context: Context) {
) )
} }
builder.show(Notifications.ID_RESTORE_PROGRESS) // KMK -->
// Avoid calling show() before returning builder for ForegroundInfo.
// Calling show() here can cause duplicate notifications, as setForegroundSafely will display the notification using the returned builder.
// builder.show(Notifications.ID_RESTORE_PROGRESS)
// KMK <--
return builder return builder
} }

View file

@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.backup.restore.restorers.FeedRestorer
import eu.kanade.tachiyomi.data.backup.restore.restorers.MangaRestorer import eu.kanade.tachiyomi.data.backup.restore.restorers.MangaRestorer
import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer
import eu.kanade.tachiyomi.data.backup.restore.restorers.SavedSearchRestorer import eu.kanade.tachiyomi.data.backup.restore.restorers.SavedSearchRestorer
import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.util.system.createFileInCacheDir import eu.kanade.tachiyomi.util.system.createFileInCacheDir
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.coroutineScope
@ -139,12 +140,17 @@ class BackupRestorer(
categoriesRestorer(backupCategories) categoriesRestorer(backupCategories)
restoreProgress += 1 restoreProgress += 1
notifier.showRestoreProgress( with(notifier) {
context.stringResource(MR.strings.categories), showRestoreProgress(
restoreProgress, context.stringResource(MR.strings.categories),
restoreAmount, restoreProgress,
isSync, restoreAmount,
) isSync,
)
// KMK -->
.show(Notifications.ID_RESTORE_PROGRESS)
// KMK <--
}
} }
// SY --> // SY -->
@ -161,12 +167,17 @@ class BackupRestorer(
// KMK <-- // KMK <--
restoreProgress += 1 restoreProgress += 1
notifier.showRestoreProgress( with(notifier) {
context.stringResource(KMR.strings.saved_searches_feeds), showRestoreProgress(
restoreProgress, context.stringResource(KMR.strings.saved_searches_feeds),
restoreAmount, restoreProgress,
isSync, restoreAmount,
) isSync,
)
// KMK -->
.show(Notifications.ID_RESTORE_PROGRESS)
// KMK <--
}
} }
// SY <-- // SY <--
@ -186,7 +197,12 @@ class BackupRestorer(
} }
restoreProgress += 1 restoreProgress += 1
notifier.showRestoreProgress(it.title, restoreProgress, restoreAmount, isSync) with(notifier) {
showRestoreProgress(it.title, restoreProgress, restoreAmount, isSync)
// KMK -->
.show(Notifications.ID_RESTORE_PROGRESS)
// KMK <--
}
} }
} }
@ -201,12 +217,17 @@ class BackupRestorer(
) )
restoreProgress += 1 restoreProgress += 1
notifier.showRestoreProgress( with(notifier) {
context.stringResource(MR.strings.app_settings), showRestoreProgress(
restoreProgress, context.stringResource(MR.strings.app_settings),
restoreAmount, restoreProgress,
isSync, restoreAmount,
) isSync,
)
// KMK -->
.show(Notifications.ID_RESTORE_PROGRESS)
// KMK <--
}
} }
private fun CoroutineScope.restoreSourcePreferences(preferences: List<BackupSourcePreferences>) = launch { private fun CoroutineScope.restoreSourcePreferences(preferences: List<BackupSourcePreferences>) = launch {
@ -214,12 +235,17 @@ class BackupRestorer(
preferenceRestorer.restoreSource(preferences) preferenceRestorer.restoreSource(preferences)
restoreProgress += 1 restoreProgress += 1
notifier.showRestoreProgress( with(notifier) {
context.stringResource(MR.strings.source_settings), showRestoreProgress(
restoreProgress, context.stringResource(MR.strings.source_settings),
restoreAmount, restoreProgress,
isSync, restoreAmount,
) isSync,
)
// KMK -->
.show(Notifications.ID_RESTORE_PROGRESS)
// KMK <--
}
} }
private fun CoroutineScope.restoreExtensionRepos( private fun CoroutineScope.restoreExtensionRepos(
@ -236,12 +262,17 @@ class BackupRestorer(
} }
restoreProgress += 1 restoreProgress += 1
notifier.showRestoreProgress( with(notifier) {
context.stringResource(MR.strings.extensionRepo_settings), showRestoreProgress(
restoreProgress, context.stringResource(MR.strings.extensionRepo_settings),
restoreAmount, restoreProgress,
isSync, restoreAmount,
) isSync,
)
// KMK -->
.show(Notifications.ID_RESTORE_PROGRESS)
// KMK <--
}
} }
} }

View file

@ -74,7 +74,11 @@ class SyncNotifier(private val context: Context) {
) )
} }
builder.show(Notifications.ID_SYNC_PROGRESS) // KMK -->
// Avoid calling show() before returning builder for ForegroundInfo.
// Calling show() here can cause duplicate notifications, as setForegroundSafely will display the notification using the returned builder.
// builder.show(Notifications.ID_SYNC_PROGRESS)
// KMK <--
return builder return builder
} }

View file

@ -124,7 +124,12 @@ class AppUpdateDownloadJob(private val context: Context, workerParams: WorkerPar
*/ */
private suspend fun downloadApk(title: String, url: String) = coroutineScope { private suspend fun downloadApk(title: String, url: String) = coroutineScope {
// Show notification download starting. // Show notification download starting.
notifier.onDownloadStarted(title) with(notifier) {
onDownloadStarted(title)
// KMK -->
.show()
// KMK <--
}
val progressListener = object : ProgressListener { val progressListener = object : ProgressListener {
// KMK --> // KMK -->

View file

@ -32,7 +32,7 @@ internal class AppUpdateNotifier(private val context: Context) {
* *
* @param id id of the notification channel. * @param id id of the notification channel.
*/ */
private fun NotificationCompat.Builder.show(id: Int = Notifications.ID_APP_UPDATER) { internal fun NotificationCompat.Builder.show(id: Int = Notifications.ID_APP_UPDATER) {
context.notify(id, build()) context.notify(id, build())
} }
@ -102,7 +102,13 @@ internal class AppUpdateNotifier(private val context: Context) {
NotificationReceiver.cancelDownloadAppUpdatePendingBroadcast(context), NotificationReceiver.cancelDownloadAppUpdatePendingBroadcast(context),
) )
} }
notificationBuilder.show()
// KMK -->
// Avoid calling show() before returning builder for ForegroundInfo.
// Calling show() here can cause duplicate notifications, as setForegroundSafely will display the notification using the returned builder.
// notificationBuilder.show()
// KMK <--
return notificationBuilder return notificationBuilder
} }