feat: Compose 举报

This commit is contained in:
HuanCheng65 2024-01-30 14:59:21 +08:00
parent 197d0626a7
commit 0c5c11a88d
No known key found for this signature in database
GPG Key ID: 5EC9DD60A32C7360
7 changed files with 90 additions and 15 deletions

View File

@ -1200,9 +1200,18 @@ interface ITiebaApi {
* @param postId PID * @param postId PID
*/ */
fun checkReportPost( fun checkReportPost(
postId: String postId: String,
): Call<CheckReportBean> ): Call<CheckReportBean>
/**
* 获取举报贴子/回贴页面 URL
*
* @param postId PID
*/
fun checkReportPostAsync(
postId: String,
): Deferred<ApiResult<CheckReportBean>>
/** /**
* 获得当前用户昵称需登录 * 获得当前用户昵称需登录
*/ */
@ -1213,7 +1222,7 @@ interface ITiebaApi {
*/ */
fun initNickNameFlow( fun initNickNameFlow(
bduss: String, bduss: String,
sToken: String sToken: String,
): Flow<InitNickNameBean> ): Flow<InitNickNameBean>
/** /**

View File

@ -910,6 +910,14 @@ object MixedTiebaApiImpl : ITiebaApi {
) )
) )
override fun checkReportPostAsync(postId: String): Deferred<ApiResult<CheckReportBean>> =
RetrofitTiebaApi.OFFICIAL_TIEBA_API.checkReportAsync(
category = "1",
reportParam = mapOf(
"pid" to postId
)
)
override fun initNickNameFlow(): Flow<InitNickNameBean> = override fun initNickNameFlow(): Flow<InitNickNameBean> =
RetrofitTiebaApi.OFFICIAL_TIEBA_API.initNickNameFlow() RetrofitTiebaApi.OFFICIAL_TIEBA_API.initNickNameFlow()

View File

@ -1,15 +1,21 @@
package com.huanchengfly.tieba.post.api.models package com.huanchengfly.tieba.post.api.models
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class CheckReportBean( data class CheckReportBean(
@SerialName("errno")
@SerializedName("errno") @SerializedName("errno")
var errorCode: Int?, var errorCode: Int?,
@SerialName("errmsg")
@SerializedName("errmsg") @SerializedName("errmsg")
var errorMsg: String?, var errorMsg: String?,
val data: CheckReportDataBean val data: CheckReportDataBean,
) { ) {
@Serializable
data class CheckReportDataBean( data class CheckReportDataBean(
val url: String? val url: String = "",
) )
} }

View File

@ -492,9 +492,19 @@ interface OfficialTiebaApi {
@Field("category") category: String, @Field("category") category: String,
@FieldMap reportParam: Map<String, String>, @FieldMap reportParam: Map<String, String>,
@Field("stoken") stoken: String? = AccountUtil.getLoginInfo() @Field("stoken") stoken: String? = AccountUtil.getLoginInfo()
?.sToken ?.sToken,
): Call<CheckReportBean> ): Call<CheckReportBean>
@Headers("${Header.FORCE_LOGIN}: ${Header.FORCE_LOGIN_TRUE}")
@POST("/c/f/ueg/checkjubao")
@FormUrlEncoded
fun checkReportAsync(
@Field("category") category: String,
@FieldMap reportParam: Map<String, String>,
@Field("stoken") stoken: String? = AccountUtil.getLoginInfo()
?.sToken,
): Deferred<ApiResult<CheckReportBean>>
@Headers("${Header.FORCE_LOGIN}: ${Header.FORCE_LOGIN_TRUE}") @Headers("${Header.FORCE_LOGIN}: ${Header.FORCE_LOGIN_TRUE}")
@POST("/c/c/bawu/delthread") @POST("/c/c/bawu/delthread")
@FormUrlEncoded @FormUrlEncoded

View File

@ -24,13 +24,14 @@ import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material.icons.rounded.Close import androidx.compose.material.icons.rounded.Close
import androidx.compose.material.icons.rounded.OpenInBrowser import androidx.compose.material.icons.rounded.OpenInBrowser
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@ -88,6 +89,7 @@ import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.spec.DestinationStyleBottomSheet import com.ramcosta.composedestinations.spec.DestinationStyleBottomSheet
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@Destination @Destination
@Composable @Composable
@ -282,7 +284,7 @@ internal fun SubPostsContent(
navigationIcon = { navigationIcon = {
IconButton(onClick = { navigator.navigateUp() }) { IconButton(onClick = { navigator.navigateUp() }) {
Icon( Icon(
imageVector = if (isSheet) Icons.Rounded.Close else Icons.Rounded.ArrowBack, imageVector = if (isSheet) Icons.Rounded.Close else Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = stringResource(id = R.string.btn_close) contentDescription = stringResource(id = R.string.btn_close)
) )
} }
@ -535,6 +537,8 @@ private fun SubPostItem(
) { ) {
val (subPost, contentRenders, blocked) = item val (subPost, contentRenders, blocked) = item
val context = LocalContext.current val context = LocalContext.current
val navigator = LocalNavigator.current
val coroutineScope = rememberCoroutineScope()
val author = remember(subPost) { subPost.get { author }?.wrapImmutable() } val author = remember(subPost) { subPost.get { author }?.wrapImmutable() }
val hasAgreed = remember(subPost) { val hasAgreed = remember(subPost) {
subPost.get { agree?.hasAgree == 1 } subPost.get { agree?.hasAgree == 1 }
@ -576,7 +580,9 @@ private fun SubPostItem(
} }
DropdownMenuItem( DropdownMenuItem(
onClick = { onClick = {
TiebaUtil.reportPost(context, subPost.get { id }.toString()) coroutineScope.launch {
TiebaUtil.reportPost(context, navigator, subPost.get { id }.toString())
}
menuState.expanded = false menuState.expanded = false
} }
) { ) {

View File

@ -122,6 +122,7 @@ import com.huanchengfly.tieba.post.ui.common.theme.compose.invertChipBackground
import com.huanchengfly.tieba.post.ui.common.theme.compose.invertChipContent import com.huanchengfly.tieba.post.ui.common.theme.compose.invertChipContent
import com.huanchengfly.tieba.post.ui.common.theme.compose.pullRefreshIndicator import com.huanchengfly.tieba.post.ui.common.theme.compose.pullRefreshIndicator
import com.huanchengfly.tieba.post.ui.common.theme.compose.threadBottomBar import com.huanchengfly.tieba.post.ui.common.theme.compose.threadBottomBar
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
import com.huanchengfly.tieba.post.ui.page.ProvideNavigator import com.huanchengfly.tieba.post.ui.page.ProvideNavigator
import com.huanchengfly.tieba.post.ui.page.destinations.CopyTextDialogPageDestination import com.huanchengfly.tieba.post.ui.page.destinations.CopyTextDialogPageDestination
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
@ -1167,10 +1168,13 @@ fun ThreadPage(
thread?.get { firstPostId }.takeIf { it != 0L } thread?.get { firstPostId }.takeIf { it != 0L }
?: firstPost?.get { id } ?: firstPost?.get { id }
?: 0L ?: 0L
coroutineScope.launch {
TiebaUtil.reportPost( TiebaUtil.reportPost(
context, context,
navigator,
firstPostId.toString() firstPostId.toString()
) )
}
}, },
onDeleteClick = { onDeleteClick = {
deletePost = null deletePost = null
@ -1634,6 +1638,8 @@ fun PostCard(
onMenuDeleteClick: ((Post) -> Unit)? = null, onMenuDeleteClick: ((Post) -> Unit)? = null,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val navigator = LocalNavigator.current
val coroutineScope = rememberCoroutineScope()
val post = remember(postHolder) { postHolder.get() } val post = remember(postHolder) { postHolder.get() }
val hasPadding = remember(key1 = postHolder, key2 = immersiveMode) { val hasPadding = remember(key1 = postHolder, key2 = immersiveMode) {
postHolder.get { floor > 1 } && !immersiveMode postHolder.get { floor > 1 } && !immersiveMode
@ -1693,7 +1699,9 @@ fun PostCard(
} }
DropdownMenuItem( DropdownMenuItem(
onClick = { onClick = {
TiebaUtil.reportPost(context, post.id.toString()) coroutineScope.launch {
TiebaUtil.reportPost(context, navigator, post.id.toString())
}
menuState.expanded = false menuState.expanded = false
} }
) { ) {
@ -1879,6 +1887,8 @@ private fun SubPostItem(
onMenuCopyClick: ((SubPostList) -> Unit)?, onMenuCopyClick: ((SubPostList) -> Unit)?,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val navigator = LocalNavigator.current
val coroutineScope = rememberCoroutineScope()
val menuState = rememberMenuState() val menuState = rememberMenuState()
LongClickMenu( LongClickMenu(
menuState = menuState, menuState = menuState,
@ -1905,7 +1915,9 @@ private fun SubPostItem(
} }
DropdownMenuItem( DropdownMenuItem(
onClick = { onClick = {
TiebaUtil.reportPost(context, subPostList.get { id }.toString()) coroutineScope.launch {
TiebaUtil.reportPost(context, navigator, subPostList.get { id }.toString())
}
menuState.expanded = false menuState.expanded = false
} }
) { ) {

View File

@ -14,11 +14,15 @@ import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.activities.WebViewActivity import com.huanchengfly.tieba.post.activities.WebViewActivity
import com.huanchengfly.tieba.post.api.TiebaApi import com.huanchengfly.tieba.post.api.TiebaApi
import com.huanchengfly.tieba.post.api.models.CheckReportBean import com.huanchengfly.tieba.post.api.models.CheckReportBean
import com.huanchengfly.tieba.post.api.retrofit.doIfFailure
import com.huanchengfly.tieba.post.api.retrofit.doIfSuccess
import com.huanchengfly.tieba.post.components.dialogs.LoadingDialog import com.huanchengfly.tieba.post.components.dialogs.LoadingDialog
import com.huanchengfly.tieba.post.pendingIntentFlagMutable import com.huanchengfly.tieba.post.pendingIntentFlagMutable
import com.huanchengfly.tieba.post.receivers.AutoSignAlarm import com.huanchengfly.tieba.post.receivers.AutoSignAlarm
import com.huanchengfly.tieba.post.services.OKSignService import com.huanchengfly.tieba.post.services.OKSignService
import com.huanchengfly.tieba.post.toastShort import com.huanchengfly.tieba.post.toastShort
import com.huanchengfly.tieba.post.ui.page.destinations.WebViewPageDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
@ -125,7 +129,7 @@ object TiebaUtil {
.enqueue(object : Callback<CheckReportBean> { .enqueue(object : Callback<CheckReportBean> {
override fun onResponse( override fun onResponse(
call: Call<CheckReportBean>, call: Call<CheckReportBean>,
response: Response<CheckReportBean> response: Response<CheckReportBean>,
) { ) {
dialog.dismiss() dialog.dismiss()
WebViewActivity.launch(context, response.body()!!.data.url) WebViewActivity.launch(context, response.body()!!.data.url)
@ -137,4 +141,24 @@ object TiebaUtil {
} }
}) })
} }
suspend fun reportPost(
context: Context,
navigator: DestinationsNavigator,
postId: String,
) {
val dialog = LoadingDialog(context).apply { show() }
TiebaApi.getInstance()
.checkReportPostAsync(postId)
.doIfSuccess {
dialog.dismiss()
navigator.navigate(
WebViewPageDestination(it.data.url)
)
}
.doIfFailure {
dialog.dismiss()
context.toastShort(R.string.toast_load_failed)
}
}
} }