feat: 自由复制

This commit is contained in:
HuanCheng65 2023-09-30 01:26:43 +08:00
parent eecc703c7f
commit 349b397278
No known key found for this signature in database
GPG Key ID: 5EC9DD60A32C7360
6 changed files with 273 additions and 52 deletions

View File

@ -0,0 +1,177 @@
package com.huanchengfly.tieba.post.ui.page.dialogs
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Close
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
import com.huanchengfly.tieba.post.ui.widgets.compose.Button
import com.huanchengfly.tieba.post.ui.widgets.compose.TitleCentredToolbar
import com.huanchengfly.tieba.post.utils.TiebaUtil
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.spec.DestinationStyle
@Destination
@Composable
fun CopyTextPage(
text: String,
navigator: DestinationsNavigator,
) {
val context = LocalContext.current
CopyTextPageContent(
text = text,
onCopy = {
TiebaUtil.copyText(context, it)
},
onCancel = {
navigator.navigateUp()
}
)
}
object CopyTextDialogStyle : DestinationStyle.Dialog {
override val properties: DialogProperties
get() = DialogProperties(
usePlatformDefaultWidth = false,
)
}
@Destination(
style = CopyTextDialogStyle::class
)
@Composable
fun CopyTextDialogPage(
text: String,
navigator: DestinationsNavigator,
) {
val context = LocalContext.current
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.fillMaxSize()
.background(color = ExtendedTheme.colors.windowBackground)
) {
CopyTextPageContent(
text = text,
onCopy = {
TiebaUtil.copyText(context, it)
},
onCancel = {
navigator.navigateUp()
}
)
}
}
@Composable
private fun CopyTextPageContent(
text: String,
onCopy: (String) -> Unit,
onCancel: () -> Unit,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.background(color = ExtendedTheme.colors.windowBackground)
.systemBarsPadding()
.padding(bottom = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
TitleCentredToolbar(
title = {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = stringResource(id = R.string.title_copy),
style = MaterialTheme.typography.h6,
fontWeight = FontWeight.Bold
)
Text(
text = stringResource(id = R.string.tip_copy_text),
style = MaterialTheme.typography.caption
)
}
},
navigationIcon = {
IconButton(onClick = onCancel) {
Icon(
imageVector = Icons.Rounded.Close,
contentDescription = stringResource(id = R.string.btn_close)
)
}
}
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState())
.weight(1f),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
SelectionContainer {
Text(
text = text,
modifier = Modifier.fillMaxWidth(),
style = MaterialTheme.typography.body1
)
}
}
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
onCopy(text)
onCancel()
}
) {
Text(text = stringResource(id = R.string.btn_copy_all))
}
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
onCancel()
},
colors = ButtonDefaults.buttonColors(
backgroundColor = ExtendedTheme.colors.text.copy(alpha = 0.1f),
contentColor = ExtendedTheme.colors.text
)
) {
Text(text = stringResource(id = R.string.btn_close))
}
}
}
}

View File

@ -49,6 +49,7 @@ import com.huanchengfly.tieba.post.arch.wrapImmutable
import com.huanchengfly.tieba.post.ui.common.theme.compose.ExtendedTheme
import com.huanchengfly.tieba.post.ui.page.LocalNavigator
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.ReplyPageDestination
import com.huanchengfly.tieba.post.ui.page.destinations.ThreadPageDestination
import com.huanchengfly.tieba.post.ui.page.thread.PostAgreeBtn
@ -142,6 +143,7 @@ internal fun SubPostsContent(
loadFromSubPost: Boolean = false,
isSheet: Boolean = false
) {
val context = LocalContext.current
val navigator = LocalNavigator.current
val account = LocalAccount.current
@ -406,6 +408,11 @@ internal fun SubPostsContent(
)
)
},
onMenuCopyClick = {
navigator.navigate(
CopyTextDialogPageDestination(it)
)
},
) {
deleteSubPost = null
confirmDeleteDialogState.show()
@ -465,6 +472,12 @@ internal fun SubPostsContent(
)
)
},
onMenuCopyClick = {
navigator.navigate(
CopyTextDialogPageDestination(it)
)
// TiebaUtil.copyText(context, it)
},
onMenuDeleteClick = {
deleteSubPost = it.wrapImmutable()
confirmDeleteDialogState.show()
@ -499,6 +512,7 @@ private fun SubPostItem(
canDelete: (SubPostList) -> Boolean = { false },
onAgree: (SubPostList) -> Unit = {},
onReplyClick: (SubPostList) -> Unit = {},
onMenuCopyClick: ((String) -> Unit)? = null,
onMenuDeleteClick: ((SubPostList) -> Unit)? = null,
) {
val (subPost, contentRenders, blocked) = item
@ -532,16 +546,16 @@ private fun SubPostItem(
Text(text = stringResource(id = R.string.btn_reply))
}
}
if (onMenuCopyClick != null) {
DropdownMenuItem(
onClick = {
TiebaUtil.copyText(
context,
contentRenders.joinToString("\n") { it.toString() })
onMenuCopyClick(contentRenders.joinToString("\n") { it.toString() })
menuState.expanded = false
}
) {
Text(text = stringResource(id = R.string.menu_copy))
}
}
DropdownMenuItem(
onClick = {
TiebaUtil.reportPost(context, subPost.get { id }.toString())

View File

@ -102,7 +102,6 @@ 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.bawuType
import com.huanchengfly.tieba.post.api.models.protos.plainText
import com.huanchengfly.tieba.post.api.models.protos.renders
import com.huanchengfly.tieba.post.api.retrofit.exception.getErrorMessage
import com.huanchengfly.tieba.post.arch.GlobalEvent
import com.huanchengfly.tieba.post.arch.ImmutableHolder
@ -123,6 +122,7 @@ 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.threadBottomBar
import com.huanchengfly.tieba.post.ui.page.ProvideNavigator
import com.huanchengfly.tieba.post.ui.page.destinations.CopyTextPageDestination
import com.huanchengfly.tieba.post.ui.page.destinations.ForumPageDestination
import com.huanchengfly.tieba.post.ui.page.destinations.ReplyPageDestination
import com.huanchengfly.tieba.post.ui.page.destinations.SubPostsSheetPageDestination
@ -873,6 +873,11 @@ fun ThreadPage(
)
}
},
onMenuCopyClick = {
navigator.navigate(
CopyTextPageDestination(it)
)
},
onMenuFavoriteClick = {
val isPostCollected =
it.id == thread?.get { collectMarkPid.toLongOrNull() }
@ -1209,6 +1214,11 @@ fun ThreadPage(
)
)
},
onMenuCopyClick = {
navigator.navigate(
CopyTextPageDestination(it)
)
},
onMenuFavoriteClick = {
viewModel.send(
ThreadUiIntent.AddFavorite(
@ -1540,6 +1550,7 @@ fun PostCard(
onReplyClick: (Post) -> Unit = {},
onSubPostReplyClick: ((Post, SubPostList) -> Unit)? = null,
onOpenSubPosts: (subPostId: Long) -> Unit = {},
onMenuCopyClick: ((String) -> Unit)? = null,
onMenuFavoriteClick: ((Post) -> Unit)? = null,
onMenuDeleteClick: ((Post) -> Unit)? = null,
) {
@ -1591,14 +1602,16 @@ fun PostCard(
Text(text = stringResource(id = R.string.btn_reply))
}
}
if (onMenuCopyClick != null) {
DropdownMenuItem(
onClick = {
TiebaUtil.copyText(context, post.content.plainText)
onMenuCopyClick(post.content.plainText)
menuState.expanded = false
}
) {
Text(text = stringResource(id = R.string.menu_copy))
}
}
DropdownMenuItem(
onClick = {
TiebaUtil.reportPost(context, post.id.toString())
@ -1744,6 +1757,9 @@ fun PostCard(
onSubPostReplyClick?.invoke(post, it)
},
onOpenSubPosts = onOpenSubPosts,
onMenuCopyClick = {
onMenuCopyClick?.invoke(it.content.plainText)
}
)
}
}
@ -1781,6 +1797,7 @@ private fun SubPostItem(
modifier: Modifier = Modifier,
onReplyClick: ((SubPostList) -> Unit)?,
onOpenSubPosts: (Long) -> Unit,
onMenuCopyClick: ((SubPostList) -> Unit)?,
) {
val context = LocalContext.current
val menuState = rememberMenuState()
@ -1797,16 +1814,16 @@ private fun SubPostItem(
Text(text = stringResource(id = R.string.title_reply))
}
}
if (onMenuCopyClick != null) {
DropdownMenuItem(
onClick = {
TiebaUtil.copyText(
context,
subPostList.get { content.renders.joinToString(" ") { it.toString() } })
onMenuCopyClick(subPostList.get())
menuState.expanded = false
}
) {
Text(text = stringResource(id = R.string.menu_copy))
}
}
DropdownMenuItem(
onClick = {
TiebaUtil.reportPost(context, subPostList.get { id }.toString())

View File

@ -1,6 +1,8 @@
package com.huanchengfly.tieba.post.ui.widgets.compose
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
@ -47,23 +49,26 @@ fun Button(
) {
val contentColor by colors.contentColor(enabled)
Surface(
modifier = Modifier
.clickable(
onClick = onClick,
modifier = modifier,
enabled = enabled,
interactionSource = interactionSource,
indication = LocalIndication.current
)
.then(modifier),
shape = shape,
color = colors.backgroundColor(enabled).value,
contentColor = contentColor.copy(alpha = 1f),
border = border,
elevation = elevation?.elevation(enabled, interactionSource)?.value ?: 0.dp,
interactionSource = interactionSource,
) {
CompositionLocalProvider(LocalContentAlpha provides contentColor.alpha) {
ProvideTextStyle(
value = MaterialTheme.typography.button
) {
Row(
Modifier
.padding(contentPadding),
Modifier.padding(contentPadding),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
content = content

View File

@ -27,6 +27,7 @@ import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ProvideTextStyle
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
@ -209,7 +210,7 @@ fun TitleCentredToolbar(
) {
TitleCentredToolbar(
title = {
Text(text = title, fontWeight = FontWeight.Bold, style = MaterialTheme.typography.h6)
Text(text = title)
},
modifier = modifier,
insets = insets,
@ -241,12 +242,14 @@ fun TitleCentredToolbar(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxHeight()
) {
ProvideContentColor(color = ExtendedTheme.colors.onTopBar) {
navigationIcon?.invoke()
Spacer(modifier = Modifier.weight(1f))
actions()
}
}
Row(
Modifier
@ -255,12 +258,14 @@ fun TitleCentredToolbar(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
ProvideTextStyle(value = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold)) {
ProvideContentColor(color = ExtendedTheme.colors.onTopBar) {
title()
}
}
}
}
}
},
modifier = modifier,
insets = insets,
@ -275,21 +280,12 @@ fun Toolbar(
actions: @Composable RowScope.() -> Unit = {},
content: (@Composable ColumnScope.() -> Unit)? = null,
) {
TopAppBarContainer(
topBar = {
TopAppBar(
Toolbar(
title = {
ProvideContentColor(color = ExtendedTheme.colors.onTopBar) {
Text(text = title, fontWeight = FontWeight.Bold)
}
Text(text = title)
},
actions = actions,
navigationIcon = navigationIcon,
backgroundColor = ExtendedTheme.colors.topBar,
contentColor = ExtendedTheme.colors.onTopBar,
elevation = 0.dp
)
},
actions = actions,
content = content
)
}
@ -305,10 +301,20 @@ fun Toolbar(
topBar = {
TopAppBar(
title = {
ProvideTextStyle(value = MaterialTheme.typography.h6.copy(fontWeight = FontWeight.Bold)) {
ProvideContentColor(color = ExtendedTheme.colors.onTopBar, content = title)
}
},
actions = {
ProvideContentColor(color = ExtendedTheme.colors.onTopBar) {
actions()
}
},
navigationIcon = {
ProvideContentColor(color = ExtendedTheme.colors.onTopBar) {
navigationIcon?.invoke()
}
},
actions = actions,
navigationIcon = navigationIcon,
backgroundColor = ExtendedTheme.colors.topBar,
contentColor = ExtendedTheme.colors.onTopBar,
elevation = 0.dp

View File

@ -729,4 +729,6 @@
<string name="title_hide_reply">隐藏回贴入口</string>
<string name="title_settings_use_themed_icon">应用图标使用动态取色</string>
<string name="tip_settings_use_themed_icon_summary_not_supported">当前正在使用的应用图标暂不支持动态取色</string>
<string name="btn_copy_all">复制全部</string>
<string name="title_copy">复制</string>
</resources>