Allow refreshing the feed tab

This commit is contained in:
Jobobby04 2023-02-04 19:58:09 -05:00
parent 59d307c6a1
commit 475fb82c66
3 changed files with 68 additions and 15 deletions

View File

@ -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<Manga>,
) {
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,
)
}
}
}
}

View File

@ -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
}

View File

@ -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) },
)