mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-22 10:41:50 +01:00
Refactor search toolbar and fix browse source (#8360)
This commit is contained in:
parent
86c3d8c064
commit
a078f1ab1b
@ -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,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
@ -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 = {
|
||||||
Icon(Icons.Outlined.Close, contentDescription = stringResource(R.string.action_reset))
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key("actions") { actions() }
|
||||||
},
|
},
|
||||||
isActionMode = false,
|
isActionMode = false,
|
||||||
downloadedOnlyMode = downloadedOnlyMode,
|
downloadedOnlyMode = downloadedOnlyMode,
|
||||||
incognitoMode = incognitoMode,
|
incognitoMode = incognitoMode,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
LaunchedEffect(focusRequester) {
|
LaunchedEffect(searchClickCount) {
|
||||||
focusRequester.requestFocus()
|
if (searchQuery == null) return@LaunchedEffect
|
||||||
|
try {
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
} catch (_: Throwable) {
|
||||||
|
// TextField is gone
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 = {
|
SearchToolbar(
|
||||||
AppBarActions(tabs[state.currentPage].actions)
|
titleContent = { AppBarTitle(stringResource(titleRes)) },
|
||||||
},
|
searchEnabled = searchEnabled,
|
||||||
)
|
searchQuery = if (searchEnabled) searchQuery else null,
|
||||||
} else {
|
onChangeSearchQuery = onChangeSearchQuery,
|
||||||
SearchToolbar(
|
actions = { AppBarActions(tab.actions) },
|
||||||
searchQuery = searchQuery,
|
)
|
||||||
placeholderText = placeholderRes?.let { stringResource(it) },
|
|
||||||
onChangeSearchQuery = {
|
|
||||||
onChangeSearchQuery(it)
|
|
||||||
},
|
|
||||||
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,
|
||||||
)
|
)
|
||||||
|
@ -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
|
SearchToolbar(
|
||||||
val focusManager = LocalFocusManager.current
|
titleContent = { AppBarTitle(stringResource(R.string.history)) },
|
||||||
|
searchQuery = state.searchQuery,
|
||||||
if (state.searchQuery == null) {
|
onChangeSearchQuery = { state.searchQuery = it },
|
||||||
HistoryRegularToolbar(
|
|
||||||
onClickSearch = { state.searchQuery = "" },
|
|
||||||
onClickDelete = { state.dialog = HistoryPresenter.Dialog.DeleteAll },
|
|
||||||
incognitoMode = incognitoMode,
|
|
||||||
downloadedOnlyMode = downloadedOnlyMode,
|
|
||||||
scrollBehavior = scrollBehavior,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
SearchToolbar(
|
|
||||||
searchQuery = state.searchQuery!!,
|
|
||||||
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))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user