Skip to content

Commit

Permalink
feat(ui): Add sources search to Migrate Source Screen (#232)
Browse files Browse the repository at this point in the history
  • Loading branch information
cuong-tran committed Aug 5, 2024
1 parent c0c3950 commit 8da0a14
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 61 deletions.
148 changes: 96 additions & 52 deletions app/src/main/java/eu/kanade/presentation/browse/MigrateSourceScreen.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package eu.kanade.presentation.browse

import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowDownward
import androidx.compose.material.icons.outlined.ArrowUpward
Expand All @@ -26,14 +28,16 @@ import androidx.compose.ui.text.style.TextOverflow
import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.presentation.browse.components.BaseSourceItem
import eu.kanade.presentation.browse.components.SourceIcon
import eu.kanade.presentation.util.animateItemFastScroll
import eu.kanade.tachiyomi.ui.browse.migration.sources.MigrateSourceScreenModel
import eu.kanade.tachiyomi.util.system.copyToClipboard
import kotlinx.collections.immutable.ImmutableList
import tachiyomi.domain.source.model.Source
import tachiyomi.i18n.MR
import tachiyomi.i18n.kmk.KMR
import tachiyomi.presentation.core.components.Badge
import tachiyomi.presentation.core.components.BadgeGroup
import tachiyomi.presentation.core.components.ScrollbarLazyColumn
import tachiyomi.presentation.core.components.FastScrollLazyColumn
import tachiyomi.presentation.core.components.Scroller.STICKY_HEADER_KEY_PREFIX
import tachiyomi.presentation.core.components.material.padding
import tachiyomi.presentation.core.components.material.topSmallPaddingValues
Expand All @@ -54,11 +58,17 @@ fun MigrateSourceScreen(
// SY -->
onClickAll: (Source) -> Unit,
// SY <--
// KMK -->
onChangeSearchQuery: (String?) -> Unit,
// KMK <--
) {
val context = LocalContext.current
when {
state.isLoading -> LoadingScreen(Modifier.padding(contentPadding))
state.isEmpty -> EmptyScreen(
// KMK -->
state.searchQuery.isNullOrBlank() &&
// KMK <--
state.isEmpty -> EmptyScreen(
stringRes = MR.strings.information_empty_library,
modifier = Modifier.padding(contentPadding),
)
Expand All @@ -78,6 +88,10 @@ fun MigrateSourceScreen(
// SY -->
onClickAll = onClickAll,
// SY <--
// KMK -->
state = state,
onChangeSearchQuery = onChangeSearchQuery,
// KMK <--
)
}
}
Expand All @@ -95,64 +109,94 @@ private fun MigrateSourceList(
// SY -->
onClickAll: (Source) -> Unit,
// SY <--
// KMK -->
state: MigrateSourceScreenModel.State,
onChangeSearchQuery: (String?) -> Unit,
// KMK <--
) {
ScrollbarLazyColumn(
contentPadding = contentPadding + topSmallPaddingValues,
// KMK -->
val lazyListState = rememberLazyListState()

BackHandler(enabled = !state.searchQuery.isNullOrBlank()) {
onChangeSearchQuery(null)
}

Column(
// Wrap around so we can use stickyHeader
modifier = Modifier.padding(contentPadding + topSmallPaddingValues),
) {
stickyHeader(key = STICKY_HEADER_KEY_PREFIX) {
Row(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.padding(start = MaterialTheme.padding.medium),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(MR.strings.migration_selection_prompt),
modifier = Modifier.weight(1f),
style = MaterialTheme.typography.header,
)
AnimatedFloatingSearchBox(
listState = lazyListState,
searchQuery = state.searchQuery,
onChangeSearchQuery = onChangeSearchQuery,
placeholderText = stringResource(KMR.strings.action_search_for_source),
)

IconButton(onClick = onToggleSortingMode) {
when (sortingMode) {
SetMigrateSorting.Mode.ALPHABETICAL -> Icon(
Icons.Outlined.SortByAlpha,
contentDescription = stringResource(MR.strings.action_sort_alpha),
)
SetMigrateSorting.Mode.TOTAL -> Icon(
Icons.Outlined.Numbers,
contentDescription = stringResource(MR.strings.action_sort_count),
)
FastScrollLazyColumn(
state = lazyListState,
// contentPadding = contentPadding + topSmallPaddingValues,
// KMK <--
) {
stickyHeader(key = STICKY_HEADER_KEY_PREFIX) {
Row(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.padding(start = MaterialTheme.padding.medium),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = stringResource(MR.strings.migration_selection_prompt),
modifier = Modifier.weight(1f),
style = MaterialTheme.typography.header,
)

IconButton(onClick = onToggleSortingMode) {
when (sortingMode) {
SetMigrateSorting.Mode.ALPHABETICAL -> Icon(
Icons.Outlined.SortByAlpha,
contentDescription = stringResource(MR.strings.action_sort_alpha),
)

SetMigrateSorting.Mode.TOTAL -> Icon(
Icons.Outlined.Numbers,
contentDescription = stringResource(MR.strings.action_sort_count),
)
}
}
}
IconButton(onClick = onToggleSortingDirection) {
when (sortingDirection) {
SetMigrateSorting.Direction.ASCENDING -> Icon(
Icons.Outlined.ArrowUpward,
contentDescription = stringResource(MR.strings.action_asc),
)
SetMigrateSorting.Direction.DESCENDING -> Icon(
Icons.Outlined.ArrowDownward,
contentDescription = stringResource(MR.strings.action_desc),
)
IconButton(onClick = onToggleSortingDirection) {
when (sortingDirection) {
SetMigrateSorting.Direction.ASCENDING -> Icon(
Icons.Outlined.ArrowUpward,
contentDescription = stringResource(MR.strings.action_asc),
)

SetMigrateSorting.Direction.DESCENDING -> Icon(
Icons.Outlined.ArrowDownward,
contentDescription = stringResource(MR.strings.action_desc),
)
}
}
}
}
}

items(
items = list,
key = { (source, _) -> "migrate-${source.id}" },
) { (source, count) ->
MigrateSourceItem(
modifier = Modifier.animateItem(),
source = source,
count = count,
onClickItem = { onClickItem(source) },
onLongClickItem = { onLongClickItem(source) },
// SY -->
onClickAll = { onClickAll(source) },
// SY <--
)
items(
items = list,
key = { (source, _) -> "migrate-${source.id}" },
) { (source, count) ->
MigrateSourceItem(
// KMK -->
// modifier = Modifier.animateItem(),
modifier = Modifier.animateItemFastScroll(),
// KMK <--
source = source,
count = count,
onClickItem = { onClickItem(source) },
onLongClickItem = { onLongClickItem(source) },
// SY -->
onClickAll = { onClickAll(source) },
// SY <--
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@ import cafe.adriel.voyager.core.model.StateScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.source.interactor.GetSourcesWithFavoriteCount
import eu.kanade.domain.source.interactor.SetMigrateSorting
import eu.kanade.domain.source.model.installedExtension
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.presentation.components.SEARCH_DEBOUNCE_MILLIS
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.update
Expand All @@ -34,7 +40,29 @@ class MigrateSourceScreenModel(

init {
screenModelScope.launchIO {
getSourcesWithFavoriteCount.subscribe()
// KMK -->
combine(
state.map { it.searchQuery }.distinctUntilChanged().debounce(SEARCH_DEBOUNCE_MILLIS),
// KMK <--
getSourcesWithFavoriteCount.subscribe(),
// KMK -->
) { searchQuery, sourceCounts ->
val queryFilter: (String?) -> ((Pair<Source, Long>) -> Boolean) = { query ->
filter@{ pair ->
val source = pair.first
if (query.isNullOrBlank()) return@filter true
query.split(",").any {
val input = it.trim()
if (input.isEmpty()) return@any false
source.installedExtension?.name?.contains(input, ignoreCase = true) == true ||
source.name.contains(input, ignoreCase = true) ||
source.id == input.toLongOrNull()
}
}
}
sourceCounts.filter(queryFilter(searchQuery))
}
// KMK <--
.catch {
logcat(LogPriority.ERROR, it)
_channel.send(Event.FailedFetchingSourcesWithCount)
Expand Down Expand Up @@ -80,12 +108,23 @@ class MigrateSourceScreenModel(
}
}

// KMK -->
fun search(query: String?) {
mutableState.update {
it.copy(searchQuery = query)
}
}
// KMK <--

@Immutable
data class State(
val isLoading: Boolean = true,
val items: ImmutableList<Pair<Source, Long>> = persistentListOf(),
val sortingMode: SetMigrateSorting.Mode = SetMigrateSorting.Mode.ALPHABETICAL,
val sortingDirection: SetMigrateSorting.Direction = SetMigrateSorting.Direction.ASCENDING,
// KMK -->
val searchQuery: String? = null,
// KMK <--
) {
val isEmpty = items.isEmpty()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ fun Screen.migrateSourceTab(): TabContent {
}
},
// SY <--
// KMK -->
onChangeSearchQuery = screenModel::search,
// KMK <--
)
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,14 @@ class SourcesScreenModel(
}
// SY <--

fun showSourceDialog(source: Source) {
mutableState.update { it.copy(dialog = Dialog.SourceLongClick(source)) }
}

fun closeDialog() {
mutableState.update { it.copy(dialog = null) }
}

// KMK -->
fun search(query: String?) {
mutableState.update {
Expand All @@ -210,14 +218,6 @@ class SourcesScreenModel(
}
// KMK <--

fun showSourceDialog(source: Source) {
mutableState.update { it.copy(dialog = Dialog.SourceLongClick(source)) }
}

fun closeDialog() {
mutableState.update { it.copy(dialog = null) }
}

sealed interface Event {
data object FailedFetchingSources : Event
}
Expand Down

0 comments on commit 8da0a14

Please sign in to comment.