Refactor search toolbar and fix browse source (#8360)

This commit is contained in:
stevenyomi 2022-10-31 01:34:47 +08:00 committed by GitHub
parent 86c3d8c064
commit a078f1ab1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 104 additions and 236 deletions

View File

@ -6,12 +6,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems
import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.manga.model.Manga
import eu.kanade.presentation.browse.components.BrowseSourceSearchToolbar
import eu.kanade.presentation.components.Scaffold import eu.kanade.presentation.components.Scaffold
import eu.kanade.tachiyomi.R import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter
import eu.kanade.tachiyomi.ui.more.MoreController import eu.kanade.tachiyomi.ui.more.MoreController
@ -38,13 +36,11 @@ fun SourceSearchScreen(
Scaffold( Scaffold(
topBar = { scrollBehavior -> topBar = { scrollBehavior ->
BrowseSourceSearchToolbar( SearchToolbar(
searchQuery = presenter.searchQuery ?: "", searchQuery = presenter.searchQuery ?: "",
onSearchQueryChanged = { presenter.searchQuery = it }, onChangeSearchQuery = { presenter.searchQuery = it },
placeholderText = stringResource(R.string.action_search_hint), onClickCloseSearch = navigateUp,
navigateUp = navigateUp, onSearch = { presenter.search(it) },
onResetClick = { presenter.searchQuery = "" },
onSearchClick = { presenter.search(it) },
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
) )
}, },

View File

@ -1,13 +1,10 @@
package eu.kanade.presentation.browse.components package eu.kanade.presentation.browse.components
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ViewList import androidx.compose.material.icons.filled.ViewList
import androidx.compose.material.icons.filled.ViewModule import androidx.compose.material.icons.filled.ViewModule
import androidx.compose.material.icons.outlined.Help import androidx.compose.material.icons.outlined.Help
import androidx.compose.material.icons.outlined.Public import androidx.compose.material.icons.outlined.Public
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -15,14 +12,12 @@ 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
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import eu.kanade.domain.library.model.LibraryDisplayMode import eu.kanade.domain.library.model.LibraryDisplayMode
import eu.kanade.presentation.browse.BrowseSourceState import eu.kanade.presentation.browse.BrowseSourceState
import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.AppBarTitle
import eu.kanade.presentation.components.DropdownMenu import eu.kanade.presentation.components.DropdownMenu
import eu.kanade.presentation.components.RadioMenuItem import eu.kanade.presentation.components.RadioMenuItem
import eu.kanade.presentation.components.SearchToolbar import eu.kanade.presentation.components.SearchToolbar
@ -42,59 +37,21 @@ fun BrowseSourceToolbar(
onSearch: (String) -> Unit, onSearch: (String) -> Unit,
scrollBehavior: TopAppBarScrollBehavior? = null, scrollBehavior: TopAppBarScrollBehavior? = null,
) { ) {
if (state.searchQuery == null) { // Avoid capturing unstable source in actions lambda
BrowseSourceRegularToolbar( val title = source?.name
title = if (state.isUserQuery) state.currentFilter.query else source?.name.orEmpty(), val isLocalSource = source is LocalSource
isLocalSource = source is LocalSource,
displayMode = displayMode,
onDisplayModeChange = onDisplayModeChange,
navigateUp = navigateUp,
onSearchClick = { state.searchQuery = if (state.isUserQuery) state.currentFilter.query else "" },
onWebViewClick = onWebViewClick,
onHelpClick = onHelpClick,
scrollBehavior = scrollBehavior,
)
} else {
val cancelSearch = { state.searchQuery = null }
BrowseSourceSearchToolbar(
searchQuery = state.searchQuery!!,
onSearchQueryChanged = { state.searchQuery = it },
placeholderText = stringResource(R.string.action_search_hint),
navigateUp = cancelSearch,
onResetClick = { state.searchQuery = "" },
onSearchClick = {
onSearch(it)
cancelSearch()
},
scrollBehavior = scrollBehavior,
)
}
}
@Composable SearchToolbar(
fun BrowseSourceRegularToolbar(
title: String,
isLocalSource: Boolean,
displayMode: LibraryDisplayMode,
onDisplayModeChange: (LibraryDisplayMode) -> Unit,
navigateUp: () -> Unit,
onSearchClick: () -> Unit,
onWebViewClick: () -> Unit,
onHelpClick: () -> Unit,
scrollBehavior: TopAppBarScrollBehavior?,
) {
AppBar(
navigateUp = navigateUp, navigateUp = navigateUp,
title = title, titleContent = { AppBarTitle(title) },
searchQuery = state.searchQuery,
onChangeSearchQuery = { state.searchQuery = it },
onSearch = onSearch,
onClickCloseSearch = navigateUp,
actions = { actions = {
var selectingDisplayMode by remember { mutableStateOf(false) } var selectingDisplayMode by remember { mutableStateOf(false) }
AppBarActions( AppBarActions(
actions = listOf( actions = listOf(
AppBar.Action(
title = stringResource(R.string.action_search),
icon = Icons.Outlined.Search,
onClick = onSearchClick,
),
AppBar.Action( AppBar.Action(
title = stringResource(R.string.action_display_mode), title = stringResource(R.string.action_display_mode),
icon = if (displayMode == LibraryDisplayMode.List) Icons.Filled.ViewList else Icons.Filled.ViewModule, icon = if (displayMode == LibraryDisplayMode.List) Icons.Filled.ViewList else Icons.Filled.ViewModule,
@ -123,18 +80,21 @@ fun BrowseSourceRegularToolbar(
text = { Text(text = stringResource(R.string.action_display_comfortable_grid)) }, text = { Text(text = stringResource(R.string.action_display_comfortable_grid)) },
isChecked = displayMode == LibraryDisplayMode.ComfortableGrid, isChecked = displayMode == LibraryDisplayMode.ComfortableGrid,
) { ) {
selectingDisplayMode = false
onDisplayModeChange(LibraryDisplayMode.ComfortableGrid) onDisplayModeChange(LibraryDisplayMode.ComfortableGrid)
} }
RadioMenuItem( RadioMenuItem(
text = { Text(text = stringResource(R.string.action_display_grid)) }, text = { Text(text = stringResource(R.string.action_display_grid)) },
isChecked = displayMode == LibraryDisplayMode.CompactGrid, isChecked = displayMode == LibraryDisplayMode.CompactGrid,
) { ) {
selectingDisplayMode = false
onDisplayModeChange(LibraryDisplayMode.CompactGrid) onDisplayModeChange(LibraryDisplayMode.CompactGrid)
} }
RadioMenuItem( RadioMenuItem(
text = { Text(text = stringResource(R.string.action_display_list)) }, text = { Text(text = stringResource(R.string.action_display_list)) },
isChecked = displayMode == LibraryDisplayMode.List, isChecked = displayMode == LibraryDisplayMode.List,
) { ) {
selectingDisplayMode = false
onDisplayModeChange(LibraryDisplayMode.List) onDisplayModeChange(LibraryDisplayMode.List)
} }
} }
@ -142,34 +102,3 @@ fun BrowseSourceRegularToolbar(
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
) )
} }
@Composable
fun BrowseSourceSearchToolbar(
searchQuery: String,
onSearchQueryChanged: (String) -> Unit,
placeholderText: String?,
navigateUp: () -> Unit,
onResetClick: () -> Unit,
onSearchClick: (String) -> Unit,
scrollBehavior: TopAppBarScrollBehavior?,
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
SearchToolbar(
searchQuery = searchQuery,
onChangeSearchQuery = onSearchQueryChanged,
placeholderText = placeholderText,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = KeyboardActions(
onSearch = {
onSearchClick(searchQuery)
focusManager.clearFocus()
keyboardController?.hide()
},
),
onClickCloseSearch = navigateUp,
onClickResetSearch = onResetClick,
scrollBehavior = scrollBehavior,
)
}

View File

@ -1,6 +1,5 @@
package eu.kanade.presentation.components package eu.kanade.presentation.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
@ -13,6 +12,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowBack import androidx.compose.material.icons.outlined.ArrowBack
import androidx.compose.material.icons.outlined.Close import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.MoreVert import androidx.compose.material.icons.outlined.MoreVert
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
@ -26,6 +26,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -34,8 +35,11 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -215,15 +219,22 @@ fun AppBarActions(
} }
} }
/**
* @param searchEnabled Set to false if you don't want to show search action.
* @param searchQuery If null, use normal toolbar.
* @param placeholderText If null, [R.string.action_search_hint] is used.
*/
@Composable @Composable
fun SearchToolbar( fun SearchToolbar(
searchQuery: String, titleContent: @Composable () -> Unit = {},
onChangeSearchQuery: (String) -> Unit, navigateUp: (() -> Unit)? = null,
searchEnabled: Boolean = true,
searchQuery: String?,
onChangeSearchQuery: (String?) -> Unit,
placeholderText: String? = null, placeholderText: String? = null,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default, onSearch: (String) -> Unit = {},
keyboardActions: KeyboardActions = KeyboardActions.Default, onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) },
onClickCloseSearch: () -> Unit, actions: @Composable RowScope.() -> Unit = {},
onClickResetSearch: () -> Unit,
incognitoMode: Boolean = false, incognitoMode: Boolean = false,
downloadedOnlyMode: Boolean = false, downloadedOnlyMode: Boolean = false,
scrollBehavior: TopAppBarScrollBehavior? = null, scrollBehavior: TopAppBarScrollBehavior? = null,
@ -231,9 +242,15 @@ fun SearchToolbar(
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) { ) {
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
var searchClickCount by remember { mutableStateOf(0) }
AppBar( AppBar(
titleContent = { titleContent = {
if (searchQuery == null) return@AppBar titleContent()
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
BasicTextField( BasicTextField(
value = searchQuery, value = searchQuery,
onValueChange = onChangeSearchQuery, onValueChange = onChangeSearchQuery,
@ -245,8 +262,14 @@ fun SearchToolbar(
fontWeight = FontWeight.Normal, fontWeight = FontWeight.Normal,
fontSize = 18.sp, fontSize = 18.sp,
), ),
keyboardOptions = keyboardOptions, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
keyboardActions = keyboardActions, keyboardActions = KeyboardActions(
onSearch = {
onSearch(searchQuery)
focusManager.clearFocus()
keyboardController?.hide()
},
),
singleLine = true, singleLine = true,
cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground), cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground),
visualTransformation = visualTransformation, visualTransformation = visualTransformation,
@ -260,7 +283,7 @@ fun SearchToolbar(
visualTransformation = visualTransformation, visualTransformation = visualTransformation,
interactionSource = interactionSource, interactionSource = interactionSource,
placeholder = { placeholder = {
if (!placeholderText.isNullOrEmpty()) { (placeholderText ?: stringResource(R.string.action_search_hint)).let { placeholderText ->
Text( Text(
modifier = Modifier.secondaryItemAlpha(), modifier = Modifier.secondaryItemAlpha(),
text = placeholderText, text = placeholderText,
@ -277,22 +300,41 @@ fun SearchToolbar(
}, },
) )
}, },
navigationIcon = Icons.Outlined.ArrowBack, navigateUp = if (searchQuery == null) navigateUp else onClickCloseSearch,
navigateUp = onClickCloseSearch,
actions = { actions = {
AnimatedVisibility(visible = searchQuery.isNotEmpty()) { key("search") {
IconButton(onClick = onClickResetSearch) { val onClick = {
searchClickCount++
onChangeSearchQuery("")
}
if (!searchEnabled) {
// Don't show search action
} else if (searchQuery == null) {
IconButton(onClick) {
Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
}
} else if (searchQuery.isNotEmpty()) {
IconButton(onClick) {
Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset)) Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
} }
} }
}
key("actions") { actions() }
}, },
isActionMode = false, isActionMode = false,
downloadedOnlyMode = downloadedOnlyMode, downloadedOnlyMode = downloadedOnlyMode,
incognitoMode = incognitoMode, incognitoMode = incognitoMode,
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
) )
LaunchedEffect(focusRequester) { LaunchedEffect(searchClickCount) {
if (searchQuery == null) return@LaunchedEffect
try {
focusRequester.requestFocus() focusRequester.requestFocus()
} catch (_: Throwable) {
// TextField is gone
}
} }
} }

View File

@ -26,7 +26,6 @@ fun TabbedScreen(
tabs: List<TabContent>, tabs: List<TabContent>,
startIndex: Int? = null, startIndex: Int? = null,
searchQuery: String? = null, searchQuery: String? = null,
@StringRes placeholderRes: Int? = null,
onChangeSearchQuery: (String?) -> Unit = {}, onChangeSearchQuery: (String?) -> Unit = {},
incognitoMode: Boolean, incognitoMode: Boolean,
downloadedOnlyMode: Boolean, downloadedOnlyMode: Boolean,
@ -42,28 +41,16 @@ fun TabbedScreen(
Scaffold( Scaffold(
topBar = { topBar = {
if (searchQuery == null) { val tab = tabs[state.currentPage]
AppBar( val searchEnabled = tab.searchEnabled
title = stringResource(titleRes),
actions = {
AppBarActions(tabs[state.currentPage].actions)
},
)
} else {
SearchToolbar( SearchToolbar(
searchQuery = searchQuery, titleContent = { AppBarTitle(stringResource(titleRes)) },
placeholderText = placeholderRes?.let { stringResource(it) }, searchEnabled = searchEnabled,
onChangeSearchQuery = { searchQuery = if (searchEnabled) searchQuery else null,
onChangeSearchQuery(it) onChangeSearchQuery = onChangeSearchQuery,
}, actions = { AppBarActions(tab.actions) },
onClickCloseSearch = {
onChangeSearchQuery(null)
},
onClickResetSearch = {
onChangeSearchQuery("")
},
) )
}
}, },
) { contentPadding -> ) { contentPadding ->
Column( Column(
@ -108,6 +95,7 @@ fun TabbedScreen(
data class TabContent( data class TabContent(
@StringRes val titleRes: Int, @StringRes val titleRes: Int,
val badgeNumber: Int? = null, val badgeNumber: Int? = null,
val searchEnabled: Boolean = false,
val actions: List<AppBar.Action> = emptyList(), val actions: List<AppBar.Action> = emptyList(),
val content: @Composable (contentPadding: PaddingValues) -> Unit, val content: @Composable (contentPadding: PaddingValues) -> Unit,
) )

View File

@ -1,19 +1,13 @@
package eu.kanade.presentation.history.components package eu.kanade.presentation.history.components
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.DeleteSweep import androidx.compose.material.icons.outlined.DeleteSweep
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction import eu.kanade.presentation.components.AppBarTitle
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.SearchToolbar import eu.kanade.presentation.components.SearchToolbar
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter import eu.kanade.tachiyomi.ui.recent.history.HistoryPresenter
@ -26,54 +20,12 @@ fun HistoryToolbar(
incognitoMode: Boolean, incognitoMode: Boolean,
downloadedOnlyMode: Boolean, downloadedOnlyMode: Boolean,
) { ) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
if (state.searchQuery == null) {
HistoryRegularToolbar(
onClickSearch = { state.searchQuery = "" },
onClickDelete = { state.dialog = HistoryPresenter.Dialog.DeleteAll },
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
scrollBehavior = scrollBehavior,
)
} else {
SearchToolbar( SearchToolbar(
searchQuery = state.searchQuery!!, titleContent = { AppBarTitle(stringResource(R.string.history)) },
searchQuery = state.searchQuery,
onChangeSearchQuery = { state.searchQuery = it }, onChangeSearchQuery = { state.searchQuery = it },
placeholderText = stringResource(R.string.action_search_hint),
onClickCloseSearch = { state.searchQuery = null },
onClickResetSearch = { state.searchQuery = "" },
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Search,
),
keyboardActions = KeyboardActions(
onSearch = {
focusManager.clearFocus()
keyboardController?.hide()
},
),
)
}
}
@Composable
fun HistoryRegularToolbar(
onClickSearch: () -> Unit,
onClickDelete: () -> Unit,
incognitoMode: Boolean,
downloadedOnlyMode: Boolean,
scrollBehavior: TopAppBarScrollBehavior,
) {
AppBar(
title = stringResource(R.string.history),
actions = { actions = {
IconButton(onClick = onClickSearch) { IconButton(onClick = { state.dialog = HistoryPresenter.Dialog.DeleteAll }) {
Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
}
IconButton(onClick = onClickDelete) {
Icon(Icons.Outlined.DeleteSweep, contentDescription = stringResource(R.string.pref_clear_history)) Icon(Icons.Outlined.DeleteSweep, contentDescription = stringResource(R.string.pref_clear_history))
} }
}, },

View File

@ -2,12 +2,9 @@ package eu.kanade.presentation.library.components
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.FilterList import androidx.compose.material.icons.outlined.FilterList
import androidx.compose.material.icons.outlined.FlipToBack import androidx.compose.material.icons.outlined.FlipToBack
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.SelectAll import androidx.compose.material.icons.outlined.SelectAll
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@ -19,10 +16,7 @@ import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBar
@ -55,36 +49,13 @@ fun LibraryToolbar(
onClickSelectAll = onClickSelectAll, onClickSelectAll = onClickSelectAll,
onClickInvertSelection = onClickInvertSelection, onClickInvertSelection = onClickInvertSelection,
) )
state.searchQuery != null -> {
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
SearchToolbar(
searchQuery = state.searchQuery!!,
onChangeSearchQuery = { state.searchQuery = it },
onClickCloseSearch = { state.searchQuery = null },
onClickResetSearch = { state.searchQuery = "" },
scrollBehavior = scrollBehavior,
incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode,
placeholderText = stringResource(R.string.action_search_hint),
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Search,
),
keyboardActions = KeyboardActions(
onSearch = {
focusManager.clearFocus()
keyboardController?.hide()
},
),
)
}
else -> LibraryRegularToolbar( else -> LibraryRegularToolbar(
title = title, title = title,
hasFilters = state.hasActiveFilters, hasFilters = state.hasActiveFilters,
incognitoMode = incognitoMode, incognitoMode = incognitoMode,
downloadedOnlyMode = downloadedOnlyMode, downloadedOnlyMode = downloadedOnlyMode,
onClickSearch = { state.searchQuery = "" }, searchQuery = state.searchQuery,
onChangeSearchQuery = { state.searchQuery = it },
onClickFilter = onClickFilter, onClickFilter = onClickFilter,
onClickRefresh = onClickRefresh, onClickRefresh = onClickRefresh,
onClickOpenRandomManga = onClickOpenRandomManga, onClickOpenRandomManga = onClickOpenRandomManga,
@ -98,7 +69,8 @@ fun LibraryRegularToolbar(
hasFilters: Boolean, hasFilters: Boolean,
incognitoMode: Boolean, incognitoMode: Boolean,
downloadedOnlyMode: Boolean, downloadedOnlyMode: Boolean,
onClickSearch: () -> Unit, searchQuery: String?,
onChangeSearchQuery: (String?) -> Unit,
onClickFilter: () -> Unit, onClickFilter: () -> Unit,
onClickRefresh: () -> Unit, onClickRefresh: () -> Unit,
onClickOpenRandomManga: () -> Unit, onClickOpenRandomManga: () -> Unit,
@ -106,7 +78,7 @@ fun LibraryRegularToolbar(
) { ) {
val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f val pillAlpha = if (isSystemInDarkTheme()) 0.12f else 0.08f
val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current val filterTint = if (hasFilters) MaterialTheme.colorScheme.active else LocalContentColor.current
AppBar( SearchToolbar(
titleContent = { titleContent = {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Text( Text(
@ -124,10 +96,9 @@ fun LibraryRegularToolbar(
} }
} }
}, },
searchQuery = searchQuery,
onChangeSearchQuery = onChangeSearchQuery,
actions = { actions = {
IconButton(onClick = onClickSearch) {
Icon(Icons.Outlined.Search, contentDescription = stringResource(R.string.action_search))
}
IconButton(onClick = onClickFilter) { IconButton(onClick = onClickFilter) {
Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint) Icon(Icons.Outlined.FilterList, contentDescription = stringResource(R.string.action_filter), tint = filterTint)
} }

View File

@ -45,7 +45,6 @@ class BrowseController : FullComposeController<BrowsePresenter>, RootController
startIndex = 1.takeIf { toExtensions }, startIndex = 1.takeIf { toExtensions },
searchQuery = query, searchQuery = query,
onChangeSearchQuery = { presenter.extensionsPresenter.search(it) }, onChangeSearchQuery = { presenter.extensionsPresenter.search(it) },
placeholderRes = R.string.action_search_hint,
incognitoMode = presenter.isIncognitoMode, incognitoMode = presenter.isIncognitoMode,
downloadedOnlyMode = presenter.isDownloadOnly, downloadedOnlyMode = presenter.isDownloadOnly,
) )

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.ui.browse.extension package eu.kanade.tachiyomi.ui.browse.extension
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Translate import androidx.compose.material.icons.outlined.Translate
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -21,13 +20,8 @@ fun extensionsTab(
) = TabContent( ) = TabContent(
titleRes = R.string.label_extensions, titleRes = R.string.label_extensions,
badgeNumber = presenter.updates.takeIf { it > 0 }, badgeNumber = presenter.updates.takeIf { it > 0 },
searchEnabled = true,
actions = listOf( actions = listOf(
AppBar.Action(
title = stringResource(R.string.action_search),
icon = Icons.Outlined.Search,
onClick = { presenter.search("") },
),
AppBar.Action( AppBar.Action(
title = stringResource(R.string.action_filter), title = stringResource(R.string.action_filter),
icon = Icons.Outlined.Translate, icon = Icons.Outlined.Translate,

View File

@ -119,11 +119,7 @@ open class BrowseSourceController(bundle: Bundle) :
private fun navigateUp() { private fun navigateUp() {
when { when {
presenter.searchQuery != null -> presenter.searchQuery = null !presenter.isUserQuery && presenter.searchQuery != null -> presenter.searchQuery = null
presenter.isUserQuery -> {
val (_, filters) = presenter.currentFilter as BrowseSourcePresenter.Filter.UserInput
presenter.search(query = "", filters = filters)
}
else -> router.popCurrentController() else -> router.popCurrentController()
} }
} }

View File

@ -163,6 +163,7 @@ open class BrowseSourcePresenter(
Filter.valueOf(query ?: "").let { Filter.valueOf(query ?: "").let {
if (it !is Filter.UserInput) { if (it !is Filter.UserInput) {
state.currentFilter = it state.currentFilter = it
state.searchQuery = null
return return
} }
} }