Browse Source

HistoryScreen: Remove paging (#8125)

* HistoryScreen: Remove paging

Per my testing performance-wise there's virtually no
difference in loading time.

* cleanups

* add key and contentType
Ivan Iskandar 2 years ago
parent
commit
42b0e3e438

+ 5 - 8
app/src/main/java/eu/kanade/data/history/HistoryRepositoryImpl.kt

@@ -1,6 +1,5 @@
 package eu.kanade.data.history
 
-import androidx.paging.PagingSource
 import eu.kanade.data.DatabaseHandler
 import eu.kanade.data.chapter.chapterMapper
 import eu.kanade.data.manga.mangaMapper
@@ -10,19 +9,17 @@ import eu.kanade.domain.history.model.HistoryWithRelations
 import eu.kanade.domain.history.repository.HistoryRepository
 import eu.kanade.domain.manga.model.Manga
 import eu.kanade.tachiyomi.util.system.logcat
+import kotlinx.coroutines.flow.Flow
 import logcat.LogPriority
 
 class HistoryRepositoryImpl(
     private val handler: DatabaseHandler,
 ) : HistoryRepository {
 
-    override fun getHistory(query: String): PagingSource<Long, HistoryWithRelations> {
-        return handler.subscribeToPagingSource(
-            countQuery = { historyViewQueries.countHistory(query) },
-            queryProvider = { limit, offset ->
-                historyViewQueries.history(query, limit, offset, historyWithRelationsMapper)
-            },
-        )
+    override fun getHistory(query: String): Flow<List<HistoryWithRelations>> {
+        return handler.subscribeToList {
+            historyViewQueries.history(query, historyWithRelationsMapper)
+        }
     }
 
     override suspend fun getLastHistory(): HistoryWithRelations? {

+ 2 - 10
app/src/main/java/eu/kanade/domain/history/interactor/GetHistory.kt

@@ -1,8 +1,5 @@
 package eu.kanade.domain.history.interactor
 
-import androidx.paging.Pager
-import androidx.paging.PagingConfig
-import androidx.paging.PagingData
 import eu.kanade.domain.history.model.HistoryWithRelations
 import eu.kanade.domain.history.repository.HistoryRepository
 import kotlinx.coroutines.flow.Flow
@@ -10,12 +7,7 @@ import kotlinx.coroutines.flow.Flow
 class GetHistory(
     private val repository: HistoryRepository,
 ) {
-
-    fun subscribe(query: String): Flow<PagingData<HistoryWithRelations>> {
-        return Pager(
-            PagingConfig(pageSize = 25),
-        ) {
-            repository.getHistory(query)
-        }.flow
+    fun subscribe(query: String): Flow<List<HistoryWithRelations>> {
+        return repository.getHistory(query)
     }
 }

+ 2 - 2
app/src/main/java/eu/kanade/domain/history/repository/HistoryRepository.kt

@@ -1,13 +1,13 @@
 package eu.kanade.domain.history.repository
 
-import androidx.paging.PagingSource
 import eu.kanade.domain.chapter.model.Chapter
 import eu.kanade.domain.history.model.HistoryUpdate
 import eu.kanade.domain.history.model.HistoryWithRelations
+import kotlinx.coroutines.flow.Flow
 
 interface HistoryRepository {
 
-    fun getHistory(query: String): PagingSource<Long, HistoryWithRelations>
+    fun getHistory(query: String): Flow<List<HistoryWithRelations>>
 
     suspend fun getLastHistory(): HistoryWithRelations?
 

+ 20 - 14
app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt

@@ -2,8 +2,9 @@ package eu.kanade.presentation.history
 
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
 import androidx.compose.ui.platform.LocalContext
-import androidx.paging.LoadState
 import eu.kanade.domain.history.model.HistoryWithRelations
 import eu.kanade.presentation.components.EmptyScreen
 import eu.kanade.presentation.components.LoadingScreen
@@ -39,20 +40,25 @@ fun HistoryScreen(
             )
         },
     ) { contentPadding ->
-        val items = presenter.getLazyHistory()
-        when {
-            items.loadState.refresh is LoadState.Loading && items.itemCount < 1 -> LoadingScreen()
-            items.loadState.refresh is LoadState.NotLoading && items.itemCount < 1 -> EmptyScreen(textResource = R.string.information_no_recent_manga)
-            else -> HistoryContent(
-                history = items,
-                contentPadding = contentPadding,
-                onClickCover = onClickCover,
-                onClickResume = onClickResume,
-                onClickDelete = { presenter.dialog = Dialog.Delete(it) },
-            )
+        val items by presenter.getHistory().collectAsState(initial = null)
+        items.let {
+            if (it == null) {
+                LoadingScreen()
+            } else if (it.isEmpty()) {
+                EmptyScreen(textResource = R.string.information_no_recent_manga)
+            } else {
+                HistoryContent(
+                    history = it,
+                    contentPadding = contentPadding,
+                    onClickCover = onClickCover,
+                    onClickResume = onClickResume,
+                    onClickDelete = { item -> presenter.dialog = Dialog.Delete(item) },
+                )
+            }
         }
-        LaunchedEffect(items.loadState.refresh) {
-            if (items.loadState.refresh is LoadState.NotLoading) {
+
+        LaunchedEffect(items) {
+            if (items != null) {
                 (presenter.view?.activity as? MainActivity)?.ready = true
             }
         }

+ 13 - 41
app/src/main/java/eu/kanade/presentation/history/components/HistoryContent.kt

@@ -1,19 +1,10 @@
 package eu.kanade.presentation.history.components
 
-import androidx.compose.animation.core.LinearEasing
-import androidx.compose.animation.core.animateFloat
-import androidx.compose.animation.core.infiniteRepeatable
-import androidx.compose.animation.core.rememberInfiniteTransition
-import androidx.compose.animation.core.tween
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.lazy.rememberLazyListState
+import androidx.compose.foundation.lazy.items
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Brush
-import androidx.paging.compose.LazyPagingItems
-import androidx.paging.compose.items
 import eu.kanade.domain.history.model.HistoryWithRelations
 import eu.kanade.domain.ui.UiPreferences
 import eu.kanade.presentation.components.RelativeDateHeader
@@ -21,7 +12,6 @@ import eu.kanade.presentation.components.ScrollbarLazyColumn
 import eu.kanade.presentation.history.HistoryUiModel
 import eu.kanade.presentation.util.bottomNavPaddingValues
 import eu.kanade.presentation.util.plus
-import eu.kanade.presentation.util.shimmerGradient
 import eu.kanade.presentation.util.topPaddingValues
 import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
@@ -29,7 +19,7 @@ import java.text.DateFormat
 
 @Composable
 fun HistoryContent(
-    history: LazyPagingItems<HistoryUiModel>,
+    history: List<HistoryUiModel>,
     contentPadding: PaddingValues,
     onClickCover: (HistoryWithRelations) -> Unit,
     onClickResume: (HistoryWithRelations) -> Unit,
@@ -41,14 +31,21 @@ fun HistoryContent(
 
     ScrollbarLazyColumn(
         contentPadding = contentPadding + bottomNavPaddingValues + topPaddingValues,
-        state = rememberLazyListState(),
     ) {
-        items(history) { item ->
+        items(
+            items = history,
+            key = { "history-${it.hashCode()}" },
+            contentType = {
+                when (it) {
+                    is HistoryUiModel.Header -> "header"
+                    is HistoryUiModel.Item -> "item"
+                }
+            },
+        ) { item ->
             when (item) {
                 is HistoryUiModel.Header -> {
                     RelativeDateHeader(
-                        modifier = Modifier
-                            .animateItemPlacement(),
+                        modifier = Modifier.animateItemPlacement(),
                         date = item.date,
                         relativeTime = relativeTime,
                         dateFormat = dateFormat,
@@ -64,31 +61,6 @@ fun HistoryContent(
                         onClickDelete = { onClickDelete(value) },
                     )
                 }
-                null -> {
-                    val transition = rememberInfiniteTransition()
-                    val translateAnimation = transition.animateFloat(
-                        initialValue = 0f,
-                        targetValue = 1000f,
-                        animationSpec = infiniteRepeatable(
-                            animation = tween(
-                                durationMillis = 1000,
-                                easing = LinearEasing,
-                            ),
-                        ),
-                    )
-
-                    val brush = remember {
-                        Brush.linearGradient(
-                            colors = shimmerGradient,
-                            start = Offset(0f, 0f),
-                            end = Offset(
-                                x = translateAnimation.value,
-                                y = 00f,
-                            ),
-                        )
-                    }
-                    HistoryItemShimmer(brush = brush)
-                }
             }
         }
     }

+ 2 - 51
app/src/main/java/eu/kanade/presentation/history/components/HistoryItem.kt

@@ -1,15 +1,11 @@
 package eu.kanade.presentation.history.components
 
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.aspectRatio
 import androidx.compose.foundation.layout.fillMaxHeight
-import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.outlined.Delete
 import androidx.compose.material3.Icon
@@ -20,9 +16,6 @@ import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.draw.drawBehind
-import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.text.style.TextOverflow
@@ -65,9 +58,10 @@ fun HistoryItem(
             val textStyle = MaterialTheme.typography.bodyMedium
             Text(
                 text = history.title,
+                fontWeight = FontWeight.SemiBold,
                 maxLines = 2,
                 overflow = TextOverflow.Ellipsis,
-                style = textStyle.copy(fontWeight = FontWeight.SemiBold),
+                style = textStyle,
             )
             val readAt = remember { history.readAt?.toTimestampString() ?: "" }
             Text(
@@ -95,49 +89,6 @@ fun HistoryItem(
     }
 }
 
-@Composable
-fun HistoryItemShimmer(brush: Brush) {
-    Row(
-        modifier = Modifier
-            .height(HISTORY_ITEM_HEIGHT)
-            .padding(horizontal = horizontalPadding, vertical = 8.dp),
-        verticalAlignment = Alignment.CenterVertically,
-    ) {
-        Box(
-            modifier = Modifier
-                .fillMaxHeight()
-                .aspectRatio(MangaCover.Book.ratio)
-                .clip(RoundedCornerShape(4.dp))
-                .drawBehind {
-                    drawRect(brush = brush)
-                },
-        )
-        Column(
-            modifier = Modifier
-                .weight(1f)
-                .padding(start = horizontalPadding, end = 8.dp),
-        ) {
-            Box(
-                modifier = Modifier
-                    .drawBehind {
-                        drawRect(brush = brush)
-                    }
-                    .height(14.dp)
-                    .fillMaxWidth(0.70f),
-            )
-            Box(
-                modifier = Modifier
-                    .padding(top = 4.dp)
-                    .height(14.dp)
-                    .fillMaxWidth(0.45f)
-                    .drawBehind {
-                        drawRect(brush = brush)
-                    },
-            )
-        }
-    }
-}
-
 private val chapterFormatter = DecimalFormat(
     "#.###",
     DecimalFormatSymbols().apply { decimalSeparator = '.' },

+ 0 - 9
app/src/main/java/eu/kanade/presentation/util/Shimmer.kt

@@ -1,9 +0,0 @@
-package eu.kanade.presentation.util
-
-import androidx.compose.ui.graphics.Color
-
-val shimmerGradient = listOf(
-    Color.LightGray.copy(alpha = 0.8f),
-    Color.LightGray.copy(alpha = 0.2f),
-    Color.LightGray.copy(alpha = 0.8f),
-)

+ 7 - 16
app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt

@@ -5,14 +5,8 @@ import androidx.compose.runtime.Stable
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
-import androidx.paging.PagingData
-import androidx.paging.cachedIn
-import androidx.paging.compose.LazyPagingItems
-import androidx.paging.compose.collectAsLazyPagingItems
-import androidx.paging.insertSeparators
-import androidx.paging.map
+import eu.kanade.core.util.insertSeparators
 import eu.kanade.domain.base.BasePreferences
 import eu.kanade.domain.chapter.model.Chapter
 import eu.kanade.domain.history.interactor.DeleteHistoryTable
@@ -32,6 +26,7 @@ import eu.kanade.tachiyomi.util.system.toast
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.receiveAsFlow
 import logcat.LogPriority
@@ -57,11 +52,11 @@ class HistoryPresenter(
     val isIncognitoMode: Boolean by preferences.incognitoMode().asState()
 
     @Composable
-    fun getLazyHistory(): LazyPagingItems<HistoryUiModel> {
-        val scope = rememberCoroutineScope()
+    fun getHistory(): Flow<List<HistoryUiModel>> {
         val query = searchQuery ?: ""
-        val flow = remember(query) {
+        return remember(query) {
             getHistory.subscribe(query)
+                .distinctUntilChanged()
                 .catch { error ->
                     logcat(LogPriority.ERROR, error)
                     _events.send(Event.InternalError)
@@ -69,15 +64,11 @@ class HistoryPresenter(
                 .map { pagingData ->
                     pagingData.toHistoryUiModels()
                 }
-                .cachedIn(scope)
         }
-        return flow.collectAsLazyPagingItems()
     }
 
-    private fun PagingData<HistoryWithRelations>.toHistoryUiModels(): PagingData<HistoryUiModel> {
-        return this.map {
-            HistoryUiModel.Item(it)
-        }
+    private fun List<HistoryWithRelations>.toHistoryUiModels(): List<HistoryUiModel> {
+        return map { HistoryUiModel.Item(it) }
             .insertSeparators { before, after ->
                 val beforeDate = before?.item?.readAt?.time?.toDateKey() ?: Date(0)
                 val afterDate = after?.item?.readAt?.time?.toDateKey() ?: Date(0)

+ 1 - 9
app/src/main/sqldelight/view/historyView.sq

@@ -26,13 +26,6 @@ JOIN (
 ) AS max_last_read
 ON chapters.manga_id = max_last_read.manga_id;
 
-countHistory:
-SELECT count(*)
-FROM historyView
-WHERE historyView.readAt > 0
-AND maxReadAtChapterId = historyView.chapterId
-AND lower(historyView.title) LIKE ('%' || :query || '%');
-
 history:
 SELECT
 id,
@@ -50,8 +43,7 @@ FROM historyView
 WHERE historyView.readAt > 0
 AND maxReadAtChapterId = historyView.chapterId
 AND lower(historyView.title) LIKE ('%' || :query || '%')
-ORDER BY readAt DESC
-LIMIT :limit OFFSET :offset;
+ORDER BY readAt DESC;
 
 getLatestHistory:
 SELECT