mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	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:
		@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user