feat: 贴页面错误提示
This commit is contained in:
parent
2f1ab3b038
commit
67052d4a91
|
|
@ -4,4 +4,8 @@ import com.huanchengfly.tieba.post.api.Error.ERROR_NETWORK
|
||||||
|
|
||||||
class NoConnectivityException(
|
class NoConnectivityException(
|
||||||
msg: String = "No internet!"
|
msg: String = "No internet!"
|
||||||
) : TiebaLocalException(ERROR_NETWORK, msg)
|
) : TiebaLocalException(ERROR_NETWORK, msg) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NoConnectivityException(message=$message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,11 @@ import com.huanchengfly.tieba.post.api.models.CommonResponse
|
||||||
|
|
||||||
class TiebaApiException(
|
class TiebaApiException(
|
||||||
private val commonResponse: CommonResponse
|
private val commonResponse: CommonResponse
|
||||||
) : TiebaException(commonResponse.errorMsg?.takeIf { it.isNotEmpty() } ?: "未知错误") {
|
) : TiebaException(commonResponse.errorMsg.takeIf { it.isNotEmpty() } ?: "未知错误") {
|
||||||
override val code: Int
|
override val code: Int
|
||||||
get() = commonResponse.errorCode ?: -1
|
get() = commonResponse.errorCode
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "TiebaApiException(code=$code, message=$message, commonResponse=$commonResponse)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -4,4 +4,13 @@ import java.io.IOException
|
||||||
|
|
||||||
abstract class TiebaException(message: String) : IOException(message) {
|
abstract class TiebaException(message: String) : IOException(message) {
|
||||||
abstract val code: Int
|
abstract val code: Int
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "TiebaException(code=$code, message=$message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object TiebaUnknownException : TiebaException("未知错误") {
|
||||||
|
override val code: Int
|
||||||
|
get() = -1
|
||||||
}
|
}
|
||||||
|
|
@ -3,4 +3,8 @@ package com.huanchengfly.tieba.post.api.retrofit.exception
|
||||||
open class TiebaLocalException(
|
open class TiebaLocalException(
|
||||||
override val code: Int,
|
override val code: Int,
|
||||||
msg: String
|
msg: String
|
||||||
) : TiebaException(msg)
|
) : TiebaException(msg) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "TiebaLocalException(code=$code, message=$message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,4 +4,8 @@ import com.huanchengfly.tieba.post.api.Error.ERROR_NOT_LOGGED_IN
|
||||||
|
|
||||||
class TiebaNotLoggedInException(
|
class TiebaNotLoggedInException(
|
||||||
msg: String = "Not logged in!"
|
msg: String = "Not logged in!"
|
||||||
) : TiebaLocalException(ERROR_NOT_LOGGED_IN, msg)
|
) : TiebaLocalException(ERROR_NOT_LOGGED_IN, msg) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "TiebaNotLoggedInException(message=$message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -120,6 +120,7 @@ import com.huanchengfly.tieba.post.ui.widgets.compose.BackNavigationIcon
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.Card
|
import com.huanchengfly.tieba.post.ui.widgets.compose.Card
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ConfirmDialog
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ConfirmDialog
|
||||||
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ErrorScreen
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.HorizontalDivider
|
import com.huanchengfly.tieba.post.ui.widgets.compose.HorizontalDivider
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
import com.huanchengfly.tieba.post.ui.widgets.compose.LazyLoad
|
||||||
import com.huanchengfly.tieba.post.ui.widgets.compose.ListMenuItem
|
import com.huanchengfly.tieba.post.ui.widgets.compose.ListMenuItem
|
||||||
|
|
@ -457,6 +458,14 @@ fun ThreadPage(
|
||||||
prop1 = ThreadUiState::isLoadingMore,
|
prop1 = ThreadUiState::isLoadingMore,
|
||||||
initial = false
|
initial = false
|
||||||
)
|
)
|
||||||
|
val isError by viewModel.uiState.collectPartialAsState(
|
||||||
|
prop1 = ThreadUiState::isError,
|
||||||
|
initial = false
|
||||||
|
)
|
||||||
|
val error by viewModel.uiState.collectPartialAsState(
|
||||||
|
prop1 = ThreadUiState::error,
|
||||||
|
initial = null
|
||||||
|
)
|
||||||
val hasMore by viewModel.uiState.collectPartialAsState(
|
val hasMore by viewModel.uiState.collectPartialAsState(
|
||||||
prop1 = ThreadUiState::hasMore,
|
prop1 = ThreadUiState::hasMore,
|
||||||
initial = true
|
initial = true
|
||||||
|
|
@ -469,10 +478,6 @@ fun ThreadPage(
|
||||||
prop1 = ThreadUiState::hasPrevious,
|
prop1 = ThreadUiState::hasPrevious,
|
||||||
initial = true
|
initial = true
|
||||||
)
|
)
|
||||||
val currentPageMin by viewModel.uiState.collectPartialAsState(
|
|
||||||
prop1 = ThreadUiState::currentPageMin,
|
|
||||||
initial = 0
|
|
||||||
)
|
|
||||||
val currentPageMax by viewModel.uiState.collectPartialAsState(
|
val currentPageMax by viewModel.uiState.collectPartialAsState(
|
||||||
prop1 = ThreadUiState::currentPageMax,
|
prop1 = ThreadUiState::currentPageMax,
|
||||||
initial = 0
|
initial = 0
|
||||||
|
|
@ -707,8 +712,14 @@ fun ThreadPage(
|
||||||
ProvideNavigator(navigator = navigator) {
|
ProvideNavigator(navigator = navigator) {
|
||||||
StateScreen(
|
StateScreen(
|
||||||
isEmpty = isEmpty,
|
isEmpty = isEmpty,
|
||||||
isError = false,
|
isError = isError,
|
||||||
isLoading = isRefreshing,
|
isLoading = isRefreshing,
|
||||||
|
errorScreen = {
|
||||||
|
error?.let {
|
||||||
|
val (e) = it
|
||||||
|
ErrorScreen(error = e)
|
||||||
|
}
|
||||||
|
},
|
||||||
onReload = {
|
onReload = {
|
||||||
viewModel.send(
|
viewModel.send(
|
||||||
ThreadUiIntent.Load(
|
ThreadUiIntent.Load(
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import com.huanchengfly.tieba.post.api.models.protos.SimpleForum
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
import com.huanchengfly.tieba.post.api.models.protos.ThreadInfo
|
||||||
import com.huanchengfly.tieba.post.api.models.protos.User
|
import com.huanchengfly.tieba.post.api.models.protos.User
|
||||||
import com.huanchengfly.tieba.post.api.renders
|
import com.huanchengfly.tieba.post.api.renders
|
||||||
|
import com.huanchengfly.tieba.post.api.retrofit.exception.TiebaUnknownException
|
||||||
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorCode
|
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorCode
|
||||||
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
|
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
|
||||||
import com.huanchengfly.tieba.post.api.updateAgreeStatus
|
import com.huanchengfly.tieba.post.api.updateAgreeStatus
|
||||||
|
|
@ -108,7 +109,7 @@ class ThreadViewModel @Inject constructor() :
|
||||||
fun ThreadUiIntent.Init.producePartialChange(): Flow<ThreadPartialChange.Init> =
|
fun ThreadUiIntent.Init.producePartialChange(): Flow<ThreadPartialChange.Init> =
|
||||||
flowOf<ThreadPartialChange.Init>(
|
flowOf<ThreadPartialChange.Init>(
|
||||||
ThreadPartialChange.Init.Success(
|
ThreadPartialChange.Init.Success(
|
||||||
threadInfo?.title ?: "",
|
threadInfo?.title.orEmpty(),
|
||||||
threadInfo?.author,
|
threadInfo?.author,
|
||||||
threadInfo,
|
threadInfo,
|
||||||
threadInfo?.firstPostContent?.renders ?: emptyList(),
|
threadInfo?.firstPostContent?.renders ?: emptyList(),
|
||||||
|
|
@ -116,18 +117,14 @@ class ThreadViewModel @Inject constructor() :
|
||||||
seeLz,
|
seeLz,
|
||||||
sortType,
|
sortType,
|
||||||
)
|
)
|
||||||
).catch {
|
).catch { emit(ThreadPartialChange.Init.Failure(it)) }
|
||||||
emit(
|
|
||||||
ThreadPartialChange.Init.Failure(
|
|
||||||
it.getErrorCode(),
|
|
||||||
it.getErrorMessage()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ThreadUiIntent.Load.producePartialChange(): Flow<ThreadPartialChange.Load> =
|
fun ThreadUiIntent.Load.producePartialChange(): Flow<ThreadPartialChange.Load> =
|
||||||
PbPageRepository
|
PbPageRepository
|
||||||
.pbPage(threadId, page, postId, forumId, seeLz, sortType, from = from)
|
.pbPage(
|
||||||
|
threadId, page, postId, forumId, seeLz, sortType,
|
||||||
|
from = from.takeIf { it == ThreadPageFrom.FROM_STORE }.orEmpty()
|
||||||
|
)
|
||||||
.map { response ->
|
.map { response ->
|
||||||
if (
|
if (
|
||||||
response.data_?.page != null
|
response.data_?.page != null
|
||||||
|
|
@ -170,17 +167,10 @@ class ThreadViewModel @Inject constructor() :
|
||||||
seeLz,
|
seeLz,
|
||||||
sortType,
|
sortType,
|
||||||
)
|
)
|
||||||
} else ThreadPartialChange.Load.Failure(-1, "未知错误")
|
} else ThreadPartialChange.Load.Failure(TiebaUnknownException)
|
||||||
}
|
}
|
||||||
.onStart { emit(ThreadPartialChange.Load.Start) }
|
.onStart { emit(ThreadPartialChange.Load.Start) }
|
||||||
.catch {
|
.catch { emit(ThreadPartialChange.Load.Failure(it)) }
|
||||||
emit(
|
|
||||||
ThreadPartialChange.Load.Failure(
|
|
||||||
it.getErrorCode(),
|
|
||||||
it.getErrorMessage()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ThreadUiIntent.LoadFirstPage.producePartialChange(): Flow<ThreadPartialChange.LoadFirstPage> =
|
fun ThreadUiIntent.LoadFirstPage.producePartialChange(): Flow<ThreadPartialChange.LoadFirstPage> =
|
||||||
PbPageRepository
|
PbPageRepository
|
||||||
|
|
@ -220,17 +210,10 @@ class ThreadViewModel @Inject constructor() :
|
||||||
seeLz,
|
seeLz,
|
||||||
sortType,
|
sortType,
|
||||||
)
|
)
|
||||||
} else ThreadPartialChange.LoadFirstPage.Failure(-1, "未知错误")
|
} else ThreadPartialChange.LoadFirstPage.Failure(TiebaUnknownException)
|
||||||
}
|
}
|
||||||
.onStart { emit(ThreadPartialChange.LoadFirstPage.Start) }
|
.onStart { emit(ThreadPartialChange.LoadFirstPage.Start) }
|
||||||
.catch {
|
.catch { emit(ThreadPartialChange.LoadFirstPage.Failure(it)) }
|
||||||
emit(
|
|
||||||
ThreadPartialChange.LoadFirstPage.Failure(
|
|
||||||
it.getErrorCode(),
|
|
||||||
it.getErrorMessage()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun ThreadUiIntent.LoadMore.producePartialChange(): Flow<ThreadPartialChange.LoadMore> =
|
fun ThreadUiIntent.LoadMore.producePartialChange(): Flow<ThreadPartialChange.LoadMore> =
|
||||||
PbPageRepository
|
PbPageRepository
|
||||||
|
|
@ -488,6 +471,8 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
override fun reduce(oldState: ThreadUiState): ThreadUiState = when (this) {
|
override fun reduce(oldState: ThreadUiState): ThreadUiState = when (this) {
|
||||||
is Success -> oldState.copy(
|
is Success -> oldState.copy(
|
||||||
isRefreshing = true,
|
isRefreshing = true,
|
||||||
|
isError = false,
|
||||||
|
error = null,
|
||||||
title = title,
|
title = title,
|
||||||
author = if (author != null) wrapImmutable(author) else null,
|
author = if (author != null) wrapImmutable(author) else null,
|
||||||
threadInfo = threadInfo?.wrapImmutable(),
|
threadInfo = threadInfo?.wrapImmutable(),
|
||||||
|
|
@ -506,7 +491,10 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
sortType = sortType,
|
sortType = sortType,
|
||||||
)
|
)
|
||||||
|
|
||||||
is Failure -> oldState
|
is Failure -> oldState.copy(
|
||||||
|
isError = true,
|
||||||
|
error = error.wrapImmutable()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Success(
|
data class Success(
|
||||||
|
|
@ -520,8 +508,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
) : Init()
|
) : Init()
|
||||||
|
|
||||||
data class Failure(
|
data class Failure(
|
||||||
val errorCode: Int,
|
val error: Throwable
|
||||||
val errorMessage: String
|
|
||||||
) : Init()
|
) : Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,6 +518,8 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
|
|
||||||
is Success -> oldState.copy(
|
is Success -> oldState.copy(
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
|
isError = false,
|
||||||
|
error = null,
|
||||||
title = title,
|
title = title,
|
||||||
author = wrapImmutable(author),
|
author = wrapImmutable(author),
|
||||||
user = wrapImmutable(user),
|
user = wrapImmutable(user),
|
||||||
|
|
@ -553,7 +542,11 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
sortType = sortType,
|
sortType = sortType,
|
||||||
)
|
)
|
||||||
|
|
||||||
is Failure -> oldState.copy(isRefreshing = false)
|
is Failure -> oldState.copy(
|
||||||
|
isRefreshing = false,
|
||||||
|
isError = true,
|
||||||
|
error = error.wrapImmutable()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Start : Load()
|
object Start : Load()
|
||||||
|
|
@ -580,8 +573,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
) : Load()
|
) : Load()
|
||||||
|
|
||||||
data class Failure(
|
data class Failure(
|
||||||
val errorCode: Int,
|
val error: Throwable,
|
||||||
val errorMessage: String
|
|
||||||
) : Load()
|
) : Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,6 +582,8 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
is Start -> oldState.copy(isRefreshing = true)
|
is Start -> oldState.copy(isRefreshing = true)
|
||||||
is Success -> oldState.copy(
|
is Success -> oldState.copy(
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
|
isError = false,
|
||||||
|
error = null,
|
||||||
title = title,
|
title = title,
|
||||||
author = wrapImmutable(author),
|
author = wrapImmutable(author),
|
||||||
data = data.toImmutableList(),
|
data = data.toImmutableList(),
|
||||||
|
|
@ -607,7 +601,11 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
sortType = sortType,
|
sortType = sortType,
|
||||||
)
|
)
|
||||||
|
|
||||||
is Failure -> oldState.copy(isRefreshing = false)
|
is Failure -> oldState.copy(
|
||||||
|
isRefreshing = false,
|
||||||
|
isError = true,
|
||||||
|
error = error.wrapImmutable(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Start : LoadFirstPage()
|
object Start : LoadFirstPage()
|
||||||
|
|
@ -630,8 +628,7 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
) : LoadFirstPage()
|
) : LoadFirstPage()
|
||||||
|
|
||||||
data class Failure(
|
data class Failure(
|
||||||
val errorCode: Int,
|
val error: Throwable
|
||||||
val errorMessage: String
|
|
||||||
) : LoadFirstPage()
|
) : LoadFirstPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -866,6 +863,8 @@ sealed interface ThreadPartialChange : PartialChange<ThreadUiState> {
|
||||||
data class ThreadUiState(
|
data class ThreadUiState(
|
||||||
val isRefreshing: Boolean = false,
|
val isRefreshing: Boolean = false,
|
||||||
val isLoadingMore: Boolean = false,
|
val isLoadingMore: Boolean = false,
|
||||||
|
val isError: Boolean = false,
|
||||||
|
val error: ImmutableHolder<Throwable>? = null,
|
||||||
|
|
||||||
val hasMore: Boolean = true,
|
val hasMore: Boolean = true,
|
||||||
val nextPagePostId: Long = 0,
|
val nextPagePostId: Long = 0,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -653,7 +653,7 @@
|
||||||
<string name="no_internet_connectivity">无互联网连接</string>
|
<string name="no_internet_connectivity">无互联网连接</string>
|
||||||
<string name="connectivity_timeout">连接超时</string>
|
<string name="connectivity_timeout">连接超时</string>
|
||||||
<string name="title_no_internet_connectivity">网络找不到了</string>
|
<string name="title_no_internet_connectivity">网络找不到了</string>
|
||||||
<string name="title_api_error">服务器有一些自己的想法</string>
|
<string name="title_api_error">啊哦,出错了</string>
|
||||||
<string name="title_unknown_error">发生了一个奇怪的错误…</string>
|
<string name="title_unknown_error">发生了一个奇怪的错误…</string>
|
||||||
<string name="message_no_internet_connectivity">%s。请检查你的网络连接是否正常</string>
|
<string name="message_no_internet_connectivity">%s。请检查你的网络连接是否正常</string>
|
||||||
<string name="message_unknown_error">哦我的老伙计,我向你保证这真的是一个奇怪的错误……</string>
|
<string name="message_unknown_error">哦我的老伙计,我向你保证这真的是一个奇怪的错误……</string>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue