Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.parcelize)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ksp)
alias(libs.plugins.spotless)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.hippo.ehviewer.ui.screen

import android.content.Context
import android.view.ViewConfiguration
import androidx.collection.MutableLongSet
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
Expand Down Expand Up @@ -41,6 +42,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
Expand All @@ -50,8 +52,14 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.paging.cachedIn
import androidx.paging.compose.collectAsLazyPagingItems
import androidx.paging.filter
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
Expand All @@ -76,31 +84,38 @@ import com.hippo.ehviewer.ui.startDownload
import com.hippo.ehviewer.ui.tools.asyncState
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.awaitSelectItem
import com.hippo.ehviewer.ui.tools.foldToLoadResult
import com.hippo.ehviewer.ui.tools.rememberInVM
import com.hippo.ehviewer.ui.tools.rememberSerializable
import com.hippo.ehviewer.ui.tools.thenIf
import com.hippo.ehviewer.util.mapToLongArray
import com.hippo.ehviewer.util.takeAndClear
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.lang.withUIContext
import kotlin.math.roundToInt
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import moe.tarsin.coroutines.onEachLatest
import moe.tarsin.coroutines.runSuspendCatching
import moe.tarsin.coroutines.runSwallowingWithUI
import moe.tarsin.launch
import moe.tarsin.navigate

@Destination<RootGraph>
@Composable
fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, viewModel: FavoritesViewModel = viewModel()) = Screen(navigator) {
fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator) = Screen(navigator) {
// Immutables
val localFavName = stringResource(R.string.local_favorites)
val cloudFavName = stringResource(R.string.cloud_favorites)
val animateItems by Settings.animateItems.collectAsState()
val hasSignedIn by Settings.hasSignedIn.collectAsState()

// Meta State
var urlBuilder by viewModel.urlBuilder
var urlBuilder by rememberSerializable { mutableStateOf(FavListUrlBuilder(favCat = Settings.recentFavCat)) }
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
var searchBarOffsetY by remember { mutableIntStateOf(0) }

Expand All @@ -120,15 +135,64 @@ fun AnimatedVisibilityScope.FavouritesScreen(navigator: DestinationsNavigator, v
}
val density = LocalDensity.current
val searchBarHint = stringResource(R.string.search_bar_hint, favCatName)
val data = viewModel.data.collectAsLazyPagingItems()
val data = rememberInVM {
snapshotFlow { urlBuilder.isLocal }.flatMapLatest { isLocalFav ->
if (isLocalFav) {
Pager(PagingConfig(20, jumpThreshold = 40)) {
val keywordNow = urlBuilder.keyword.orEmpty()
if (keywordNow.isBlank()) {
EhDB.localFavLazyList
} else {
EhDB.searchLocalFav(keywordNow)
}
}
} else {
Pager(PagingConfig(25)) {
object : PagingSource<String, BaseGalleryInfo>() {
override fun getRefreshKey(state: PagingState<String, BaseGalleryInfo>): String? = null
override suspend fun load(params: LoadParams<String>) = withIOContext {
when (params) {
is LoadParams.Prepend -> urlBuilder.setIndex(params.key, isNext = false)
is LoadParams.Append -> urlBuilder.setIndex(params.key, isNext = true)
is LoadParams.Refresh -> {
val key = params.key
if (key.isNullOrBlank()) {
if (urlBuilder.jumpTo != null) {
urlBuilder.next ?: urlBuilder.setIndex("2", true)
}
} else {
urlBuilder.setIndex(key, false)
}
}
}
runSuspendCatching {
EhEngine.getFavorites(urlBuilder.build())
}.foldToLoadResult { result ->
Settings.favCat = result.catArray.toTypedArray()
Settings.favCount = result.countArray.toIntArray()
Settings.favCloudCount = result.countArray.sum()
urlBuilder.jumpTo = null
LoadResult.Page(result.galleryInfoList, result.prev, result.next)
}
}
}
}
}.flow.map { pagingData ->
// https://github.com/FooIbar/EhViewer/issues/1190
// Workaround for duplicate items when sorting by favorited time
val gidSet = MutableLongSet(50)
pagingData.filter { gidSet.add(it.gid) }
}
}.cachedIn(viewModelScope)
}.collectAsLazyPagingItems()

fun refresh(newUrlBuilder: FavListUrlBuilder = urlBuilder.copy(jumpTo = null, prev = null, next = null)) {
urlBuilder = newUrlBuilder
data.refresh()
}

ProvideSideSheetContent { sheetState ->
val localFavCount by viewModel.localFavCount.collectAsState(0)
val localFavCount by rememberInVM { EhDB.localFavCount }.collectAsState(0)
TopAppBar(
title = { Text(text = stringResource(id = R.string.collections)) },
windowInsets = WindowInsets(),
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,24 @@
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.LoadState
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.paging.cachedIn
import androidx.paging.compose.collectAsLazyPagingItems
import arrow.core.raise.ensure
import arrow.core.raise.ensureNotNull
import com.hippo.ehviewer.EhDB
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.asMutableState
import com.hippo.ehviewer.client.EhEngine
import com.hippo.ehviewer.client.EhTagDatabase
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.data.BaseGalleryInfo
import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_IMAGE_SEARCH
import com.hippo.ehviewer.client.data.ListUrlBuilder.Companion.MODE_NORMAL
Expand Down Expand Up @@ -111,19 +117,24 @@
import com.hippo.ehviewer.ui.tools.awaitConfirmationOrCancel
import com.hippo.ehviewer.ui.tools.awaitInputText
import com.hippo.ehviewer.ui.tools.awaitInputTextWithCheckBox
import com.hippo.ehviewer.ui.tools.foldToLoadResult
import com.hippo.ehviewer.ui.tools.rememberHapticFeedback
import com.hippo.ehviewer.ui.tools.rememberInVM
import com.hippo.ehviewer.ui.tools.rememberMutableStateInDataStore
import com.hippo.ehviewer.ui.tools.rememberSerializable
import com.hippo.ehviewer.ui.tools.thenIf
import com.hippo.ehviewer.util.FavouriteStatusRouter
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.spec.Direction
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.lang.withUIContext
import kotlin.math.roundToInt
import kotlin.random.Random
import kotlinx.coroutines.delay
import moe.tarsin.coroutines.onEachLatest
import moe.tarsin.coroutines.runSuspendCatching
import moe.tarsin.launch
import moe.tarsin.launchIO
import moe.tarsin.navigate
Expand All @@ -150,13 +161,9 @@

@Destination<RootGraph>
@Composable
fun AnimatedVisibilityScope.GalleryListScreen(
lub: ListUrlBuilder,
navigator: DestinationsNavigator,
viewModel: GalleryListViewModel = viewModel { GalleryListViewModel(lub, createSavedStateHandle()) },
) = Screen(navigator) {
fun AnimatedVisibilityScope.GalleryListScreen(lub: ListUrlBuilder, navigator: DestinationsNavigator) = Screen(navigator) {
val searchFieldState = rememberTextFieldState()
var urlBuilder by viewModel.urlBuilder
var urlBuilder by rememberSerializable { mutableStateOf(lub) }
var searchBarExpanded by rememberSaveable { mutableStateOf(false) }
var searchBarOffsetY by remember { mutableIntStateOf(0) }
val animateItems by Settings.animateItems.collectAsState()
Expand Down Expand Up @@ -187,7 +194,49 @@
val exHint = stringResource(R.string.gallery_list_search_bar_hint_exhentai)
val searchBarHint by rememberUpdatedState(if (EhUtils.isExHentai) exHint else ehHint)
val suitableTitle = getSuitableTitleForUrlBuilder(urlBuilder)
val data = viewModel.data.collectAsLazyPagingItems()
val data = rememberInVM {
Pager(PagingConfig(25)) {
object : PagingSource<String, BaseGalleryInfo>() {
override fun getRefreshKey(state: PagingState<String, BaseGalleryInfo>): String? = null
override suspend fun load(params: LoadParams<String>) = withIOContext {
if (urlBuilder.mode == MODE_TOPLIST) {
// TODO: Since we know total pages, let pager support jump

Check warning on line 203 in app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt

View check run for this annotation

codefactor.io / CodeFactor

app/src/main/kotlin/com/hippo/ehviewer/ui/screen/GalleryListScreen.kt#L203

Forbidden TODO todo marker in comment, please do the changes. (detekt.ForbiddenComment)
val key = (params.key ?: urlBuilder.jumpTo)?.toInt() ?: 0
val prev = (key - 1).takeIf { it > 0 }
val next = (key + 1).takeIf { it < TOPLIST_PAGES }
runSuspendCatching {
urlBuilder.setJumpTo(key)
EhEngine.getGalleryList(urlBuilder.build())
}.foldToLoadResult { result ->
LoadResult.Page(result.galleryInfoList, prev?.toString(), next?.toString())
}
} else {
when (params) {
is LoadParams.Prepend -> urlBuilder.setIndex(params.key, isNext = false)
is LoadParams.Append -> urlBuilder.setIndex(params.key, isNext = true)
is LoadParams.Refresh -> {
val key = params.key
if (key.isNullOrBlank()) {
if (urlBuilder.jumpTo != null) {
urlBuilder.next ?: urlBuilder.setIndex("2", true)
}
} else {
urlBuilder.setIndex(key, false)
}
}
}
runSuspendCatching {
val url = urlBuilder.build()
EhEngine.getGalleryList(url)
}.foldToLoadResult { result ->
urlBuilder.jumpTo = null
LoadResult.Page(result.galleryInfoList, result.prev, result.next)
}
}
}
}
}.flow.cachedIn(viewModelScope)
}.collectAsLazyPagingItems()
ReportDrawnWhen { data.loadState.refresh !is LoadState.Loading }
FavouriteStatusRouter.Observe(data)
val listMode by Settings.listMode.collectAsState()
Expand Down
Loading