Reimplement appbar color overlay on scroll (#7663)

only on updates and history screen for now, but the required changes on app bar
is there.

also fix missing incognito-downloaded mode indicator on history screen
This commit is contained in:
Ivan Iskandar 2022-08-01 09:24:19 +07:00 committed by GitHub
parent 322f3a07e8
commit 737cf9898d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 44 deletions

View File

@ -2,11 +2,7 @@ package eu.kanade.presentation.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.Close
@ -18,6 +14,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
@ -51,19 +48,63 @@ fun AppBar(
// Banners
downloadedOnlyMode: Boolean = false,
incognitoMode: Boolean = false,
scrollBehavior: TopAppBarScrollBehavior? = null,
) {
val isActionMode by derivedStateOf { actionModeCounter > 0 }
val backgroundColor = if (isActionMode) {
TopAppBarDefaults.smallTopAppBarColors().containerColor(1f).value
} else {
MaterialTheme.colorScheme.surface
}
AppBar(
modifier = modifier,
titleContent = {
if (isActionMode) {
AppBarTitle(actionModeCounter.toString())
} else {
AppBarTitle(title, subtitle)
}
},
navigateUp = navigateUp,
navigationIcon = navigationIcon,
actions = {
if (isActionMode) {
actionModeActions()
} else {
actions()
}
},
isActionMode = isActionMode,
onCancelActionMode = onCancelActionMode,
downloadedOnlyMode = downloadedOnlyMode,
incognitoMode = incognitoMode,
scrollBehavior = scrollBehavior,
)
}
@Composable
fun AppBar(
modifier: Modifier = Modifier,
// Title
titleContent: @Composable () -> Unit,
// Up button
navigateUp: (() -> Unit)? = null,
navigationIcon: ImageVector = Icons.Default.ArrowBack,
// Menu
actions: @Composable RowScope.() -> Unit = {},
// Action mode
isActionMode: Boolean,
onCancelActionMode: () -> Unit = {},
// Banners
downloadedOnlyMode: Boolean = false,
incognitoMode: Boolean = false,
scrollBehavior: TopAppBarScrollBehavior? = null,
) {
val scrollFraction = if (isActionMode) 1f else scrollBehavior?.state?.overlappedFraction ?: 0f
val backgroundColor by TopAppBarDefaults.smallTopAppBarColors().containerColor(scrollFraction)
Column(
modifier = modifier.drawBehind { drawRect(backgroundColor) },
) {
SmallTopAppBar(
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top)),
modifier = Modifier.statusBarsPadding(),
navigationIcon = {
if (isActionMode) {
IconButton(onClick = onCancelActionMode) {
@ -83,25 +124,14 @@ fun AppBar(
}
}
},
title = {
if (isActionMode) {
AppBarTitle(actionModeCounter.toString())
} else {
AppBarTitle(title, subtitle)
}
},
actions = {
if (isActionMode) {
actionModeActions()
} else {
actions()
}
},
title = titleContent,
actions = actions,
// Background handled by parent
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = Color.Transparent,
scrolledContainerColor = Color.Transparent,
),
scrollBehavior = scrollBehavior,
)
if (downloadedOnlyMode) {

View File

@ -1,10 +1,18 @@
package eu.kanade.presentation.history
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.asPaddingValues
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.paging.LoadState
import eu.kanade.domain.history.model.HistoryWithRelations
@ -30,10 +38,21 @@ fun HistoryScreen(
onClickResume: (HistoryWithRelations) -> Unit,
) {
val context = LocalContext.current
val insetPaddingValue = WindowInsets.navigationBars
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
.asPaddingValues()
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
Scaffold(
modifier = Modifier.safeDrawingPadding(),
modifier = Modifier
.padding(insetPaddingValue)
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
HistoryToolbar(state = presenter)
HistoryToolbar(
state = presenter,
incognitoMode = presenter.isIncognitoMode,
downloadedOnlyMode = presenter.isDownloadOnly,
scrollBehavior = scrollBehavior,
)
},
) { contentPadding ->
val items = presenter.getLazyHistory()

View File

@ -9,8 +9,7 @@ import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
@ -19,6 +18,7 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.stringResource
import eu.kanade.presentation.components.AppBar
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
import eu.kanade.tachiyomi.ui.recent.history.HistoryState
@ -27,17 +27,25 @@ import kotlinx.coroutines.delay
@Composable
fun HistoryToolbar(
state: HistoryState,
scrollBehavior: TopAppBarScrollBehavior,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
) {
if (state.searchQuery == null) {
HistoryRegularToolbar(
onClickSearch = { state.searchQuery = "" },
onClickDelete = { state.dialog = HistoryPresenter.Dialog.DeleteAll },
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
scrollBehavior = scrollBehavior,
)
} else {
HistorySearchToolbar(
searchQuery = state.searchQuery!!,
onChangeSearchQuery = { state.searchQuery = it },
onClickCloseSearch = { state.searchQuery = null },
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
)
}
}
@ -46,11 +54,12 @@ fun HistoryToolbar(
fun HistoryRegularToolbar(
onClickSearch: () -> Unit,
onClickDelete: () -> Unit,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
scrollBehavior: TopAppBarScrollBehavior,
) {
SmallTopAppBar(
title = {
Text(text = stringResource(id = R.string.history))
},
AppBar(
title = stringResource(id = R.string.history),
actions = {
IconButton(onClick = onClickSearch) {
Icon(Icons.Outlined.Search, contentDescription = "search")
@ -59,6 +68,9 @@ fun HistoryRegularToolbar(
Icon(Icons.Outlined.DeleteSweep, contentDescription = "delete")
}
},
downloadedOnlyMode = downloadedOnlyMode,
incognitoMode = incognitoMode,
scrollBehavior = scrollBehavior,
)
}
@ -67,15 +79,12 @@ fun HistorySearchToolbar(
searchQuery: String,
onChangeSearchQuery: (String) -> Unit,
onClickCloseSearch: () -> Unit,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
) {
val focusRequester = remember { FocusRequester.Default }
SmallTopAppBar(
navigationIcon = {
IconButton(onClick = onClickCloseSearch) {
Icon(Icons.Outlined.ArrowBack, contentDescription = "delete")
}
},
title = {
AppBar(
titleContent = {
BasicTextField(
value = searchQuery,
onValueChange = onChangeSearchQuery,
@ -87,6 +96,11 @@ fun HistorySearchToolbar(
cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground),
)
},
navigationIcon = Icons.Outlined.ArrowBack,
navigateUp = onClickCloseSearch,
isActionMode = false,
downloadedOnlyMode = downloadedOnlyMode,
incognitoMode = incognitoMode,
)
LaunchedEffect(focusRequester) {
// TODO: https://issuetracker.google.com/issues/204502668

View File

@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBars
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
@ -20,9 +19,13 @@ import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material.icons.filled.SelectAll
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.res.stringResource
@ -57,7 +60,9 @@ fun UpdateScreen(
onDownloadChapter: (List<UpdatesItem>, ChapterDownloadAction) -> Unit,
) {
val updatesListState = rememberLazyListState()
val insetPaddingValue = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues()
val insetPaddingValue = WindowInsets.navigationBars
.only(WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom)
.asPaddingValues()
val internalOnBackPressed = {
if (presenter.selectionMode) {
@ -76,9 +81,11 @@ fun UpdateScreen(
}
}
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
Scaffold(
modifier = Modifier
.padding(insetPaddingValue),
.padding(insetPaddingValue)
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
UpdatesAppBar(
incognitoMode = presenter.isIncognitoMode,
@ -88,6 +95,7 @@ fun UpdateScreen(
onSelectAll = { presenter.toggleAllSelection(true) },
onInvertSelection = { presenter.invertSelection() },
onCancelActionMode = { presenter.toggleAllSelection(false) },
scrollBehavior = scrollBehavior,
)
},
bottomBar = {
@ -185,6 +193,7 @@ fun UpdatesAppBar(
onSelectAll: () -> Unit,
onInvertSelection: () -> Unit,
onCancelActionMode: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior,
) {
AppBar(
modifier = modifier,
@ -215,6 +224,7 @@ fun UpdatesAppBar(
},
downloadedOnlyMode = downloadedOnlyMode,
incognitoMode = incognitoMode,
scrollBehavior = scrollBehavior,
)
}

View File

@ -22,6 +22,7 @@ import eu.kanade.domain.history.interactor.RemoveHistoryByMangaId
import eu.kanade.domain.history.model.HistoryWithRelations
import eu.kanade.presentation.history.HistoryUiModel
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.launchUI
@ -45,11 +46,16 @@ class HistoryPresenter(
private val deleteHistoryTable: DeleteHistoryTable = Injekt.get(),
private val removeHistoryById: RemoveHistoryById = Injekt.get(),
private val removeHistoryByMangaId: RemoveHistoryByMangaId = Injekt.get(),
preferences: PreferencesHelper = Injekt.get(),
) : BasePresenter<HistoryController>(), HistoryState by state {
private val _events: Channel<Event> = Channel(Int.MAX_VALUE)
val events: Flow<Event> = _events.receiveAsFlow()
val isDownloadOnly: Boolean by preferences.downloadedOnly().asState()
val isIncognitoMode: Boolean by preferences.incognitoMode().asState()
@Composable
fun getLazyHistory(): LazyPagingItems<HistoryUiModel> {
val scope = rememberCoroutineScope()