mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 16:18:55 +01:00 
			
		
		
		
	Replicate global search filters to migrate screen
Still needs better refactoring to dedupe all of this stuff though...
This commit is contained in:
		@@ -1,45 +1,21 @@
 | 
			
		||||
package eu.kanade.presentation.browse
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.horizontalScroll
 | 
			
		||||
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.layout.size
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyColumn
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.DoneAll
 | 
			
		||||
import androidx.compose.material.icons.outlined.FilterList
 | 
			
		||||
import androidx.compose.material.icons.outlined.PushPin
 | 
			
		||||
import androidx.compose.material3.FilterChip
 | 
			
		||||
import androidx.compose.material3.FilterChipDefaults
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.State
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import eu.kanade.presentation.browse.components.GlobalSearchCardRow
 | 
			
		||||
import eu.kanade.presentation.browse.components.GlobalSearchEmptyResultItem
 | 
			
		||||
import eu.kanade.presentation.browse.components.GlobalSearchErrorResultItem
 | 
			
		||||
import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem
 | 
			
		||||
import eu.kanade.presentation.browse.components.GlobalSearchResultItem
 | 
			
		||||
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.source.CatalogueSource
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchScreenModel
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Divider
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
import tachiyomi.presentation.core.components.material.VerticalDivider
 | 
			
		||||
import tachiyomi.presentation.core.components.material.padding
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun GlobalSearchScreen(
 | 
			
		||||
@@ -56,76 +32,19 @@ fun GlobalSearchScreen(
 | 
			
		||||
) {
 | 
			
		||||
    Scaffold(
 | 
			
		||||
        topBar = { scrollBehavior ->
 | 
			
		||||
            Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
 | 
			
		||||
                GlobalSearchToolbar(
 | 
			
		||||
                    searchQuery = state.searchQuery,
 | 
			
		||||
                    progress = state.progress,
 | 
			
		||||
                    total = state.total,
 | 
			
		||||
                    navigateUp = navigateUp,
 | 
			
		||||
                    onChangeSearchQuery = onChangeSearchQuery,
 | 
			
		||||
                    onSearch = onSearch,
 | 
			
		||||
                    scrollBehavior = scrollBehavior,
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                Row(
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .horizontalScroll(rememberScrollState())
 | 
			
		||||
                        .padding(horizontal = MaterialTheme.padding.small),
 | 
			
		||||
                    horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
 | 
			
		||||
                ) {
 | 
			
		||||
                    // TODO: make this UX better; it only applies when triggering a new search
 | 
			
		||||
                    FilterChip(
 | 
			
		||||
                        selected = state.sourceFilter == SourceFilter.PinnedOnly,
 | 
			
		||||
                        onClick = { onChangeSearchFilter(SourceFilter.PinnedOnly) },
 | 
			
		||||
                        leadingIcon = {
 | 
			
		||||
                            Icon(
 | 
			
		||||
                                imageVector = Icons.Outlined.PushPin,
 | 
			
		||||
                                contentDescription = null,
 | 
			
		||||
                                modifier = Modifier
 | 
			
		||||
                                    .size(FilterChipDefaults.IconSize),
 | 
			
		||||
                            )
 | 
			
		||||
                        },
 | 
			
		||||
                        label = {
 | 
			
		||||
                            Text(text = stringResource(id = R.string.pinned_sources))
 | 
			
		||||
                        },
 | 
			
		||||
                    )
 | 
			
		||||
                    FilterChip(
 | 
			
		||||
                        selected = state.sourceFilter == SourceFilter.All,
 | 
			
		||||
                        onClick = { onChangeSearchFilter(SourceFilter.All) },
 | 
			
		||||
                        leadingIcon = {
 | 
			
		||||
                            Icon(
 | 
			
		||||
                                imageVector = Icons.Outlined.DoneAll,
 | 
			
		||||
                                contentDescription = null,
 | 
			
		||||
                                modifier = Modifier
 | 
			
		||||
                                    .size(FilterChipDefaults.IconSize),
 | 
			
		||||
                            )
 | 
			
		||||
                        },
 | 
			
		||||
                        label = {
 | 
			
		||||
                            Text(text = stringResource(id = R.string.all))
 | 
			
		||||
                        },
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
                    VerticalDivider()
 | 
			
		||||
 | 
			
		||||
                    FilterChip(
 | 
			
		||||
                        selected = state.onlyShowHasResults,
 | 
			
		||||
                        onClick = { onToggleResults() },
 | 
			
		||||
                        leadingIcon = {
 | 
			
		||||
                            Icon(
 | 
			
		||||
                                imageVector = Icons.Outlined.FilterList,
 | 
			
		||||
                                contentDescription = null,
 | 
			
		||||
                                modifier = Modifier
 | 
			
		||||
                                    .size(FilterChipDefaults.IconSize),
 | 
			
		||||
                            )
 | 
			
		||||
                        },
 | 
			
		||||
                        label = {
 | 
			
		||||
                            Text(text = stringResource(id = R.string.has_results))
 | 
			
		||||
                        },
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Divider()
 | 
			
		||||
            }
 | 
			
		||||
            GlobalSearchToolbar(
 | 
			
		||||
                searchQuery = state.searchQuery,
 | 
			
		||||
                progress = state.progress,
 | 
			
		||||
                total = state.total,
 | 
			
		||||
                navigateUp = navigateUp,
 | 
			
		||||
                onChangeSearchQuery = onChangeSearchQuery,
 | 
			
		||||
                onSearch = onSearch,
 | 
			
		||||
                sourceFilter = state.sourceFilter,
 | 
			
		||||
                onChangeSearchFilter = onChangeSearchFilter,
 | 
			
		||||
                onlyShowHasResults = state.onlyShowHasResults,
 | 
			
		||||
                onToggleResults = onToggleResults,
 | 
			
		||||
                scrollBehavior = scrollBehavior,
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
    ) { paddingValues ->
 | 
			
		||||
        GlobalSearchContent(
 | 
			
		||||
@@ -141,7 +60,7 @@ fun GlobalSearchScreen(
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
internal fun GlobalSearchContent(
 | 
			
		||||
    sourceId: Long? = null,
 | 
			
		||||
    fromSourceId: Long? = null,
 | 
			
		||||
    items: Map<CatalogueSource, SearchItemResult>,
 | 
			
		||||
    contentPadding: PaddingValues,
 | 
			
		||||
    getManga: @Composable (Manga) -> State<Manga>,
 | 
			
		||||
@@ -155,7 +74,7 @@ internal fun GlobalSearchContent(
 | 
			
		||||
        items.forEach { (source, result) ->
 | 
			
		||||
            item(key = source.id) {
 | 
			
		||||
                GlobalSearchResultItem(
 | 
			
		||||
                    title = sourceId?.let { "▶ ${source.name}".takeIf { source.id == sourceId } } ?: source.name,
 | 
			
		||||
                    title = fromSourceId?.let { "▶ ${source.name}".takeIf { source.id == fromSourceId } } ?: source.name,
 | 
			
		||||
                    subtitle = LocaleHelper.getDisplayName(source.lang),
 | 
			
		||||
                    onClick = { onClickSource(source) },
 | 
			
		||||
                ) {
 | 
			
		||||
@@ -164,11 +83,6 @@ internal fun GlobalSearchContent(
 | 
			
		||||
                            GlobalSearchLoadingResultItem()
 | 
			
		||||
                        }
 | 
			
		||||
                        is SearchItemResult.Success -> {
 | 
			
		||||
                            if (result.isEmpty) {
 | 
			
		||||
                                GlobalSearchEmptyResultItem()
 | 
			
		||||
                                return@GlobalSearchResultItem
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            GlobalSearchCardRow(
 | 
			
		||||
                                titles = result.result,
 | 
			
		||||
                                getManga = getManga,
 | 
			
		||||
 
 | 
			
		||||
@@ -5,16 +5,19 @@ import androidx.compose.runtime.State
 | 
			
		||||
import eu.kanade.presentation.browse.components.GlobalSearchToolbar
 | 
			
		||||
import eu.kanade.tachiyomi.source.CatalogueSource
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.migration.search.MigrateSearchScreenModel
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Scaffold
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun MigrateSearchScreen(
 | 
			
		||||
    navigateUp: () -> Unit,
 | 
			
		||||
    state: MigrateSearchScreenModel.State,
 | 
			
		||||
    getManga: @Composable (Manga) -> State<Manga>,
 | 
			
		||||
    navigateUp: () -> Unit,
 | 
			
		||||
    onChangeSearchQuery: (String?) -> Unit,
 | 
			
		||||
    onSearch: (String) -> Unit,
 | 
			
		||||
    onChangeSearchFilter: (SourceFilter) -> Unit,
 | 
			
		||||
    onToggleResults: () -> Unit,
 | 
			
		||||
    getManga: @Composable (Manga) -> State<Manga>,
 | 
			
		||||
    onClickSource: (CatalogueSource) -> Unit,
 | 
			
		||||
    onClickItem: (Manga) -> Unit,
 | 
			
		||||
    onLongClickItem: (Manga) -> Unit,
 | 
			
		||||
@@ -28,13 +31,17 @@ fun MigrateSearchScreen(
 | 
			
		||||
                navigateUp = navigateUp,
 | 
			
		||||
                onChangeSearchQuery = onChangeSearchQuery,
 | 
			
		||||
                onSearch = onSearch,
 | 
			
		||||
                sourceFilter = state.sourceFilter,
 | 
			
		||||
                onChangeSearchFilter = onChangeSearchFilter,
 | 
			
		||||
                onlyShowHasResults = state.onlyShowHasResults,
 | 
			
		||||
                onToggleResults = onToggleResults,
 | 
			
		||||
                scrollBehavior = scrollBehavior,
 | 
			
		||||
            )
 | 
			
		||||
        },
 | 
			
		||||
    ) { paddingValues ->
 | 
			
		||||
        GlobalSearchContent(
 | 
			
		||||
            sourceId = state.manga?.source,
 | 
			
		||||
            items = state.items,
 | 
			
		||||
            fromSourceId = state.manga?.source,
 | 
			
		||||
            items = state.filteredItems,
 | 
			
		||||
            contentPadding = paddingValues,
 | 
			
		||||
            getManga = getManga,
 | 
			
		||||
            onClickSource = onClickSource,
 | 
			
		||||
 
 | 
			
		||||
@@ -3,17 +3,21 @@ package eu.kanade.presentation.browse.components
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.PaddingValues
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.layout.width
 | 
			
		||||
import androidx.compose.foundation.lazy.LazyRow
 | 
			
		||||
import androidx.compose.foundation.lazy.items
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.State
 | 
			
		||||
import androidx.compose.runtime.getValue
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import eu.kanade.presentation.library.components.CommonMangaItemDefaults
 | 
			
		||||
import eu.kanade.presentation.library.components.MangaComfortableGridItem
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import tachiyomi.domain.manga.model.Manga
 | 
			
		||||
import tachiyomi.domain.manga.model.MangaCover
 | 
			
		||||
import tachiyomi.domain.manga.model.asMangaCover
 | 
			
		||||
@@ -26,13 +30,18 @@ fun GlobalSearchCardRow(
 | 
			
		||||
    onClick: (Manga) -> Unit,
 | 
			
		||||
    onLongClick: (Manga) -> Unit,
 | 
			
		||||
) {
 | 
			
		||||
    if (titles.isEmpty()) {
 | 
			
		||||
        EmptyResultItem()
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LazyRow(
 | 
			
		||||
        contentPadding = PaddingValues(MaterialTheme.padding.small),
 | 
			
		||||
        horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.tiny),
 | 
			
		||||
    ) {
 | 
			
		||||
        items(titles) {
 | 
			
		||||
            val title by getManga(it)
 | 
			
		||||
            GlobalSearchCard(
 | 
			
		||||
            MangaItem(
 | 
			
		||||
                title = title.title,
 | 
			
		||||
                cover = title.asMangaCover(),
 | 
			
		||||
                isFavorite = title.favorite,
 | 
			
		||||
@@ -44,7 +53,7 @@ fun GlobalSearchCardRow(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
private fun GlobalSearchCard(
 | 
			
		||||
private fun MangaItem(
 | 
			
		||||
    title: String,
 | 
			
		||||
    cover: MangaCover,
 | 
			
		||||
    isFavorite: Boolean,
 | 
			
		||||
@@ -64,3 +73,15 @@ private fun GlobalSearchCard(
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
private fun EmptyResultItem() {
 | 
			
		||||
    Text(
 | 
			
		||||
        text = stringResource(R.string.no_results_found),
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .padding(
 | 
			
		||||
                horizontal = MaterialTheme.padding.medium,
 | 
			
		||||
                vertical = MaterialTheme.padding.small,
 | 
			
		||||
            ),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,18 +61,6 @@ fun GlobalSearchResultItem(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun GlobalSearchEmptyResultItem() {
 | 
			
		||||
    Text(
 | 
			
		||||
        text = stringResource(R.string.no_results_found),
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .padding(
 | 
			
		||||
                horizontal = MaterialTheme.padding.medium,
 | 
			
		||||
                vertical = MaterialTheme.padding.small,
 | 
			
		||||
            ),
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun GlobalSearchLoadingResultItem() {
 | 
			
		||||
    Box(
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,36 @@
 | 
			
		||||
package eu.kanade.presentation.browse.components
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.horizontalScroll
 | 
			
		||||
import androidx.compose.foundation.layout.Arrangement
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.layout.size
 | 
			
		||||
import androidx.compose.foundation.rememberScrollState
 | 
			
		||||
import androidx.compose.material.icons.Icons
 | 
			
		||||
import androidx.compose.material.icons.outlined.DoneAll
 | 
			
		||||
import androidx.compose.material.icons.outlined.FilterList
 | 
			
		||||
import androidx.compose.material.icons.outlined.PushPin
 | 
			
		||||
import androidx.compose.material3.FilterChip
 | 
			
		||||
import androidx.compose.material3.FilterChipDefaults
 | 
			
		||||
import androidx.compose.material3.Icon
 | 
			
		||||
import androidx.compose.material3.LinearProgressIndicator
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.material3.TopAppBarScrollBehavior
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Alignment
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.res.stringResource
 | 
			
		||||
import eu.kanade.presentation.components.SearchToolbar
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
 | 
			
		||||
import tachiyomi.presentation.core.components.material.Divider
 | 
			
		||||
import tachiyomi.presentation.core.components.material.VerticalDivider
 | 
			
		||||
import tachiyomi.presentation.core.components.material.padding
 | 
			
		||||
 | 
			
		||||
@Composable
 | 
			
		||||
fun GlobalSearchToolbar(
 | 
			
		||||
@@ -17,24 +40,89 @@ fun GlobalSearchToolbar(
 | 
			
		||||
    navigateUp: () -> Unit,
 | 
			
		||||
    onChangeSearchQuery: (String?) -> Unit,
 | 
			
		||||
    onSearch: (String) -> Unit,
 | 
			
		||||
    sourceFilter: SourceFilter,
 | 
			
		||||
    onChangeSearchFilter: (SourceFilter) -> Unit,
 | 
			
		||||
    onlyShowHasResults: Boolean,
 | 
			
		||||
    onToggleResults: () -> Unit,
 | 
			
		||||
    scrollBehavior: TopAppBarScrollBehavior,
 | 
			
		||||
) {
 | 
			
		||||
    Box {
 | 
			
		||||
        SearchToolbar(
 | 
			
		||||
            searchQuery = searchQuery,
 | 
			
		||||
            onChangeSearchQuery = onChangeSearchQuery,
 | 
			
		||||
            onSearch = onSearch,
 | 
			
		||||
            onClickCloseSearch = navigateUp,
 | 
			
		||||
            navigateUp = navigateUp,
 | 
			
		||||
            scrollBehavior = scrollBehavior,
 | 
			
		||||
        )
 | 
			
		||||
        if (progress in 1 until total) {
 | 
			
		||||
            LinearProgressIndicator(
 | 
			
		||||
                progress = progress / total.toFloat(),
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .align(Alignment.BottomStart)
 | 
			
		||||
                    .fillMaxWidth(),
 | 
			
		||||
    Column(modifier = Modifier.background(MaterialTheme.colorScheme.surface)) {
 | 
			
		||||
        Box {
 | 
			
		||||
            SearchToolbar(
 | 
			
		||||
                searchQuery = searchQuery,
 | 
			
		||||
                onChangeSearchQuery = onChangeSearchQuery,
 | 
			
		||||
                onSearch = onSearch,
 | 
			
		||||
                onClickCloseSearch = navigateUp,
 | 
			
		||||
                navigateUp = navigateUp,
 | 
			
		||||
                scrollBehavior = scrollBehavior,
 | 
			
		||||
            )
 | 
			
		||||
            if (progress in 1 until total) {
 | 
			
		||||
                LinearProgressIndicator(
 | 
			
		||||
                    progress = progress / total.toFloat(),
 | 
			
		||||
                    modifier = Modifier
 | 
			
		||||
                        .align(Alignment.BottomStart)
 | 
			
		||||
                        .fillMaxWidth(),
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Row(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .horizontalScroll(rememberScrollState())
 | 
			
		||||
                .padding(horizontal = MaterialTheme.padding.small),
 | 
			
		||||
            horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.small),
 | 
			
		||||
        ) {
 | 
			
		||||
            // TODO: make this UX better; it only applies when triggering a new search
 | 
			
		||||
            FilterChip(
 | 
			
		||||
                selected = sourceFilter == SourceFilter.PinnedOnly,
 | 
			
		||||
                onClick = { onChangeSearchFilter(SourceFilter.PinnedOnly) },
 | 
			
		||||
                leadingIcon = {
 | 
			
		||||
                    Icon(
 | 
			
		||||
                        imageVector = Icons.Outlined.PushPin,
 | 
			
		||||
                        contentDescription = null,
 | 
			
		||||
                        modifier = Modifier
 | 
			
		||||
                            .size(FilterChipDefaults.IconSize),
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
                label = {
 | 
			
		||||
                    Text(text = stringResource(id = R.string.pinned_sources))
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
            FilterChip(
 | 
			
		||||
                selected = sourceFilter == SourceFilter.All,
 | 
			
		||||
                onClick = { onChangeSearchFilter(SourceFilter.All) },
 | 
			
		||||
                leadingIcon = {
 | 
			
		||||
                    Icon(
 | 
			
		||||
                        imageVector = Icons.Outlined.DoneAll,
 | 
			
		||||
                        contentDescription = null,
 | 
			
		||||
                        modifier = Modifier
 | 
			
		||||
                            .size(FilterChipDefaults.IconSize),
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
                label = {
 | 
			
		||||
                    Text(text = stringResource(id = R.string.all))
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            VerticalDivider()
 | 
			
		||||
 | 
			
		||||
            FilterChip(
 | 
			
		||||
                selected = onlyShowHasResults,
 | 
			
		||||
                onClick = { onToggleResults() },
 | 
			
		||||
                leadingIcon = {
 | 
			
		||||
                    Icon(
 | 
			
		||||
                        imageVector = Icons.Outlined.FilterList,
 | 
			
		||||
                        contentDescription = null,
 | 
			
		||||
                        modifier = Modifier
 | 
			
		||||
                            .size(FilterChipDefaults.IconSize),
 | 
			
		||||
                    )
 | 
			
		||||
                },
 | 
			
		||||
                label = {
 | 
			
		||||
                    Text(text = stringResource(id = R.string.has_results))
 | 
			
		||||
                },
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Divider()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,11 +21,13 @@ class MigrateSearchScreen(private val mangaId: Long) : Screen() {
 | 
			
		||||
        val state by screenModel.state.collectAsState()
 | 
			
		||||
 | 
			
		||||
        MigrateSearchScreen(
 | 
			
		||||
            navigateUp = navigator::pop,
 | 
			
		||||
            state = state,
 | 
			
		||||
            getManga = { screenModel.getManga(it) },
 | 
			
		||||
            navigateUp = navigator::pop,
 | 
			
		||||
            onChangeSearchQuery = screenModel::updateSearchQuery,
 | 
			
		||||
            onSearch = screenModel::search,
 | 
			
		||||
            getManga = { screenModel.getManga(it) },
 | 
			
		||||
            onChangeSearchFilter = screenModel::setSourceFilter,
 | 
			
		||||
            onToggleResults = screenModel::toggleFilterResults,
 | 
			
		||||
            onClickSource = {
 | 
			
		||||
                if (!screenModel.incognitoMode.get()) {
 | 
			
		||||
                    screenModel.lastUsedSourceId.set(it.id)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,7 @@ import eu.kanade.domain.source.service.SourcePreferences
 | 
			
		||||
import eu.kanade.tachiyomi.source.CatalogueSource
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchItemResult
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SearchScreenModel
 | 
			
		||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.SourceFilter
 | 
			
		||||
import kotlinx.coroutines.flow.update
 | 
			
		||||
import kotlinx.coroutines.launch
 | 
			
		||||
import tachiyomi.domain.manga.interactor.GetManga
 | 
			
		||||
@@ -23,6 +24,9 @@ class MigrateSearchScreenModel(
 | 
			
		||||
    private val getManga: GetManga = Injekt.get(),
 | 
			
		||||
) : SearchScreenModel<MigrateSearchScreenModel.State>(State()) {
 | 
			
		||||
 | 
			
		||||
    val incognitoMode = preferences.incognitoMode()
 | 
			
		||||
    val lastUsedSourceId = sourcePreferences.lastUsedSource()
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        coroutineScope.launch {
 | 
			
		||||
            val manga = getManga.await(mangaId)!!
 | 
			
		||||
@@ -35,15 +39,13 @@ class MigrateSearchScreenModel(
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val incognitoMode = preferences.incognitoMode()
 | 
			
		||||
    val lastUsedSourceId = sourcePreferences.lastUsedSource()
 | 
			
		||||
 | 
			
		||||
    override fun getEnabledSources(): List<CatalogueSource> {
 | 
			
		||||
        val enabledLanguages = sourcePreferences.enabledLanguages().get()
 | 
			
		||||
        val disabledSources = sourcePreferences.disabledSources().get()
 | 
			
		||||
        val pinnedSources = sourcePreferences.pinnedSources().get()
 | 
			
		||||
 | 
			
		||||
        return sourceManager.getCatalogueSources()
 | 
			
		||||
            .filter { mutableState.value.sourceFilter != SourceFilter.PinnedOnly || "${it.id}" in pinnedSources }
 | 
			
		||||
            .filter { it.lang in enabledLanguages }
 | 
			
		||||
            .filterNot { "${it.id}" in disabledSources }
 | 
			
		||||
            .sortedWith(compareBy({ "${it.id}" !in pinnedSources }, { "${it.name.lowercase()} (${it.lang})" }))
 | 
			
		||||
@@ -66,6 +68,16 @@ class MigrateSearchScreenModel(
 | 
			
		||||
        return mutableState.value.items
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setSourceFilter(filter: SourceFilter) {
 | 
			
		||||
        mutableState.update { it.copy(sourceFilter = filter) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun toggleFilterResults() {
 | 
			
		||||
        mutableState.update {
 | 
			
		||||
            it.copy(onlyShowHasResults = !it.onlyShowHasResults)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setDialog(dialog: MigrateSearchDialog?) {
 | 
			
		||||
        mutableState.update {
 | 
			
		||||
            it.copy(dialog = dialog)
 | 
			
		||||
@@ -75,12 +87,16 @@ class MigrateSearchScreenModel(
 | 
			
		||||
    @Immutable
 | 
			
		||||
    data class State(
 | 
			
		||||
        val manga: Manga? = null,
 | 
			
		||||
        val searchQuery: String? = null,
 | 
			
		||||
        val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
 | 
			
		||||
        val dialog: MigrateSearchDialog? = null,
 | 
			
		||||
 | 
			
		||||
        val searchQuery: String? = null,
 | 
			
		||||
        val sourceFilter: SourceFilter = SourceFilter.PinnedOnly,
 | 
			
		||||
        val onlyShowHasResults: Boolean = false,
 | 
			
		||||
        val items: Map<CatalogueSource, SearchItemResult> = emptyMap(),
 | 
			
		||||
    ) {
 | 
			
		||||
        val progress: Int = items.count { it.value !is SearchItemResult.Loading }
 | 
			
		||||
        val total: Int = items.size
 | 
			
		||||
        val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ class GlobalSearchScreenModel(
 | 
			
		||||
 | 
			
		||||
    val incognitoMode = preferences.incognitoMode()
 | 
			
		||||
    val lastUsedSourceId = sourcePreferences.lastUsedSource()
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        extensionFilter = initialExtensionFilter
 | 
			
		||||
        if (initialQuery.isNotBlank() || !initialExtensionFilter.isNullOrBlank()) {
 | 
			
		||||
@@ -76,7 +77,3 @@ class GlobalSearchScreenModel(
 | 
			
		||||
        val filteredItems = items.filter { (_, result) -> result.isVisible(onlyShowHasResults) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private fun SearchItemResult.isVisible(onlyShowHasResults: Boolean): Boolean {
 | 
			
		||||
    return !onlyShowHasResults || (this is SearchItemResult.Success && !this.isEmpty)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -145,4 +145,8 @@ sealed class SearchItemResult {
 | 
			
		||||
        val isEmpty: Boolean
 | 
			
		||||
            get() = result.isEmpty()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun isVisible(onlyShowHasResults: Boolean): Boolean {
 | 
			
		||||
        return !onlyShowHasResults || (this is Success && !this.isEmpty)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user