From eb62927c1b3f5359153734754eba085e9615819f Mon Sep 17 00:00:00 2001 From: Cuong-Tran Date: Sat, 31 Aug 2024 01:23:20 +0700 Subject: [PATCH] Add source search, icon & flag on Feed adding dialog (#324) * add language flag * add source icon * source search --- .../kanade/presentation/browse/FeedScreen.kt | 81 ++++++++++++++++++- .../tachiyomi/source/SourceExtensions.kt | 2 +- .../advanced/design/MigrationSourceHolder.kt | 2 +- .../process/MigrationListScreenModel.kt | 2 +- .../tachiyomi/ui/library/LibraryItem.kt | 2 +- .../tachiyomi/ui/manga/MangaScreenModel.kt | 2 +- 6 files changed, 82 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt index feae3d57c..10a19f7d6 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.AlertDialog +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -34,7 +35,9 @@ import eu.kanade.presentation.browse.components.GlobalSearchCardRow 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.SourceIcon import eu.kanade.tachiyomi.source.CatalogueSource +import eu.kanade.tachiyomi.source.getNameForMangaInfo import eu.kanade.tachiyomi.ui.browse.feed.FeedScreenState import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList @@ -43,11 +46,13 @@ import tachiyomi.core.common.i18n.stringResource import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.model.FeedSavedSearch import tachiyomi.domain.source.model.SavedSearch +import tachiyomi.domain.source.model.Source import tachiyomi.i18n.MR import tachiyomi.i18n.kmk.KMR import tachiyomi.i18n.sy.SYMR import tachiyomi.presentation.core.components.ScrollbarLazyColumn import tachiyomi.presentation.core.components.material.PullRefresh +import tachiyomi.presentation.core.components.material.padding import tachiyomi.presentation.core.components.material.topSmallPaddingValues import tachiyomi.presentation.core.i18n.stringResource import tachiyomi.presentation.core.screens.EmptyScreen @@ -190,13 +195,49 @@ fun FeedAddDialog( onDismiss: () -> Unit, onClickAdd: (CatalogueSource?) -> Unit, ) { + // KMK --> + var query by remember { mutableStateOf("") } + val sourceComposes: List<@Composable () -> Unit> = sources + .filter { source -> + if (query.isBlank()) return@filter true + query.split(",").any { + val input = it.trim() + if (input.isEmpty()) return@any false + source.name.contains(input, ignoreCase = true) || + source.id == input.toLongOrNull() + } + } + .map { + { + val source = Source( + id = it.id, + lang = it.lang, + name = it.name, + supportsLatest = it.supportsLatest, + isStub = false, + ) + SourceIcon(source = source) + Spacer(modifier = Modifier.width(MaterialTheme.padding.extraSmall)) + Text(text = it.getNameForMangaInfo()) + } + } + // KMK <-- var selected by remember { mutableStateOf(null) } AlertDialog( title = { Text(text = stringResource(SYMR.strings.feed)) }, text = { - RadioSelector(options = sources, selected = selected) { + // KMK --> + RadioSelectorSearchable( + options = sourceComposes, + queryString = query, + onChangeSearchQuery = { + query = it ?: "" + }, + // KMK <-- + selected = selected, + ) { selected = it } }, @@ -237,7 +278,7 @@ fun FeedAddSearchDialog( // KMK <-- }.toImmutableList() } - RadioSelector( + RadioSelectorSearchable( options = savedSearches, optionStrings = savedSearchStrings, selected = selected, @@ -260,7 +301,7 @@ fun FeedAddSearchDialog( } @Composable -fun RadioSelector( +fun RadioSelectorSearchable( options: ImmutableList, optionStrings: ImmutableList = remember { options.map { it.toString() }.toImmutableList() }, selected: Int?, @@ -276,13 +317,45 @@ fun RadioSelector( verticalAlignment = Alignment.CenterVertically, ) { RadioButton(selected == index, onClick = null) - Spacer(Modifier.width(4.dp)) + Spacer(Modifier.width(MaterialTheme.padding.extraSmall)) Text(option, maxLines = 1) } } } } +// KMK --> +@Composable +fun RadioSelectorSearchable( + options: List<@Composable () -> Unit>, + queryString: String? = null, + onChangeSearchQuery: ((String?) -> Unit)? = null, + selected: Int?, + onSelectOption: (Int) -> Unit = {}, +) { + Column(Modifier.verticalScroll(rememberScrollState())) { + SourcesSearch( + searchQuery = queryString, + onChangeSearchQuery = onChangeSearchQuery ?: {}, + modifier = Modifier.fillMaxWidth(), + ).takeIf { onChangeSearchQuery != null } + options.forEachIndexed { index, option -> + Row( + Modifier + .fillMaxWidth() + .height(48.dp) + .clickable { onSelectOption(index) }, + verticalAlignment = Alignment.CenterVertically, + ) { + RadioButton(selected == index, onClick = null) + Spacer(Modifier.width(MaterialTheme.padding.extraSmall)) + option() + } + } + } +} +// KMK <-- + @Composable fun FeedDeleteConfirmDialog( feed: FeedSavedSearch, diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt index 09cbeff0b..a3a012498 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceExtensions.kt @@ -9,7 +9,7 @@ import uy.kohesive.injekt.api.get fun Source.getNameForMangaInfo( // SY --> - mergeSources: List?, + mergeSources: List? = null, // SY <-- ): String { val preferences = Injekt.get() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationSourceHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationSourceHolder.kt index d10c8e563..10be35d54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationSourceHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/design/MigrationSourceHolder.kt @@ -21,7 +21,7 @@ class MigrationSourceHolder(view: View, val adapter: MigrationSourceAdapter) : // Set capitalized title. val sourceName = // KMK --> - source.getNameForMangaInfo(null) + source.getNameForMangaInfo() // KMK <-- binding.title.text = sourceName // Update circle letter image. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt index 8514a13cb..b881785e0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/advanced/process/MigrationListScreenModel.kt @@ -150,7 +150,7 @@ class MigrationListScreenModel( chapterCount = chapters.size, ) } - fun getSourceName(manga: Manga) = sourceManager.getOrStub(manga.source).getNameForMangaInfo(null) + fun getSourceName(manga: Manga) = sourceManager.getOrStub(manga.source).getNameForMangaInfo() fun getMigrationSources() = preferences.migrationSources().get().split("/").mapNotNull { val value = it.toLongOrNull() ?: return@mapNotNull null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt index f3396f893..9bf9a85b2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt @@ -26,7 +26,7 @@ data class LibraryItem( * @return true if the manga matches the query, false otherwise. */ fun matches(constraint: String): Boolean { - val sourceName by lazy { sourceManager.getOrStub(libraryManga.manga.source).getNameForMangaInfo(null) } + val sourceName by lazy { sourceManager.getOrStub(libraryManga.manga.source).getNameForMangaInfo() } return libraryManga.manga.title.contains(constraint, true) || (libraryManga.manga.author?.contains(constraint, true) ?: false) || (libraryManga.manga.artist?.contains(constraint, true) ?: false) || diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt index e58feaadd..f095da14a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt @@ -1032,7 +1032,7 @@ class MangaScreenModel( downloadProgress = activeDownload?.progress ?: 0, selected = chapter.id in selectedChapterIds, // SY --> - sourceName = source?.getNameForMangaInfo(null), + sourceName = source?.getNameForMangaInfo(), showScanlator = !isExhManga, // SY <-- )