feat(ui): Add restoring & syncing banner
This commit is contained in:
parent
8c3d99889c
commit
274aefb3b3
7 changed files with 121 additions and 3 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 <--
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 <--
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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>()
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue