feat: 首页显示最近浏览的吧
This commit is contained in:
parent
c7164e2c71
commit
42c640cc8f
|
|
@ -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)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
)
|
||||
|
|
@ -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 = "",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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" }) {
|
||||
|
|
|
|||
|
|
@ -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<HomeUiIntent, HomePartialChange, HomeUiState
|
|||
return merge(
|
||||
intentFlow.filterIsInstance<HomeUiIntent.Refresh>()
|
||||
.flatMapConcat { produceRefreshPartialChangeFlow() },
|
||||
intentFlow.filterIsInstance<HomeUiIntent.RefreshHistory>()
|
||||
.flatMapConcat { produceRefreshHistoryPartialChangeFlow() },
|
||||
intentFlow.filterIsInstance<HomeUiIntent.TopForums.Delete>()
|
||||
.flatMapConcat { it.toPartialChangeFlow() },
|
||||
intentFlow.filterIsInstance<HomeUiIntent.TopForums.Add>()
|
||||
.flatMapConcat { it.toPartialChangeFlow() },
|
||||
intentFlow.filterIsInstance<HomeUiIntent.Unfollow>()
|
||||
.flatMapConcat { it.toPartialChangeFlow() },
|
||||
intentFlow.filterIsInstance<HomeUiIntent.ToggleHistory>()
|
||||
.flatMapConcat { it.toPartialChangeFlow() }
|
||||
)
|
||||
}
|
||||
|
||||
private fun produceRefreshPartialChangeFlow() =
|
||||
TiebaApi.getInstance().forumRecommendNewFlow()
|
||||
.map<ForumRecommendResponse, HomePartialChange.Refresh> { forumRecommend ->
|
||||
@Suppress("USELESS_CAST")
|
||||
private fun produceRefreshPartialChangeFlow(): Flow<HomePartialChange.Refresh> =
|
||||
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<HomeUiIntent, HomePartialChange, HomeUiState
|
|||
val topForums = mutableListOf<HomeUiState.Forum>()
|
||||
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<HomePartialChange.RefreshHistory> =
|
||||
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<HomeUiIntent, HomePartialChange, HomeUiState
|
|||
HomePartialChange.Unfollow.Success(forumId)
|
||||
}
|
||||
.catch { emit(HomePartialChange.Unfollow.Failure(it.getErrorMessage())) }
|
||||
|
||||
private fun HomeUiIntent.ToggleHistory.toPartialChangeFlow() =
|
||||
flowOf(HomePartialChange.ToggleHistory(!currentShow))
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface HomeUiIntent : UiIntent {
|
||||
object Refresh : HomeUiIntent
|
||||
data object Refresh : HomeUiIntent
|
||||
|
||||
data object RefreshHistory : HomeUiIntent
|
||||
|
||||
data class Unfollow(val forumId: String, val forumName: String) : HomeUiIntent
|
||||
|
||||
|
|
@ -123,6 +148,8 @@ sealed interface HomeUiIntent : UiIntent {
|
|||
|
||||
data class Add(val forum: HomeUiState.Forum) : TopForums
|
||||
}
|
||||
|
||||
data class ToggleHistory(val currentShow: Boolean) : HomeUiIntent
|
||||
}
|
||||
|
||||
sealed interface HomePartialChange : PartialChange<HomeUiState> {
|
||||
|
|
@ -153,6 +180,7 @@ sealed interface HomePartialChange : PartialChange<HomeUiState> {
|
|||
isLoading = false,
|
||||
forums = forums.toImmutableList(),
|
||||
topForums = topForums.toImmutableList(),
|
||||
historyForums = historyForums.toImmutableList(),
|
||||
error = null
|
||||
)
|
||||
|
||||
|
|
@ -160,18 +188,38 @@ sealed interface HomePartialChange : PartialChange<HomeUiState> {
|
|||
Start -> oldState.copy(isLoading = true)
|
||||
}
|
||||
|
||||
object Start : Refresh()
|
||||
data object Start : Refresh()
|
||||
|
||||
data class Success(
|
||||
val forums: List<HomeUiState.Forum>,
|
||||
val topForums: List<HomeUiState.Forum>,
|
||||
val historyForums: List<History>,
|
||||
) : 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<History>,
|
||||
) : 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<HomeUiState> {
|
|||
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<Forum> = persistentListOf(),
|
||||
val topForums: ImmutableList<Forum> = persistentListOf(),
|
||||
val historyForums: ImmutableList<History> = persistentListOf(),
|
||||
val showHistoryForum: Boolean = true,
|
||||
val error: Throwable? = null,
|
||||
) : UiState {
|
||||
@Immutable
|
||||
|
|
|
|||
|
|
@ -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<History>()
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
|
|
@ -30,43 +28,33 @@ object HistoryUtil {
|
|||
}
|
||||
|
||||
val all: List<History>
|
||||
get() = order("timestamp desc, count desc").limit(100).find(
|
||||
History::class.java
|
||||
)
|
||||
get() = LitePal.order("timestamp desc, count desc").limit(100).find<History>()
|
||||
|
||||
fun getAll(type: Int): List<History> {
|
||||
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<History>()
|
||||
}
|
||||
|
||||
fun getAllAsync(type: Int): FindMultiExecutor<History> {
|
||||
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<History>()
|
||||
}
|
||||
|
||||
fun getFlow(
|
||||
type: Int,
|
||||
page: Int
|
||||
): Flow<List<History>> {
|
||||
return flow<List<History>> {
|
||||
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<History?>()
|
||||
LitePal.where("data = ?", history.data).findFirstAsync<History?>()
|
||||
.listen {
|
||||
if (it == null) {
|
||||
callback?.invoke(false)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.huanchengfly.tieba.post.utils
|
||||
package com.huanchengfly.tieba.post.utils.extension
|
||||
|
||||
/**
|
||||
* 添加flag
|
||||
|
|
@ -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 <reified T> LitePal.findAllFlow(vararg ids: Long): Flow<List<T>> =
|
||||
flow {
|
||||
emit(
|
||||
findAll<T>(*ids)
|
||||
)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
inline fun <reified T> LitePal.findAllFlow(isEager: Boolean, vararg ids: Long): Flow<List<T>> =
|
||||
flow {
|
||||
emit(
|
||||
findAll<T>(isEager, *ids)
|
||||
)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
||||
inline fun <reified T> FluentQuery.findFlow(): Flow<List<T>> =
|
||||
flow {
|
||||
emit(
|
||||
find<T>()
|
||||
)
|
||||
}.flowOn(Dispatchers.IO)
|
||||
|
|
@ -514,4 +514,5 @@
|
|||
<string name="summary_photo_picker_not_supported">当前 Android 版本不支持照片选择器</string>
|
||||
<string name="summary_do_not_use_photo_picker">将使用 App 内置的照片选择器</string>
|
||||
<string name="summary_use_photo_picker">将使用原生的照片选择器</string>
|
||||
<string name="desc_show">显示</string>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue