feat: 自由复制
This commit is contained in:
parent
eecc703c7f
commit
349b397278
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue