From 475fb82c6607347821e11f8b7c7a546e397acd6c Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 4 Feb 2023 19:58:09 -0500 Subject: [PATCH] Allow refreshing the feed tab --- .../kanade/presentation/browse/FeedScreen.kt | 53 +++++++++++++------ .../ui/browse/feed/FeedScreenModel.kt | 25 +++++++++ .../tachiyomi/ui/browse/feed/FeedTab.kt | 5 ++ 3 files changed, 68 insertions(+), 15 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 446ee78c9..d75c46c2f 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding @@ -30,6 +31,7 @@ import androidx.compose.material3.RadioButton import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -49,6 +51,7 @@ import eu.kanade.presentation.components.BadgeGroup import eu.kanade.presentation.components.EmptyScreen import eu.kanade.presentation.components.LoadingScreen import eu.kanade.presentation.components.MangaCover +import eu.kanade.presentation.components.PullRefresh import eu.kanade.presentation.components.ScrollbarLazyColumn import eu.kanade.presentation.util.plus import eu.kanade.presentation.util.topSmallPaddingValues @@ -57,6 +60,8 @@ import eu.kanade.tachiyomi.source.CatalogueSource import eu.kanade.tachiyomi.ui.browse.feed.FeedScreenState import exh.savedsearches.models.FeedSavedSearch import exh.savedsearches.models.SavedSearch +import kotlinx.coroutines.delay +import kotlin.time.Duration.Companion.seconds import eu.kanade.domain.manga.model.MangaCover as MangaCoverData data class FeedItemUI( @@ -76,6 +81,7 @@ fun FeedScreen( onClickSource: (CatalogueSource) -> Unit, onClickDelete: (FeedSavedSearch) -> Unit, onClickManga: (Manga) -> Unit, + onRefresh: () -> Unit, getMangaState: @Composable (Manga, CatalogueSource?) -> State, ) { when { @@ -85,22 +91,39 @@ fun FeedScreen( modifier = Modifier.padding(contentPadding), ) else -> { - ScrollbarLazyColumn( - contentPadding = contentPadding + topSmallPaddingValues, + var refreshing by remember { mutableStateOf(false) } + LaunchedEffect(refreshing) { + if (refreshing) { + delay(1.seconds) + refreshing = false + } + } + PullRefresh( + refreshing = refreshing && state.isLoadingItems, + onRefresh = { + refreshing = true + onRefresh() + }, + enabled = !state.isLoadingItems, ) { - items( - state.items.orEmpty(), - key = { it.feed.id }, - ) { item -> - FeedItem( - modifier = Modifier.animateItemPlacement(), - item = item, - getMangaState = { getMangaState(it, item.source) }, - onClickSavedSearch = onClickSavedSearch, - onClickSource = onClickSource, - onClickDelete = onClickDelete, - onClickManga = onClickManga, - ) + ScrollbarLazyColumn( + contentPadding = contentPadding + topSmallPaddingValues, + modifier = Modifier.fillMaxSize(), + ) { + items( + state.items.orEmpty(), + key = { it.feed.id }, + ) { item -> + FeedItem( + modifier = Modifier.animateItemPlacement(), + item = item, + getMangaState = { getMangaState(it, item.source) }, + onClickSavedSearch = onClickSavedSearch, + onClickSource = onClickSource, + onClickDelete = onClickDelete, + onClickManga = onClickManga, + ) + } } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt index 24527426a..05998508b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedScreenModel.kt @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.browse.feed import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.produceState +import androidx.compose.ui.util.fastAny import cafe.adriel.voyager.core.model.StateScreenModel import cafe.adriel.voyager.core.model.coroutineScope import eu.kanade.domain.manga.interactor.GetManga @@ -48,6 +49,8 @@ import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import xyz.nulldev.ts.api.http.serializer.FilterSerializer import java.util.concurrent.Executors +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds import eu.kanade.domain.manga.model.Manga as DomainManga /** @@ -71,6 +74,7 @@ open class FeedScreenModel( val events = _events.receiveAsFlow() private val coroutineDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher() + var lastRefresh = System.currentTimeMillis().milliseconds init { getFeedSavedSearchGlobal.subscribe() @@ -95,6 +99,24 @@ open class FeedScreenModel( .launchIn(coroutineScope) } + fun init() { + if (lastRefresh - System.currentTimeMillis().milliseconds > 30.seconds) return + refresh() + } + + fun refresh() { + lastRefresh = System.currentTimeMillis().milliseconds + coroutineScope.launchIO { + val newItems = state.value.items?.map { it.copy(results = null) } ?: return@launchIO + mutableState.update { state -> + state.copy( + items = newItems, + ) + } + getFeed(newItems) + } + } + fun openAddDialog() { coroutineScope.launchIO { if (hasTooManyFeeds()) { @@ -321,4 +343,7 @@ data class FeedScreenState( val isEmpty get() = items.isNullOrEmpty() + + val isLoadingItems + get() = items?.fastAny { it.results == null } != false } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt index 2506f44e5..0de29ec4b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/feed/FeedTab.kt @@ -30,6 +30,10 @@ fun Screen.feedTab(): TabContent { val screenModel = rememberScreenModel { FeedScreenModel() } val state by screenModel.state.collectAsState() + LaunchedEffect(Unit) { + screenModel.init() + } + return TabContent( titleRes = R.string.feed, actions = listOf( @@ -68,6 +72,7 @@ fun Screen.feedTab(): TabContent { onClickManga = { manga -> navigator.push(MangaScreen(manga.id, true)) }, + onRefresh = screenModel::refresh, getMangaState = { manga, source -> screenModel.getManga(initialManga = manga, source = source) }, )