mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +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