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
This commit is contained in:
Ivan Iskandar 2022-10-01 21:50:25 +07:00 committed by GitHub
parent 8d1f99a480
commit 42b0e3e438
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 52 additions and 160 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,10 @@
package eu.kanade.presentation.history.components 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.layout.PaddingValues
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier 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.history.model.HistoryWithRelations
import eu.kanade.domain.ui.UiPreferences import eu.kanade.domain.ui.UiPreferences
import eu.kanade.presentation.components.RelativeDateHeader 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.history.HistoryUiModel
import eu.kanade.presentation.util.bottomNavPaddingValues import eu.kanade.presentation.util.bottomNavPaddingValues
import eu.kanade.presentation.util.plus import eu.kanade.presentation.util.plus
import eu.kanade.presentation.util.shimmerGradient
import eu.kanade.presentation.util.topPaddingValues import eu.kanade.presentation.util.topPaddingValues
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
@ -29,7 +19,7 @@ import java.text.DateFormat
@Composable @Composable
fun HistoryContent( fun HistoryContent(
history: LazyPagingItems<HistoryUiModel>, history: List<HistoryUiModel>,
contentPadding: PaddingValues, contentPadding: PaddingValues,
onClickCover: (HistoryWithRelations) -> Unit, onClickCover: (HistoryWithRelations) -> Unit,
onClickResume: (HistoryWithRelations) -> Unit, onClickResume: (HistoryWithRelations) -> Unit,
@ -41,14 +31,21 @@ fun HistoryContent(
ScrollbarLazyColumn( ScrollbarLazyColumn(
contentPadding = contentPadding + bottomNavPaddingValues + topPaddingValues, 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) { when (item) {
is HistoryUiModel.Header -> { is HistoryUiModel.Header -> {
RelativeDateHeader( RelativeDateHeader(
modifier = Modifier modifier = Modifier.animateItemPlacement(),
.animateItemPlacement(),
date = item.date, date = item.date,
relativeTime = relativeTime, relativeTime = relativeTime,
dateFormat = dateFormat, dateFormat = dateFormat,
@ -64,31 +61,6 @@ fun HistoryContent(
onClickDelete = { onClickDelete(value) }, 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)
}
} }
} }
} }

View File

@ -1,15 +1,11 @@
package eu.kanade.presentation.history.components package eu.kanade.presentation.history.components
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@ -20,9 +16,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier 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.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
@ -65,9 +58,10 @@ fun HistoryItem(
val textStyle = MaterialTheme.typography.bodyMedium val textStyle = MaterialTheme.typography.bodyMedium
Text( Text(
text = history.title, text = history.title,
fontWeight = FontWeight.SemiBold,
maxLines = 2, maxLines = 2,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
style = textStyle.copy(fontWeight = FontWeight.SemiBold), style = textStyle,
) )
val readAt = remember { history.readAt?.toTimestampString() ?: "" } val readAt = remember { history.readAt?.toTimestampString() ?: "" }
Text( 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( private val chapterFormatter = DecimalFormat(
"#.###", "#.###",
DecimalFormatSymbols().apply { decimalSeparator = '.' }, DecimalFormatSymbols().apply { decimalSeparator = '.' },

View File

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

View File

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

View File

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