From 42c640cc8fa15d6b36e931249601520c4ca4775d Mon Sep 17 00:00:00 2001 From: HuanCheng65 <22636177+HuanCheng65@users.noreply.github.com> Date: Thu, 1 Feb 2024 14:09:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A6=96=E9=A1=B5=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E6=9C=80=E8=BF=91=E6=B5=8F=E8=A7=88=E7=9A=84=E5=90=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interceptors/ConnectivityInterceptor.kt | 3 +- .../tieba/post/models/ForumHistoryExtra.kt | 10 ++ .../tieba/post/models/database/History.kt | 2 + .../tieba/post/services/OKSignService.kt | 2 +- .../tieba/post/ui/page/forum/ForumPage.kt | 6 +- .../tieba/post/ui/page/main/home/HomePage.kt | 132 ++++++++++++++++-- .../post/ui/page/main/home/HomeViewModel.kt | 71 ++++++++-- .../tieba/post/utils/HistoryUtil.kt | 46 +++--- .../post/utils/{ => extension}/FlagExt.kt | 2 +- .../post/utils/extension/LitePalFlowExt.kt | 31 ++++ app/src/main/res/values/strings.xml | 1 + 11 files changed, 255 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/com/huanchengfly/tieba/post/models/ForumHistoryExtra.kt rename app/src/main/java/com/huanchengfly/tieba/post/utils/{ => extension}/FlagExt.kt (84%) create mode 100644 app/src/main/java/com/huanchengfly/tieba/post/utils/extension/LitePalFlowExt.kt diff --git a/app/src/main/java/com/huanchengfly/tieba/post/api/retrofit/interceptors/ConnectivityInterceptor.kt b/app/src/main/java/com/huanchengfly/tieba/post/api/retrofit/interceptors/ConnectivityInterceptor.kt index 7768b301..6b003cf0 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/api/retrofit/interceptors/ConnectivityInterceptor.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/api/retrofit/interceptors/ConnectivityInterceptor.kt @@ -9,6 +9,7 @@ import okhttp3.Response import java.io.IOException import java.net.SocketException import java.net.SocketTimeoutException +import javax.net.ssl.SSLHandshakeException object ConnectivityInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { @@ -17,7 +18,7 @@ object ConnectivityInterceptor : Interceptor { val exception = response.exceptionOrNull() return when { - (exception is SocketTimeoutException || exception is SocketException) && isNetworkConnected() -> throw NoConnectivityException( + (exception is SocketTimeoutException || exception is SocketException || exception is SSLHandshakeException) && isNetworkConnected() -> throw NoConnectivityException( App.INSTANCE.getString(R.string.connectivity_timeout) ) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/models/ForumHistoryExtra.kt b/app/src/main/java/com/huanchengfly/tieba/post/models/ForumHistoryExtra.kt new file mode 100644 index 00000000..80515a30 --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/models/ForumHistoryExtra.kt @@ -0,0 +1,10 @@ +package com.huanchengfly.tieba.post.models + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class ForumHistoryExtra( + @SerialName("forum_id") + val forumId: Long, +) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/models/database/History.kt b/app/src/main/java/com/huanchengfly/tieba/post/models/database/History.kt index dabaeae8..352956b5 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/models/database/History.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/models/database/History.kt @@ -1,7 +1,9 @@ package com.huanchengfly.tieba.post.models.database +import androidx.compose.runtime.Immutable import org.litepal.crud.LitePalSupport +@Immutable data class History( val title: String = "", val data: String = "", diff --git a/app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt b/app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt index 47e7f73d..0e2592cf 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/services/OKSignService.kt @@ -21,7 +21,7 @@ import com.huanchengfly.tieba.post.ui.common.theme.utils.ThemeUtils import com.huanchengfly.tieba.post.utils.AccountUtil import com.huanchengfly.tieba.post.utils.ProgressListener import com.huanchengfly.tieba.post.utils.SingleAccountSigner -import com.huanchengfly.tieba.post.utils.addFlag +import com.huanchengfly.tieba.post.utils.extension.addFlag import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt index a292fac0..9f1e8f41 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/forum/ForumPage.kt @@ -92,6 +92,7 @@ import com.huanchengfly.tieba.post.arch.onEvent import com.huanchengfly.tieba.post.arch.pageViewModel import com.huanchengfly.tieba.post.dataStore import com.huanchengfly.tieba.post.getInt +import com.huanchengfly.tieba.post.models.ForumHistoryExtra import com.huanchengfly.tieba.post.models.database.History import com.huanchengfly.tieba.post.toastShort import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme @@ -133,6 +134,8 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import kotlin.math.absoluteValue import kotlin.math.max import kotlin.math.min @@ -474,7 +477,8 @@ fun ForumPage( timestamp = System.currentTimeMillis(), avatar = forum.avatar, type = HistoryUtil.TYPE_FORUM, - data = forum.name + data = forum.name, + extras = Json.encodeToString(ForumHistoryExtra(forum.id)) ), true ) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt index 007b6ac3..3bfcdf56 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomePage.kt @@ -2,11 +2,15 @@ package com.huanchengfly.tieba.post.ui.page.main.home import android.content.Context import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -17,19 +21,21 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.items +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.DropdownMenuItem import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme -import androidx.compose.material.Scaffold import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight import androidx.compose.material.icons.outlined.ViewAgenda import androidx.compose.material.icons.rounded.Check import androidx.compose.material.icons.rounded.Search @@ -37,6 +43,7 @@ import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -47,6 +54,7 @@ import androidx.compose.ui.Alignment.Companion.Center import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalContext @@ -83,6 +91,7 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen import com.huanchengfly.tieba.post.ui.widgets.compose.LongClickMenu import com.huanchengfly.tieba.post.ui.widgets.compose.MenuState import com.huanchengfly.tieba.post.ui.widgets.compose.MyLazyVerticalGrid +import com.huanchengfly.tieba.post.ui.widgets.compose.MyScaffold import com.huanchengfly.tieba.post.ui.widgets.compose.TextButton import com.huanchengfly.tieba.post.ui.widgets.compose.TipScreen import com.huanchengfly.tieba.post.ui.widgets.compose.Toolbar @@ -394,6 +403,14 @@ fun HomePage( prop1 = HomeUiState::topForums, initial = persistentListOf() ) + val historyForums by viewModel.uiState.collectPartialAsState( + prop1 = HomeUiState::historyForums, + initial = persistentListOf() + ) + val showHistoryForum by viewModel.uiState.collectPartialAsState( + prop1 = HomeUiState::showHistoryForum, + initial = true + ) val error by viewModel.uiState.collectPartialAsState( prop1 = HomeUiState::error, initial = null @@ -401,6 +418,7 @@ fun HomePage( val isLoggedIn = remember(account) { account != null } val isEmpty by remember { derivedStateOf { forums.isEmpty() } } val hasTopForum by remember { derivedStateOf { topForums.isNotEmpty() } } + val hasHistoryForum by remember { derivedStateOf { historyForums.isNotEmpty() } } var listSingle by remember { mutableStateOf(context.appPreferences.listSingle) } val isError by remember { derivedStateOf { error != null } } val gridCells by remember { derivedStateOf { getGridCells(context, listSingle) } } @@ -429,7 +447,11 @@ fun HomePage( ) } - Scaffold( + LaunchedEffect(Unit) { + if (viewModel.initialized) viewModel.send(HomeUiIntent.RefreshHistory) + } + + MyScaffold( backgroundColor = Color.Transparent, topBar = { Toolbar( @@ -464,7 +486,7 @@ fun HomePage( .padding(contentPaddings) ) { Column { - SearchBox(modifier = Modifier.padding(bottom = 12.dp)) { + SearchBox(modifier = Modifier.padding(bottom = 4.dp)) { navigator.navigate(SearchPageDestination) } StateScreen( @@ -496,14 +518,103 @@ fun HomePage( contentPadding = PaddingValues(bottom = 12.dp), modifier = Modifier.fillMaxSize(), ) { + if (hasHistoryForum) { + item(key = "HistoryForums", span = { GridItemSpan(maxLineSpan) }) { + val rotate by animateFloatAsState( + targetValue = if (showHistoryForum) 90f else 0f, + label = "rotate" + ) + Column { + Row( + verticalAlignment = CenterVertically, + modifier = Modifier + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null + ) { + viewModel.send( + HomeUiIntent.ToggleHistory( + showHistoryForum + ) + ) + } + .padding(vertical = 8.dp) + .padding(end = 16.dp) + ) { + Header( + text = stringResource(id = R.string.title_history_forum), + invert = false + ) + + Spacer(modifier = Modifier.weight(1f)) + + Icon( + imageVector = Icons.AutoMirrored.Rounded.KeyboardArrowRight, + contentDescription = stringResource(id = R.string.desc_show), + modifier = Modifier + .size(24.dp) + .rotate(rotate) + ) + } + AnimatedVisibility(visible = showHistoryForum) { + LazyRow( + contentPadding = PaddingValues(bottom = 8.dp), + ) { + item(key = "Spacer1") { + Spacer(modifier = Modifier.width(12.dp)) + } + items( + historyForums, + key = { it.data } + ) { + Row( + modifier = Modifier + .padding(horizontal = 4.dp) + .height(IntrinsicSize.Min) + .clip(RoundedCornerShape(100)) + .background(color = ExtendedTheme.colors.chip) + .clickable { + navigator.navigate( + ForumPageDestination( + it.data + ) + ) + } + .padding(4.dp), + verticalAlignment = CenterVertically, + horizontalArrangement = Arrangement.spacedBy(4.dp) + ) { + Avatar( + data = it.avatar, + contentDescription = null, + size = 24.dp, + shape = CircleShape + ) + Text( + text = it.title, + fontSize = 12.sp, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(end = 4.dp) + ) + } + } + item(key = "Spacer2") { + Spacer(modifier = Modifier.width(12.dp)) + } + } + } + } + } + } if (hasTopForum) { item(key = "TopForumHeader", span = { GridItemSpan(maxLineSpan) }) { - Column { + Column( + modifier = Modifier.padding(vertical = 8.dp) + ) { Header( text = stringResource(id = R.string.title_top_forum), invert = true ) - Spacer(modifier = Modifier.height(8.dp)) } } items( @@ -529,11 +640,11 @@ fun HomePage( isTopForum = true ) } + } + if (hasHistoryForum || hasTopForum) { item(key = "ForumHeader", span = { GridItemSpan(maxLineSpan) }) { Column( - modifier = Modifier.padding( - vertical = 8.dp - ) + modifier = Modifier.padding(vertical = 8.dp) ) { Header(text = stringResource(id = R.string.forum_list_title)) } @@ -588,7 +699,9 @@ private fun HomePageSkeletonScreen( .fillMaxSize(), ) { item(key = "TopForumHeaderPlaceholder", span = { GridItemSpan(maxLineSpan) }) { - Column { + Column( + modifier = Modifier.padding(vertical = 8.dp) + ) { Header( text = stringResource(id = R.string.title_top_forum), modifier = Modifier.placeholder( @@ -597,7 +710,6 @@ private fun HomePageSkeletonScreen( ), invert = true ) - Spacer(modifier = Modifier.height(8.dp)) } } items(6, key = { "TopPlaceholder$it" }) { diff --git a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomeViewModel.kt b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomeViewModel.kt index 8f74ff15..602bde80 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomeViewModel.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/ui/page/main/home/HomeViewModel.kt @@ -4,7 +4,6 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import com.huanchengfly.tieba.post.api.TiebaApi import com.huanchengfly.tieba.post.api.models.CommonResponse -import com.huanchengfly.tieba.post.api.models.protos.forumRecommend.ForumRecommendResponse import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage import com.huanchengfly.tieba.post.arch.BaseViewModel import com.huanchengfly.tieba.post.arch.CommonUiEvent @@ -13,8 +12,10 @@ import com.huanchengfly.tieba.post.arch.PartialChangeProducer import com.huanchengfly.tieba.post.arch.UiEvent import com.huanchengfly.tieba.post.arch.UiIntent import com.huanchengfly.tieba.post.arch.UiState +import com.huanchengfly.tieba.post.models.database.History import com.huanchengfly.tieba.post.models.database.TopForum import com.huanchengfly.tieba.post.utils.AccountUtil +import com.huanchengfly.tieba.post.utils.HistoryUtil import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList @@ -25,10 +26,12 @@ import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.flatMapConcat import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.zip import org.litepal.LitePal @Stable @@ -52,18 +55,25 @@ class HomeViewModel : BaseViewModel() .flatMapConcat { produceRefreshPartialChangeFlow() }, + intentFlow.filterIsInstance() + .flatMapConcat { produceRefreshHistoryPartialChangeFlow() }, intentFlow.filterIsInstance() .flatMapConcat { it.toPartialChangeFlow() }, intentFlow.filterIsInstance() .flatMapConcat { it.toPartialChangeFlow() }, intentFlow.filterIsInstance() .flatMapConcat { it.toPartialChangeFlow() }, + intentFlow.filterIsInstance() + .flatMapConcat { it.toPartialChangeFlow() } ) } - private fun produceRefreshPartialChangeFlow() = - TiebaApi.getInstance().forumRecommendNewFlow() - .map { forumRecommend -> + @Suppress("USELESS_CAST") + private fun produceRefreshPartialChangeFlow(): Flow = + HistoryUtil.getFlow(HistoryUtil.TYPE_FORUM, 0) + .zip( + TiebaApi.getInstance().forumRecommendNewFlow() + ) { historyForums, forumRecommend -> val forums = forumRecommend.data_?.like_forum?.map { HomeUiState.Forum( it.avatar, @@ -76,11 +86,21 @@ class HomeViewModel : BaseViewModel() val topForumsDB = LitePal.findAll(TopForum::class.java).map { it.forumId } topForums.addAll(forums.filter { topForumsDB.contains(it.forumId) }) - HomePartialChange.Refresh.Success(forums, topForums) + HomePartialChange.Refresh.Success( + forums, + topForums, + historyForums + ) as HomePartialChange.Refresh } .onStart { emit(HomePartialChange.Refresh.Start) } .catch { emit(HomePartialChange.Refresh.Failure(it)) } + @Suppress("USELESS_CAST") + private fun produceRefreshHistoryPartialChangeFlow(): Flow = + HistoryUtil.getFlow(HistoryUtil.TYPE_FORUM, 0) + .map { HomePartialChange.RefreshHistory.Success(it) as HomePartialChange.RefreshHistory } + .catch { emit(HomePartialChange.RefreshHistory.Failure(it)) } + private fun HomeUiIntent.TopForums.Delete.toPartialChangeFlow() = flow { val deletedRows = LitePal.deleteAll(TopForum::class.java, "forumId = ?", forumId) @@ -110,11 +130,16 @@ class HomeViewModel : BaseViewModel { @@ -153,6 +180,7 @@ sealed interface HomePartialChange : PartialChange { isLoading = false, forums = forums.toImmutableList(), topForums = topForums.toImmutableList(), + historyForums = historyForums.toImmutableList(), error = null ) @@ -160,18 +188,38 @@ sealed interface HomePartialChange : PartialChange { Start -> oldState.copy(isLoading = true) } - object Start : Refresh() + data object Start : Refresh() data class Success( val forums: List, val topForums: List, + val historyForums: List, ) : Refresh() data class Failure( - val error: Throwable + val error: Throwable, ) : Refresh() } + sealed class RefreshHistory : HomePartialChange { + override fun reduce(oldState: HomeUiState): HomeUiState = + when (this) { + is Success -> oldState.copy( + historyForums = historyForums.toImmutableList(), + ) + + else -> oldState + } + + data class Success( + val historyForums: List, + ) : RefreshHistory() + + data class Failure( + val error: Throwable, + ) : RefreshHistory() + } + sealed interface TopForums : HomePartialChange { sealed interface Delete : HomePartialChange { override fun reduce(oldState: HomeUiState): HomeUiState = @@ -207,6 +255,11 @@ sealed interface HomePartialChange : PartialChange { data class Failure(val errorMessage: String) : Add } } + + data class ToggleHistory(val show: Boolean) : HomePartialChange { + override fun reduce(oldState: HomeUiState): HomeUiState = + oldState.copy(showHistoryForum = show) + } } @Immutable @@ -214,6 +267,8 @@ data class HomeUiState( val isLoading: Boolean = true, val forums: ImmutableList = persistentListOf(), val topForums: ImmutableList = persistentListOf(), + val historyForums: ImmutableList = persistentListOf(), + val showHistoryForum: Boolean = true, val error: Throwable? = null, ) : UiState { @Immutable diff --git a/app/src/main/java/com/huanchengfly/tieba/post/utils/HistoryUtil.kt b/app/src/main/java/com/huanchengfly/tieba/post/utils/HistoryUtil.kt index b43e654a..5026f361 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/utils/HistoryUtil.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/utils/HistoryUtil.kt @@ -1,15 +1,13 @@ package com.huanchengfly.tieba.post.utils import com.huanchengfly.tieba.post.models.database.History -import kotlinx.coroutines.Dispatchers +import com.huanchengfly.tieba.post.utils.extension.findFlow import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOn -import org.litepal.LitePal.deleteAll -import org.litepal.LitePal.order -import org.litepal.LitePal.where +import org.litepal.LitePal import org.litepal.crud.async.FindMultiExecutor +import org.litepal.extension.deleteAll import org.litepal.extension.find +import org.litepal.extension.findAsync import org.litepal.extension.findFirstAsync object HistoryUtil { @@ -17,7 +15,7 @@ object HistoryUtil { const val TYPE_FORUM = 1 const val TYPE_THREAD = 2 fun deleteAll() { - deleteAll(History::class.java) + LitePal.deleteAll() } @JvmOverloads @@ -30,43 +28,33 @@ object HistoryUtil { } val all: List - get() = order("timestamp desc, count desc").limit(100).find( - History::class.java - ) + get() = LitePal.order("timestamp desc, count desc").limit(100).find() fun getAll(type: Int): List { - return order("timestamp desc, count desc").where("type = ?", type.toString()) + return LitePal.order("timestamp desc, count desc").where("type = ?", type.toString()) .limit(PAGE_SIZE) - .find( - History::class.java - ) + .find() } fun getAllAsync(type: Int): FindMultiExecutor { - return order("timestamp desc, count desc").where("type = ?", type.toString()) + return LitePal.order("timestamp desc, count desc").where("type = ?", type.toString()) .limit(PAGE_SIZE) - .findAsync( - History::class.java - ) + .findAsync() } fun getFlow( type: Int, page: Int ): Flow> { - return flow> { - emit( - where("type = ?", "$type") - .order("timestamp desc, count desc") - .limit(PAGE_SIZE) - .offset(page * 100) - .find() - ) - }.flowOn(Dispatchers.IO) + return LitePal.where("type = ?", "$type") + .order("timestamp desc, count desc") + .limit(PAGE_SIZE) + .offset(page * 100) + .findFlow() } private fun update(history: History): Boolean { - val historyBean = where("data = ?", history.data).findFirst( + val historyBean = LitePal.where("data = ?", history.data).findFirst( History::class.java ) if (historyBean != null) { @@ -87,7 +75,7 @@ object HistoryUtil { history: History, callback: ((Boolean) -> Unit)? = null, ) { - where("data = ?", history.data).findFirstAsync() + LitePal.where("data = ?", history.data).findFirstAsync() .listen { if (it == null) { callback?.invoke(false) diff --git a/app/src/main/java/com/huanchengfly/tieba/post/utils/FlagExt.kt b/app/src/main/java/com/huanchengfly/tieba/post/utils/extension/FlagExt.kt similarity index 84% rename from app/src/main/java/com/huanchengfly/tieba/post/utils/FlagExt.kt rename to app/src/main/java/com/huanchengfly/tieba/post/utils/extension/FlagExt.kt index c91039ea..ba428026 100644 --- a/app/src/main/java/com/huanchengfly/tieba/post/utils/FlagExt.kt +++ b/app/src/main/java/com/huanchengfly/tieba/post/utils/extension/FlagExt.kt @@ -1,4 +1,4 @@ -package com.huanchengfly.tieba.post.utils +package com.huanchengfly.tieba.post.utils.extension /** * 添加flag diff --git a/app/src/main/java/com/huanchengfly/tieba/post/utils/extension/LitePalFlowExt.kt b/app/src/main/java/com/huanchengfly/tieba/post/utils/extension/LitePalFlowExt.kt new file mode 100644 index 00000000..82555850 --- /dev/null +++ b/app/src/main/java/com/huanchengfly/tieba/post/utils/extension/LitePalFlowExt.kt @@ -0,0 +1,31 @@ +package com.huanchengfly.tieba.post.utils.extension + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import org.litepal.FluentQuery +import org.litepal.LitePal +import org.litepal.extension.find +import org.litepal.extension.findAll + +inline fun LitePal.findAllFlow(vararg ids: Long): Flow> = + flow { + emit( + findAll(*ids) + ) + }.flowOn(Dispatchers.IO) + +inline fun LitePal.findAllFlow(isEager: Boolean, vararg ids: Long): Flow> = + flow { + emit( + findAll(isEager, *ids) + ) + }.flowOn(Dispatchers.IO) + +inline fun FluentQuery.findFlow(): Flow> = + flow { + emit( + find() + ) + }.flowOn(Dispatchers.IO) \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fb749e4e..d008ff9d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -514,4 +514,5 @@ 当前 Android 版本不支持照片选择器 将使用 App 内置的照片选择器 将使用原生的照片选择器 + 显示