App state banner tweaks (#8746)
* Move download indexing notification to this banner group * Animate state changes
This commit is contained in:
parent
5f4825465e
commit
e20c66b156
@ -1,28 +1,45 @@
|
|||||||
package eu.kanade.presentation.components
|
package eu.kanade.presentation.components
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.expandVertically
|
||||||
|
import androidx.compose.animation.shrinkVertically
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.only
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.requiredSize
|
||||||
|
import androidx.compose.foundation.layout.statusBars
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.layout.SubcomposeLayout
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.util.fastForEach
|
||||||
|
import androidx.compose.ui.util.fastMap
|
||||||
|
import androidx.compose.ui.util.fastMaxBy
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
val DownloadedOnlyBannerBackgroundColor
|
val DownloadedOnlyBannerBackgroundColor
|
||||||
@Composable get() = MaterialTheme.colorScheme.tertiary
|
@Composable get() = MaterialTheme.colorScheme.tertiary
|
||||||
val IncognitoModeBannerBackgroundColor
|
val IncognitoModeBannerBackgroundColor
|
||||||
@Composable get() = MaterialTheme.colorScheme.primary
|
@Composable get() = MaterialTheme.colorScheme.primary
|
||||||
|
val IndexingBannerBackgroundColor
|
||||||
|
@Composable get() = MaterialTheme.colorScheme.secondary
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WarningBanner(
|
fun WarningBanner(
|
||||||
@ -45,23 +62,64 @@ fun WarningBanner(
|
|||||||
fun AppStateBanners(
|
fun AppStateBanners(
|
||||||
downloadedOnlyMode: Boolean,
|
downloadedOnlyMode: Boolean,
|
||||||
incognitoMode: Boolean,
|
incognitoMode: Boolean,
|
||||||
|
indexing: Boolean,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val insets = WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)
|
val density = LocalDensity.current
|
||||||
Column(modifier = modifier) {
|
val mainInsets = WindowInsets.statusBars
|
||||||
if (downloadedOnlyMode) {
|
val mainInsetsTop = mainInsets.getTop(density)
|
||||||
DownloadedOnlyModeBanner(
|
SubcomposeLayout(modifier = modifier) { constraints ->
|
||||||
modifier = Modifier.windowInsetsPadding(insets),
|
val indexingPlaceable = subcompose(0) {
|
||||||
)
|
AnimatedVisibility(
|
||||||
}
|
visible = indexing,
|
||||||
if (incognitoMode) {
|
enter = expandVertically(),
|
||||||
IncognitoModeBanner(
|
exit = shrinkVertically(),
|
||||||
modifier = if (!downloadedOnlyMode) {
|
) {
|
||||||
Modifier.windowInsetsPadding(insets)
|
IndexingDownloadBanner(
|
||||||
} else {
|
modifier = Modifier.windowInsetsPadding(mainInsets),
|
||||||
Modifier
|
)
|
||||||
},
|
}
|
||||||
)
|
}.fastMap { it.measure(constraints) }
|
||||||
|
val indexingHeight = indexingPlaceable.fastMaxBy { it.height }?.height ?: 0
|
||||||
|
|
||||||
|
val downloadedOnlyPlaceable = subcompose(1) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = downloadedOnlyMode,
|
||||||
|
enter = expandVertically(),
|
||||||
|
exit = shrinkVertically(),
|
||||||
|
) {
|
||||||
|
val top = (mainInsetsTop - indexingHeight).coerceAtLeast(0)
|
||||||
|
DownloadedOnlyModeBanner(
|
||||||
|
modifier = Modifier.windowInsetsPadding(WindowInsets(top = top)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.fastMap { it.measure(constraints) }
|
||||||
|
val downloadedOnlyHeight = downloadedOnlyPlaceable.fastMaxBy { it.height }?.height ?: 0
|
||||||
|
|
||||||
|
val incognitoPlaceable = subcompose(2) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = incognitoMode,
|
||||||
|
enter = expandVertically(),
|
||||||
|
exit = shrinkVertically(),
|
||||||
|
) {
|
||||||
|
val top = (mainInsetsTop - indexingHeight - downloadedOnlyHeight).coerceAtLeast(0)
|
||||||
|
IncognitoModeBanner(
|
||||||
|
modifier = Modifier.windowInsetsPadding(WindowInsets(top = top)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.fastMap { it.measure(constraints) }
|
||||||
|
val incognitoHeight = incognitoPlaceable.fastMaxBy { it.height }?.height ?: 0
|
||||||
|
|
||||||
|
layout(constraints.maxWidth, indexingHeight + downloadedOnlyHeight + incognitoHeight) {
|
||||||
|
indexingPlaceable.fastForEach {
|
||||||
|
it.place(0, 0)
|
||||||
|
}
|
||||||
|
downloadedOnlyPlaceable.fastForEach {
|
||||||
|
it.place(0, indexingHeight)
|
||||||
|
}
|
||||||
|
incognitoPlaceable.fastForEach {
|
||||||
|
it.place(0, indexingHeight + downloadedOnlyHeight)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,3 +153,35 @@ private fun IncognitoModeBanner(modifier: Modifier = Modifier) {
|
|||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun IndexingDownloadBanner(modifier: Modifier = Modifier) {
|
||||||
|
val density = LocalDensity.current
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(color = IndexingBannerBackgroundColor)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(8.dp)
|
||||||
|
.then(modifier),
|
||||||
|
horizontalArrangement = Arrangement.Center,
|
||||||
|
) {
|
||||||
|
var textHeight by remember { mutableStateOf(0.dp) }
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier.requiredSize(textHeight),
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary,
|
||||||
|
strokeWidth = textHeight / 8,
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.download_notifier_cache_renewal),
|
||||||
|
color = MaterialTheme.colorScheme.onSecondary,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
onTextLayout = {
|
||||||
|
with(density) {
|
||||||
|
textHeight = it.size.height.toDp()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,11 +20,14 @@ import kotlinx.coroutines.awaitAll
|
|||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.shareIn
|
import kotlinx.coroutines.flow.shareIn
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.withTimeout
|
import kotlinx.coroutines.withTimeout
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
@ -53,8 +56,6 @@ class DownloadCache(
|
|||||||
.onStart { emit(Unit) }
|
.onStart { emit(Unit) }
|
||||||
.shareIn(scope, SharingStarted.Eagerly, 1)
|
.shareIn(scope, SharingStarted.Eagerly, 1)
|
||||||
|
|
||||||
private val notifier by lazy { DownloadNotifier(context) }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The interval after which this cache should be invalidated. 1 hour shouldn't cause major
|
* The interval after which this cache should be invalidated. 1 hour shouldn't cause major
|
||||||
* issues, as the cache is only used for UI feedback.
|
* issues, as the cache is only used for UI feedback.
|
||||||
@ -66,6 +67,10 @@ class DownloadCache(
|
|||||||
*/
|
*/
|
||||||
private var lastRenew = 0L
|
private var lastRenew = 0L
|
||||||
private var renewalJob: Job? = null
|
private var renewalJob: Job? = null
|
||||||
|
val isRenewing = changes
|
||||||
|
.map { renewalJob?.isActive ?: false }
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
|
||||||
|
|
||||||
private var rootDownloadsDir = RootDirectory(getDirectoryFromPreference())
|
private var rootDownloadsDir = RootDirectory(getDirectoryFromPreference())
|
||||||
|
|
||||||
@ -260,8 +265,6 @@ class DownloadCache(
|
|||||||
}
|
}
|
||||||
|
|
||||||
renewalJob = scope.launchIO {
|
renewalJob = scope.launchIO {
|
||||||
notifier.onCacheProgress()
|
|
||||||
|
|
||||||
var sources = getSources()
|
var sources = getSources()
|
||||||
|
|
||||||
// Try to wait until extensions and sources have loaded
|
// Try to wait until extensions and sources have loaded
|
||||||
@ -320,7 +323,6 @@ class DownloadCache(
|
|||||||
lastRenew = System.currentTimeMillis()
|
lastRenew = System.currentTimeMillis()
|
||||||
notifyChanges()
|
notifyChanges()
|
||||||
}
|
}
|
||||||
renewalJob?.invokeOnCompletion { notifier.dismissCacheProgress() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSources(): List<Source> {
|
private fun getSources(): List<Source> {
|
||||||
|
@ -39,17 +39,6 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val cacheNotificationBuilder by lazy {
|
|
||||||
context.notificationBuilder(Notifications.CHANNEL_DOWNLOADER_CACHE) {
|
|
||||||
setSmallIcon(R.drawable.ic_tachi)
|
|
||||||
setContentTitle(context.getString(R.string.download_notifier_cache_renewal))
|
|
||||||
setProgress(100, 100, true)
|
|
||||||
setOngoing(true)
|
|
||||||
setAutoCancel(false)
|
|
||||||
setOnlyAlertOnce(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status of download. Used for correct notification icon.
|
* Status of download. Used for correct notification icon.
|
||||||
*/
|
*/
|
||||||
@ -223,14 +212,4 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
errorThrown = true
|
errorThrown = true
|
||||||
isDownloading = false
|
isDownloading = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onCacheProgress() {
|
|
||||||
with(cacheNotificationBuilder) {
|
|
||||||
show(Notifications.ID_DOWNLOAD_CACHE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dismissCacheProgress() {
|
|
||||||
context.notificationManager.cancel(Notifications.ID_DOWNLOAD_CACHE)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,6 @@ object Notifications {
|
|||||||
const val ID_DOWNLOAD_CHAPTER_PROGRESS = -201
|
const val ID_DOWNLOAD_CHAPTER_PROGRESS = -201
|
||||||
const val CHANNEL_DOWNLOADER_ERROR = "downloader_error_channel"
|
const val CHANNEL_DOWNLOADER_ERROR = "downloader_error_channel"
|
||||||
const val ID_DOWNLOAD_CHAPTER_ERROR = -202
|
const val ID_DOWNLOAD_CHAPTER_ERROR = -202
|
||||||
const val CHANNEL_DOWNLOADER_CACHE = "downloader_cache_renewal"
|
|
||||||
const val ID_DOWNLOAD_CACHE = -204
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notification channel and ids used by the library updater.
|
* Notification channel and ids used by the library updater.
|
||||||
@ -91,6 +89,7 @@ object Notifications {
|
|||||||
"library_channel",
|
"library_channel",
|
||||||
"library_progress_channel",
|
"library_progress_channel",
|
||||||
"updates_ext_channel",
|
"updates_ext_channel",
|
||||||
|
"downloader_cache_renewal",
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,12 +154,6 @@ object Notifications {
|
|||||||
setGroup(GROUP_DOWNLOADER)
|
setGroup(GROUP_DOWNLOADER)
|
||||||
setShowBadge(false)
|
setShowBadge(false)
|
||||||
},
|
},
|
||||||
buildNotificationChannel(CHANNEL_DOWNLOADER_CACHE, IMPORTANCE_LOW) {
|
|
||||||
setName(context.getString(R.string.channel_downloader_cache))
|
|
||||||
setGroup(GROUP_DOWNLOADER)
|
|
||||||
setShowBadge(false)
|
|
||||||
setSound(null, null)
|
|
||||||
},
|
|
||||||
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_PROGRESS, IMPORTANCE_LOW) {
|
buildNotificationChannel(CHANNEL_BACKUP_RESTORE_PROGRESS, IMPORTANCE_LOW) {
|
||||||
setName(context.getString(R.string.channel_progress))
|
setName(context.getString(R.string.channel_progress))
|
||||||
setGroup(GROUP_BACKUP_RESTORE)
|
setGroup(GROUP_BACKUP_RESTORE)
|
||||||
|
@ -12,10 +12,13 @@ import android.widget.Toast
|
|||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||||
import androidx.compose.foundation.layout.statusBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
|
import androidx.compose.foundation.layout.only
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@ -23,6 +26,7 @@ import androidx.compose.material3.TextButton
|
|||||||
import androidx.compose.material3.surfaceColorAtElevation
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@ -54,6 +58,8 @@ import eu.kanade.domain.ui.UiPreferences
|
|||||||
import eu.kanade.presentation.components.AppStateBanners
|
import eu.kanade.presentation.components.AppStateBanners
|
||||||
import eu.kanade.presentation.components.DownloadedOnlyBannerBackgroundColor
|
import eu.kanade.presentation.components.DownloadedOnlyBannerBackgroundColor
|
||||||
import eu.kanade.presentation.components.IncognitoModeBannerBackgroundColor
|
import eu.kanade.presentation.components.IncognitoModeBannerBackgroundColor
|
||||||
|
import eu.kanade.presentation.components.IndexingBannerBackgroundColor
|
||||||
|
import eu.kanade.presentation.components.Scaffold
|
||||||
import eu.kanade.presentation.util.AssistContentScreen
|
import eu.kanade.presentation.util.AssistContentScreen
|
||||||
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
import eu.kanade.presentation.util.DefaultNavigatorScreenTransition
|
||||||
import eu.kanade.presentation.util.collectAsState
|
import eu.kanade.presentation.util.collectAsState
|
||||||
@ -61,6 +67,7 @@ import eu.kanade.tachiyomi.BuildConfig
|
|||||||
import eu.kanade.tachiyomi.Migrations
|
import eu.kanade.tachiyomi.Migrations
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
import eu.kanade.tachiyomi.data.cache.ChapterCache
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadCache
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
|
import eu.kanade.tachiyomi.data.updater.AppUpdateChecker
|
||||||
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
|
import eu.kanade.tachiyomi.data.updater.AppUpdateResult
|
||||||
@ -101,6 +108,7 @@ class MainActivity : BaseActivity() {
|
|||||||
private val preferences: BasePreferences by injectLazy()
|
private val preferences: BasePreferences by injectLazy()
|
||||||
|
|
||||||
private val chapterCache: ChapterCache by injectLazy()
|
private val chapterCache: ChapterCache by injectLazy()
|
||||||
|
private val downloadCache: DownloadCache by injectLazy()
|
||||||
|
|
||||||
// To be checked by splash screen. If true then splash screen will be removed.
|
// To be checked by splash screen. If true then splash screen will be removed.
|
||||||
var ready = false
|
var ready = false
|
||||||
@ -153,94 +161,102 @@ class MainActivity : BaseActivity() {
|
|||||||
setComposeContent {
|
setComposeContent {
|
||||||
val incognito by preferences.incognitoMode().collectAsState()
|
val incognito by preferences.incognitoMode().collectAsState()
|
||||||
val downloadOnly by preferences.downloadedOnly().collectAsState()
|
val downloadOnly by preferences.downloadedOnly().collectAsState()
|
||||||
Column {
|
val indexing by downloadCache.isRenewing.collectAsState()
|
||||||
AppStateBanners(
|
|
||||||
downloadedOnlyMode = downloadOnly,
|
// Set statusbar color considering the top app state banner
|
||||||
incognitoMode = incognito,
|
val systemUiController = rememberSystemUiController()
|
||||||
|
val isSystemInDarkTheme = isSystemInDarkTheme()
|
||||||
|
val statusBarBackgroundColor = when {
|
||||||
|
indexing -> IndexingBannerBackgroundColor
|
||||||
|
downloadOnly -> DownloadedOnlyBannerBackgroundColor
|
||||||
|
incognito -> IncognitoModeBannerBackgroundColor
|
||||||
|
else -> MaterialTheme.colorScheme.surface
|
||||||
|
}
|
||||||
|
LaunchedEffect(systemUiController, statusBarBackgroundColor) {
|
||||||
|
systemUiController.setStatusBarColor(
|
||||||
|
color = ComposeColor.Transparent,
|
||||||
|
darkIcons = statusBarBackgroundColor.luminance() > 0.5,
|
||||||
|
transformColorForLightContent = { ComposeColor.Black },
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Set statusbar color
|
// Set navigation bar color
|
||||||
val systemUiController = rememberSystemUiController()
|
val context = LocalContext.current
|
||||||
val isSystemInDarkTheme = isSystemInDarkTheme()
|
val navbarScrimColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp)
|
||||||
val statusBarBackgroundColor = when {
|
LaunchedEffect(systemUiController, isSystemInDarkTheme, navbarScrimColor) {
|
||||||
downloadOnly -> DownloadedOnlyBannerBackgroundColor
|
systemUiController.setNavigationBarColor(
|
||||||
incognito -> IncognitoModeBannerBackgroundColor
|
color = if (context.isNavigationBarNeedsScrim()) {
|
||||||
else -> MaterialTheme.colorScheme.background
|
navbarScrimColor.copy(alpha = 0.7f)
|
||||||
}
|
|
||||||
LaunchedEffect(systemUiController, statusBarBackgroundColor) {
|
|
||||||
systemUiController.setStatusBarColor(
|
|
||||||
color = ComposeColor.Transparent,
|
|
||||||
darkIcons = statusBarBackgroundColor.luminance() > 0.5,
|
|
||||||
transformColorForLightContent = { ComposeColor.Black },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set navigation bar color
|
|
||||||
val context = LocalContext.current
|
|
||||||
val navbarScrimColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp)
|
|
||||||
LaunchedEffect(systemUiController, isSystemInDarkTheme, navbarScrimColor) {
|
|
||||||
systemUiController.setNavigationBarColor(
|
|
||||||
color = if (context.isNavigationBarNeedsScrim()) {
|
|
||||||
navbarScrimColor.copy(alpha = 0.7f)
|
|
||||||
} else {
|
|
||||||
ComposeColor.Transparent
|
|
||||||
},
|
|
||||||
darkIcons = !isSystemInDarkTheme,
|
|
||||||
navigationBarContrastEnforced = false,
|
|
||||||
transformColorForLightContent = { ComposeColor.Black },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Navigator(
|
|
||||||
screen = HomeScreen,
|
|
||||||
disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true),
|
|
||||||
) { navigator ->
|
|
||||||
if (navigator.size == 1) {
|
|
||||||
ConfirmExit()
|
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(navigator) {
|
|
||||||
this@MainActivity.navigator = navigator
|
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
|
||||||
// Set start screen
|
|
||||||
handleIntentAction(intent)
|
|
||||||
|
|
||||||
// Reset Incognito Mode on relaunch
|
|
||||||
preferences.incognitoMode().set(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume insets already used by app state banners
|
|
||||||
val boxModifier = if (incognito || downloadOnly) {
|
|
||||||
Modifier.consumeWindowInsets(WindowInsets.statusBars)
|
|
||||||
} else {
|
} else {
|
||||||
Modifier
|
ComposeColor.Transparent
|
||||||
|
},
|
||||||
|
darkIcons = !isSystemInDarkTheme,
|
||||||
|
navigationBarContrastEnforced = false,
|
||||||
|
transformColorForLightContent = { ComposeColor.Black },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Navigator(
|
||||||
|
screen = HomeScreen,
|
||||||
|
disposeBehavior = NavigatorDisposeBehavior(disposeNestedNavigators = false, disposeSteps = true),
|
||||||
|
) { navigator ->
|
||||||
|
if (navigator.size == 1) {
|
||||||
|
ConfirmExit()
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(navigator) {
|
||||||
|
this@MainActivity.navigator = navigator
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
// Set start screen
|
||||||
|
handleIntentAction(intent)
|
||||||
|
|
||||||
|
// Reset Incognito Mode on relaunch
|
||||||
|
preferences.incognitoMode().set(false)
|
||||||
}
|
}
|
||||||
Box(modifier = boxModifier) {
|
}
|
||||||
|
|
||||||
|
val scaffoldInsets = WindowInsets.navigationBars.only(WindowInsetsSides.Horizontal)
|
||||||
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
AppStateBanners(
|
||||||
|
downloadedOnlyMode = downloadOnly,
|
||||||
|
incognitoMode = incognito,
|
||||||
|
indexing = indexing,
|
||||||
|
modifier = Modifier.windowInsetsPadding(scaffoldInsets),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
contentWindowInsets = scaffoldInsets,
|
||||||
|
) { contentPadding ->
|
||||||
|
// Consume insets already used by app state banners
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(contentPadding)
|
||||||
|
.consumeWindowInsets(contentPadding),
|
||||||
|
) {
|
||||||
// Shows current screen
|
// Shows current screen
|
||||||
DefaultNavigatorScreenTransition(navigator = navigator)
|
DefaultNavigatorScreenTransition(navigator = navigator)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pop source-related screens when incognito mode is turned off
|
// Pop source-related screens when incognito mode is turned off
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
preferences.incognitoMode().changes()
|
preferences.incognitoMode().changes()
|
||||||
.drop(1)
|
.drop(1)
|
||||||
.onEach {
|
.onEach {
|
||||||
if (!it) {
|
if (!it) {
|
||||||
val currentScreen = navigator.lastItem
|
val currentScreen = navigator.lastItem
|
||||||
if (currentScreen is BrowseSourceScreen ||
|
if (currentScreen is BrowseSourceScreen ||
|
||||||
(currentScreen is MangaScreen && currentScreen.fromSource)
|
(currentScreen is MangaScreen && currentScreen.fromSource)
|
||||||
) {
|
) {
|
||||||
navigator.popUntilRoot()
|
navigator.popUntilRoot()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(this)
|
}
|
||||||
}
|
.launchIn(this)
|
||||||
|
|
||||||
CheckForUpdate()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckForUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) }
|
var showChangelog by remember { mutableStateOf(didMigration && !BuildConfig.DEBUG) }
|
||||||
|
Loading…
Reference in New Issue
Block a user