From d0518515e978e21b4cfd1762aa213d1164f40ba2 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 10 Sep 2022 12:25:30 -0400 Subject: [PATCH] Control FAB with Compose in SourceFeed --- .../presentation/browse/SourceFeedScreen.kt | 7 +++ .../presentation/browse/SourceFeedState.kt | 8 ++++ .../source/feed/SourceFeedController.kt | 44 +++---------------- .../browse/source/feed/SourceFeedPresenter.kt | 33 ++++---------- .../ui/browse/source/filter/AutoComplete.kt | 2 +- 5 files changed, 30 insertions(+), 64 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt index bf90375c0..fb9dca5f8 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt @@ -101,6 +101,7 @@ sealed class SourceFeedUI { @Composable fun SourceFeedScreen( presenter: SourceFeedPresenter, + onFabClick: () -> Unit, onClickBrowse: () -> Unit, onClickLatest: () -> Unit, onClickSavedSearch: (SavedSearch) -> Unit, @@ -117,6 +118,12 @@ fun SourceFeedScreen( downloadedOnlyMode = presenter.isDownloadOnly, ) }, + floatingActionButton = { + BrowseSourceFloatingActionButton( + isVisible = presenter.filterItems.isNotEmpty(), + onFabClick = onFabClick, + ) + }, ) { paddingValues -> Crossfade(targetState = presenter.isLoading) { state -> when (state) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedState.kt b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedState.kt index 7d93eafa3..0fb3909e3 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedState.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedState.kt @@ -1,14 +1,20 @@ package eu.kanade.presentation.browse import androidx.compose.runtime.Stable +import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import eu.davidea.flexibleadapter.items.IFlexible +import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.ui.browse.source.browse.toItems @Stable interface SourceFeedState { val isLoading: Boolean var searchQuery: String? + val filters: FilterList + val filterItems: List> val items: List? } @@ -19,5 +25,7 @@ fun SourceFeedState(): SourceFeedState { class SourceFeedStateImpl : SourceFeedState { override var isLoading: Boolean by mutableStateOf(true) override var searchQuery: String? by mutableStateOf(null) + override var filters: FilterList by mutableStateOf(FilterList()) + override val filterItems: List> by derivedStateOf { filters.toItems() } override var items: List? by mutableStateOf(null) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt index ae1f1a77a..906a241b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedController.kt @@ -4,9 +4,7 @@ import android.os.Bundle import android.view.View import androidx.compose.runtime.Composable import androidx.core.os.bundleOf -import androidx.core.view.isVisible import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import eu.kanade.domain.manga.model.Manga import eu.kanade.domain.source.interactor.GetRemoteManga import eu.kanade.presentation.browse.SourceFeedScreen @@ -14,7 +12,6 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.FilterList -import eu.kanade.tachiyomi.ui.base.controller.FabController import eu.kanade.tachiyomi.ui.base.controller.FullComposeController import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController @@ -38,8 +35,7 @@ import xyz.nulldev.ts.api.http.serializer.FilterSerializer * [SourceFeedCardAdapter.OnMangaClickListener] called when manga is clicked in global search */ open class SourceFeedController : - FullComposeController, - FabController { + FullComposeController { constructor(source: CatalogueSource?) : super( bundleOf( @@ -58,8 +54,6 @@ open class SourceFeedController : var source: CatalogueSource? = null - private var actionFab: ExtendedFloatingActionButton? = null - /** * Sheet containing filter items. */ @@ -89,10 +83,6 @@ open class SourceFeedController : private val filterSerializer = FilterSerializer() fun initFilterSheet() { - if (presenter.sourceFilters.isEmpty()) { - actionFab?.text = activity!!.getString(R.string.saved_searches) - } - filterSheet = SourceFilterSheet( activity!!, // SY --> @@ -101,7 +91,7 @@ open class SourceFeedController : emptyList(), // SY <-- onFilterClicked = { - val allDefault = presenter.sourceFilters == presenter.source.getFilterList() + val allDefault = presenter.filters == presenter.source.getFilterList() filterSheet?.dismiss() if (allDefault) { onBrowseClick( @@ -110,7 +100,7 @@ open class SourceFeedController : } else { onBrowseClick( presenter.searchQuery?.nullIfBlank(), - filters = Json.encodeToString(filterSerializer.serialize(presenter.sourceFilters)), + filters = Json.encodeToString(filterSerializer.serialize(presenter.filters)), ) } }, @@ -135,9 +125,9 @@ open class SourceFeedController : return@launchUI } - presenter.sourceFilters = FilterList(search.filterList) + presenter.setFilters(FilterList(search.filterList)) filterSheet?.setFilters(presenter.filterItems) - val allDefault = presenter.sourceFilters == presenter.source.getFilterList() + val allDefault = presenter.filters == presenter.source.getFilterList() filterSheet?.dismiss() if (!allDefault) { @@ -171,35 +161,13 @@ open class SourceFeedController : filterSheet?.setSavedSearches(presenter.loadSearches()) } filterSheet?.setFilters(presenter.filterItems) - - // TODO: [ExtendedFloatingActionButton] hide/show methods don't work properly - filterSheet?.setOnShowListener { actionFab?.isVisible = false } - filterSheet?.setOnDismissListener { actionFab?.isVisible = true } - - actionFab?.setOnClickListener { filterSheet?.show() } - - actionFab?.isVisible = true - } - - override fun configureFab(fab: ExtendedFloatingActionButton) { - actionFab = fab - - // Controlled by initFilterSheet() - fab.isVisible = false - - fab.setText(R.string.action_filter) - fab.setIconResource(R.drawable.ic_filter_list_24dp) - } - - override fun cleanupFab(fab: ExtendedFloatingActionButton) { - fab.setOnClickListener(null) - actionFab = null } @Composable override fun ComposeContent() { SourceFeedScreen( presenter = presenter, + onFabClick = { filterSheet?.show() }, onClickBrowse = ::onBrowseClick, onClickLatest = ::onLatestClick, onClickSavedSearch = ::onSavedSearchClick, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt index ddacf989c..a2bf5359e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/feed/SourceFeedPresenter.kt @@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.browse.source.feed import android.os.Bundle import androidx.compose.runtime.getValue -import eu.davidea.flexibleadapter.items.IFlexible import eu.kanade.domain.manga.interactor.GetManga import eu.kanade.domain.manga.interactor.InsertManga import eu.kanade.domain.manga.interactor.UpdateManga @@ -12,7 +11,6 @@ import eu.kanade.domain.source.interactor.CountFeedSavedSearchBySourceId import eu.kanade.domain.source.interactor.DeleteFeedSavedSearchById import eu.kanade.domain.source.interactor.GetExhSavedSearch import eu.kanade.domain.source.interactor.GetFeedSavedSearchBySourceId -import eu.kanade.domain.source.interactor.GetSavedSearchBySourceId import eu.kanade.domain.source.interactor.GetSavedSearchBySourceIdFeed import eu.kanade.domain.source.interactor.InsertFeedSavedSearch import eu.kanade.presentation.browse.SourceFeedState @@ -27,8 +25,7 @@ import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.ui.browse.source.browse.toItems -import eu.kanade.tachiyomi.util.lang.launchIO +import eu.kanade.tachiyomi.util.lang.launchNonCancellableIO import eu.kanade.tachiyomi.util.lang.runAsObservable import eu.kanade.tachiyomi.util.system.logcat import exh.savedsearches.models.FeedSavedSearch @@ -53,8 +50,6 @@ import xyz.nulldev.ts.api.http.serializer.FilterSerializer * Function calls should be done from here. UI calls should be done from the controller. * * @param source the source. - * @param handler manages the database calls. - * @param preferences manages the preference calls. */ open class SourceFeedPresenter( private val state: SourceFeedStateImpl = SourceFeedState() as SourceFeedStateImpl, @@ -66,7 +61,6 @@ open class SourceFeedPresenter( private val getFeedSavedSearchBySourceId: GetFeedSavedSearchBySourceId = Injekt.get(), private val getSavedSearchBySourceIdFeed: GetSavedSearchBySourceIdFeed = Injekt.get(), private val countFeedSavedSearchBySourceId: CountFeedSavedSearchBySourceId = Injekt.get(), - private val getSavedSearchBySourceId: GetSavedSearchBySourceId = Injekt.get(), private val insertFeedSavedSearch: InsertFeedSavedSearch = Injekt.get(), private val deleteFeedSavedSearchById: DeleteFeedSavedSearchById = Injekt.get(), private val getExhSavedSearch: GetExhSavedSearch = Injekt.get(), @@ -90,21 +84,10 @@ open class SourceFeedPresenter( */ private var fetchImageSubscription: Subscription? = null - /** - * Modifiable list of filters. - */ - var sourceFilters = FilterList() - set(value) { - field = value - filterItems = value.toItems() - } - - var filterItems: List> = emptyList() - override fun onCreate(savedState: Bundle?) { super.onCreate(savedState) - sourceFilters = source.getFilterList() + setFilters(source.getFilterList()) getFeedSavedSearchBySourceId.subscribe(source.id) .onEach { @@ -122,16 +105,16 @@ open class SourceFeedPresenter( super.onDestroy() } + fun setFilters(filters: FilterList) { + state.filters = filters + } + suspend fun hasTooManyFeeds(): Boolean { return countFeedSavedSearchBySourceId.await(source.id) > 10 } - suspend fun getSourceSavedSearches(): List { - return getSavedSearchBySourceId.await(source.id) - } - fun createFeed(savedSearchId: Long) { - launchIO { + presenterScope.launchNonCancellableIO { insertFeedSavedSearch.await( FeedSavedSearch( id = -1, @@ -144,7 +127,7 @@ open class SourceFeedPresenter( } fun deleteFeed(feed: FeedSavedSearch) { - launchIO { + presenterScope.launchNonCancellableIO { deleteFeedSavedSearchById.await(feed.id) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt index 0ccb5ffc8..3f972e8b3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/filter/AutoComplete.kt @@ -85,7 +85,7 @@ open class AutoComplete(val filter: Filter.AutoComplete) : AbstractFlexibleItem< override fun equals(other: Any?): Boolean { if (this === other) return true if (javaClass != other?.javaClass) return false - return filter == (other as SelectItem).filter + return filter == (other as AutoComplete).filter } override fun hashCode(): Int {