feat(ui): Add restoring & syncing banner

This commit is contained in:
Cuong-Tran 2024-07-05 22:10:09 +07:00 committed by Tran M. Cuong
parent 8c3d99889c
commit 274aefb3b3
7 changed files with 121 additions and 3 deletions

View file

@ -63,6 +63,10 @@ fun AppStateBanners(
downloadedOnlyMode: Boolean,
incognitoMode: Boolean,
indexing: Boolean,
// KMK -->
restoring: Boolean,
syncing: Boolean,
// KMK <--
modifier: Modifier = Modifier,
) {
val density = LocalDensity.current
@ -71,12 +75,21 @@ fun AppStateBanners(
SubcomposeLayout(modifier = modifier) { constraints ->
val indexingPlaceable = subcompose(0) {
AnimatedVisibility(
visible = indexing,
// KMK -->
visible = indexing || restoring || syncing,
// KMK <--
enter = expandVertically(),
exit = shrinkVertically(),
) {
IndexingDownloadBanner(
modifier = Modifier.windowInsetsPadding(mainInsets),
// KMK -->
text = when {
syncing -> stringResource(MR.strings.syncing_library)
restoring -> stringResource(MR.strings.restoring_backup)
else -> stringResource(MR.strings.download_notifier_cache_renewal)
},
// KMK <--
)
}
}.fastMap { it.measure(constraints) }
@ -155,7 +168,12 @@ private fun IncognitoModeBanner(modifier: Modifier = Modifier) {
}
@Composable
private fun IndexingDownloadBanner(modifier: Modifier = Modifier) {
private fun IndexingDownloadBanner(
modifier: Modifier = Modifier,
// KMK -->
text: String = stringResource(MR.strings.download_notifier_cache_renewal),
// KMK <--
) {
val density = LocalDensity.current
Row(
modifier = Modifier
@ -173,7 +191,9 @@ private fun IndexingDownloadBanner(modifier: Modifier = Modifier) {
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(MR.strings.download_notifier_cache_renewal),
// KMK -->
text = text,
// KMK <--
color = MaterialTheme.colorScheme.onSecondary,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.labelMedium,

View file

@ -22,12 +22,18 @@ import logcat.LogPriority
import tachiyomi.core.common.i18n.stringResource
import tachiyomi.core.common.util.system.logcat
import tachiyomi.i18n.MR
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class BackupRestoreJob(private val context: Context, workerParams: WorkerParameters) :
CoroutineWorker(context, workerParams) {
private val notifier = BackupNotifier(context)
// KMK -->
private val backupRestoreStatus: BackupRestoreStatus = Injekt.get()
// KMK <--
override suspend fun doWork(): Result {
val uri = inputData.getString(LOCATION_URI_KEY)?.toUri()
val options = inputData.getBooleanArray(OPTIONS_KEY)?.let { RestoreOptions.fromBooleanArray(it) }
@ -36,6 +42,10 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
return Result.failure()
}
// KMK -->
backupRestoreStatus.start()
// KMK <--
val isSync = inputData.getBoolean(SYNC_KEY, false)
setForegroundSafely()
@ -54,6 +64,9 @@ class BackupRestoreJob(private val context: Context, workerParams: WorkerParamet
}
} finally {
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
// KMK -->
backupRestoreStatus.stop()
// KMK <--
}
}

View file

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.data.backup.restore
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.stateIn
class BackupRestoreStatus {
private val scope = CoroutineScope(Dispatchers.IO)
private val _isRunning = MutableStateFlow(false)
val isRunning = _isRunning
.debounce(1000L) // Don't notify if it finishes quickly enough
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
suspend fun start() {
_isRunning.emit(true)
}
suspend fun stop() {
_isRunning.emit(false)
}
}

View file

@ -29,6 +29,10 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters)
private val notifier = SyncNotifier(context)
// KMK -->
private val syncStatus: SyncStatus = Injekt.get()
// KMK <--
override suspend fun doWork(): Result {
if (tags.contains(TAG_AUTO)) {
// Find a running manual worker. If exists, try again later
@ -37,6 +41,10 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters)
}
}
// KMK -->
syncStatus.start()
// KMK <--
setForegroundSafely()
return try {
@ -48,6 +56,9 @@ class SyncDataJob(private val context: Context, workerParams: WorkerParameters)
Result.success() // try again next time
} finally {
context.cancelNotification(Notifications.ID_RESTORE_PROGRESS)
// KMK -->
syncStatus.stop()
// KMK <--
}
}

View file

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.data.sync
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.stateIn
class SyncStatus {
private val scope = CoroutineScope(Dispatchers.IO)
private val _isRunning = MutableStateFlow(false)
val isRunning = _isRunning
.debounce(1000L) // Don't notify if it finishes quickly enough
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
suspend fun start() {
_isRunning.emit(true)
}
suspend fun stop() {
_isRunning.emit(false)
}
}

View file

@ -10,6 +10,7 @@ import app.cash.sqldelight.driver.android.AndroidSqliteDriver
import eu.kanade.domain.track.store.DelayedTrackingStore
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.core.security.SecurityPreferences
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreStatus
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.cache.PagePreviewCache
@ -17,6 +18,7 @@ import eu.kanade.tachiyomi.data.download.DownloadCache
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadProvider
import eu.kanade.tachiyomi.data.saver.ImageSaver
import eu.kanade.tachiyomi.data.sync.SyncStatus
import eu.kanade.tachiyomi.data.sync.service.GoogleDriveService
import eu.kanade.tachiyomi.data.track.TrackerManager
import eu.kanade.tachiyomi.extension.ExtensionManager
@ -172,6 +174,11 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { PagePreviewCache(app) }
// SY <--
// KMK -->
addSingletonFactory { BackupRestoreStatus() }
addSingletonFactory { SyncStatus() }
// KMK <--
// Asynchronously init expensive components for a faster cold start
ContextCompat.getMainExecutor(app).execute {
get<NetworkHelper>()

View file

@ -61,10 +61,12 @@ import eu.kanade.presentation.more.settings.screen.data.RestoreBackupScreen
import eu.kanade.presentation.util.AssistContentScreen
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.data.backup.restore.BackupRestoreStatus
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.coil.MangaCoverMetadata
import eu.kanade.tachiyomi.data.download.DownloadCache
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.sync.SyncStatus
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
import eu.kanade.tachiyomi.extension.api.ExtensionApi
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
@ -122,6 +124,11 @@ class MainActivity : BaseActivity() {
private val unsortedPreferences: UnsortedPreferences by injectLazy()
// SY <--
// KMK -->
private val backupRestoreStatus: BackupRestoreStatus by injectLazy()
private val syncStatus: SyncStatus by injectLazy()
// KMK <--
private val downloadCache: DownloadCache by injectLazy()
private val chapterCache: ChapterCache by injectLazy()
@ -189,6 +196,10 @@ class MainActivity : BaseActivity() {
val incognito by preferences.incognitoMode().collectAsState()
val downloadOnly by preferences.downloadedOnly().collectAsState()
val indexing by downloadCache.isInitializing.collectAsState()
// KMK -->
val syncing by syncStatus.isRunning.collectAsState()
val restoring by backupRestoreStatus.isRunning.collectAsState()
// KMK <--
// Set status bar color considering the top app state banner
val systemUiController = rememberSystemUiController()
@ -260,6 +271,10 @@ class MainActivity : BaseActivity() {
downloadedOnlyMode = downloadOnly,
incognitoMode = incognito,
indexing = indexing,
// KMK -->
restoring = restoring,
syncing = syncing,
// KMK <--
modifier = Modifier.windowInsetsPadding(scaffoldInsets),
)
},