Refactor copy button

This commit is contained in:
Andrew 2024-06-12 11:06:13 +09:30
parent 48febb4f10
commit cf1649a6af
7 changed files with 118 additions and 41 deletions

View File

@ -161,7 +161,7 @@ fun EnterAccountId(
error = state.error?.string(), error = state.error?.string(),
) )
if (state.error == null) { if (state.error == null) {
BorderlessButtonSecondary( BorderlessButtonWithIcon(
text = stringResource(R.string.messageNewDescription), text = stringResource(R.string.messageNewDescription),
modifier = Modifier.contentDescription(R.string.AccessibilityId_help_desk_link) modifier = Modifier.contentDescription(R.string.AccessibilityId_help_desk_link)
) { onHelp() } ) { onHelp() }

View File

@ -39,6 +39,7 @@ import org.thoughtcrime.securesms.ui.classicDarkColors
import org.thoughtcrime.securesms.ui.components.AppBar import org.thoughtcrime.securesms.ui.components.AppBar
import org.thoughtcrime.securesms.ui.components.OnPrimaryButtons import org.thoughtcrime.securesms.ui.components.OnPrimaryButtons
import org.thoughtcrime.securesms.ui.components.OutlineButton import org.thoughtcrime.securesms.ui.components.OutlineButton
import org.thoughtcrime.securesms.ui.components.OutlineCopyButton
import org.thoughtcrime.securesms.ui.components.OutlineTemporaryStateButton import org.thoughtcrime.securesms.ui.components.OutlineTemporaryStateButton
import org.thoughtcrime.securesms.ui.components.SmallButtons import org.thoughtcrime.securesms.ui.components.SmallButtons
import org.thoughtcrime.securesms.ui.contentDescription import org.thoughtcrime.securesms.ui.contentDescription
@ -129,17 +130,10 @@ private fun InviteFriend(
) )
} }
OutlineTemporaryStateButton( OutlineCopyButton(
Modifier modifier = Modifier.weight(1f),
.weight(1f)
.contentDescription(R.string.AccessibilityId_copy_button),
onClick = copyPublicKey onClick = copyPublicKey
) { isTemporary -> )
Text(
stringResource(if (isTemporary) R.string.copied else R.string.copy),
style = MaterialTheme.typography.baseBold
)
}
} }
} }
} }

View File

@ -40,16 +40,15 @@ import org.thoughtcrime.securesms.ui.PreviewTheme
import org.thoughtcrime.securesms.ui.SessionShieldIcon import org.thoughtcrime.securesms.ui.SessionShieldIcon
import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
import org.thoughtcrime.securesms.ui.base import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.baseBold
import org.thoughtcrime.securesms.ui.classicDarkColors import org.thoughtcrime.securesms.ui.classicDarkColors
import org.thoughtcrime.securesms.ui.components.DestructiveButtons import org.thoughtcrime.securesms.ui.components.DestructiveButtons
import org.thoughtcrime.securesms.ui.components.OutlineButton import org.thoughtcrime.securesms.ui.components.OutlineButton
import org.thoughtcrime.securesms.ui.components.OutlineTemporaryStateButton import org.thoughtcrime.securesms.ui.components.OutlineCopyButton
import org.thoughtcrime.securesms.ui.components.QrImage import org.thoughtcrime.securesms.ui.components.QrImage
import org.thoughtcrime.securesms.ui.components.SmallButtons import org.thoughtcrime.securesms.ui.components.SmallButtons
import org.thoughtcrime.securesms.ui.contentDescription import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.extraSmallMonospace
import org.thoughtcrime.securesms.ui.h8 import org.thoughtcrime.securesms.ui.h8
import org.thoughtcrime.securesms.ui.smallMonospace
class RecoveryPasswordActivity : BaseActionBarActivity() { class RecoveryPasswordActivity : BaseActionBarActivity() {
@ -168,18 +167,13 @@ fun RecoveryPasswordCell(seed: String, copySeed:() -> Unit = {}) {
} }
AnimatedVisibility(!showQr) { AnimatedVisibility(!showQr) {
Row(horizontalArrangement = Arrangement.spacedBy(32.dp)) { Row(horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.marginMedium)) {
OutlineTemporaryStateButton( OutlineCopyButton(
Modifier Modifier
.weight(1f) .weight(1f)
.contentDescription(R.string.AccessibilityId_copy_button), .contentDescription(R.string.AccessibilityId_copy_button),
onClick = copySeed onClick = copySeed
) { isTemporary -> )
Text(
stringResource( if (isTemporary) R.string.copied else R.string.copy),
style = MaterialTheme.typography.baseBold
)
}
OutlineButton( OutlineButton(
textId = R.string.qrView, textId = R.string.qrView,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
@ -212,7 +206,7 @@ private fun RecoveryPassword(seed: String) {
) )
.padding(LocalDimensions.current.marginSmall), .padding(LocalDimensions.current.marginSmall),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
style = MaterialTheme.typography.smallMonospace, style = MaterialTheme.typography.extraSmallMonospace,
color = MaterialTheme.colors.run { if (isLight) onSurface else secondary }, color = MaterialTheme.colors.run { if (isLight) onSurface else secondary },
) )
} }

View File

@ -82,6 +82,7 @@ import org.thoughtcrime.securesms.ui.ItemButton
import org.thoughtcrime.securesms.ui.ItemButtonWithDrawable import org.thoughtcrime.securesms.ui.ItemButtonWithDrawable
import org.thoughtcrime.securesms.ui.baseBold import org.thoughtcrime.securesms.ui.baseBold
import org.thoughtcrime.securesms.ui.components.OutlineButton import org.thoughtcrime.securesms.ui.components.OutlineButton
import org.thoughtcrime.securesms.ui.components.OutlineCopyButton
import org.thoughtcrime.securesms.ui.components.OutlineTemporaryStateButton import org.thoughtcrime.securesms.ui.components.OutlineTemporaryStateButton
import org.thoughtcrime.securesms.ui.contentDescription import org.thoughtcrime.securesms.ui.contentDescription
import org.thoughtcrime.securesms.ui.destructiveButtonColors import org.thoughtcrime.securesms.ui.destructiveButtonColors
@ -401,16 +402,10 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
onClick = { sendInvitationToUseSession() } onClick = { sendInvitationToUseSession() }
) )
OutlineTemporaryStateButton( OutlineCopyButton(
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f),
.contentDescription(R.string.AccessibilityId_copy_button), onClick = ::copyPublicKey,
onClick = { copyPublicKey() }, )
) { isTemporary ->
Text(
stringResource(if (isTemporary) R.string.copied else R.string.copy),
style = MaterialTheme.typography.baseBold
)
}
} }
Spacer(modifier = Modifier.height(24.dp)) Spacer(modifier = Modifier.height(24.dp))

View File

@ -145,6 +145,7 @@ val Typography.baseMonospace get() = defaultStyle(14.sp).copy(fontFamily = FontF
val Typography.small get() = defaultStyle(12.sp) val Typography.small get() = defaultStyle(12.sp)
val Typography.smallMonospace get() = defaultStyle(12.sp).copy(fontFamily = FontFamily.Monospace) val Typography.smallMonospace get() = defaultStyle(12.sp).copy(fontFamily = FontFamily.Monospace)
val Typography.extraSmall get() = defaultStyle(11.sp) val Typography.extraSmall get() = defaultStyle(11.sp)
val Typography.extraSmallMonospace get() = defaultStyle(11.sp).copy(fontFamily = FontFamily.Monospace)
val Typography.fine get() = defaultStyle(9.sp) val Typography.fine get() = defaultStyle(9.sp)
val Typography.h7 get() = boldStyle(18.sp) val Typography.h7 get() = boldStyle(18.sp)

View File

@ -49,14 +49,20 @@ val mediumButton = Modifier.height(41.dp)
val smallButton = Modifier.wrapContentHeight() val smallButton = Modifier.wrapContentHeight()
@Composable @Composable
fun OutlineButton(@StringRes textId: Int, modifier: Modifier = Modifier, onClick: () -> Unit) { fun OutlineButton(
OutlineButton(stringResource(textId), modifier, onClick) @StringRes textId: Int,
} modifier: Modifier = Modifier,
onClick: () -> Unit
) { OutlineButton(stringResource(textId), modifier, onClick) }
@Composable @Composable
fun OutlineButton(text: String, modifier: Modifier = Modifier, onClick: () -> Unit) { fun OutlineButton(
text: String,
modifier: Modifier = Modifier,
onClick: () -> Unit
) {
OutlineButton( OutlineButton(
modifier.contentDescription(text), modifier = modifier,
onClick = onClick onClick = onClick
) { Text(text, style = MaterialTheme.typography.baseBold) } ) { Text(text, style = MaterialTheme.typography.baseBold) }
} }
@ -82,6 +88,34 @@ fun OutlineButton(
} }
} }
@Composable
fun OutlineCopyButton(
modifier: Modifier = Modifier,
onClick: () -> Unit = {}
) {
OutlineTemporaryStateButton(
text = stringResource(R.string.copy),
temporaryText = stringResource(R.string.copy),
modifier = modifier.contentDescription(R.string.AccessibilityId_copy_button),
onClick = onClick
)
}
@Composable
fun OutlineTemporaryStateButton(
text: String,
temporaryText: String,
modifier: Modifier = Modifier,
onClick: () -> Unit = {}
) {
OutlineTemporaryStateButton(modifier, onClick) { isTemporary ->
Text(
if (isTemporary) temporaryText else text,
style = MaterialTheme.typography.baseBold
)
}
}
@Composable @Composable
fun OutlineTemporaryStateButton( fun OutlineTemporaryStateButton(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -178,12 +212,12 @@ fun BorderlessButton(
} }
@Composable @Composable
fun BorderlessHtmlButton( fun BorderlessButton(
textId: Int,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
contentColor: Color = MaterialTheme.colors.onBackground, contentColor: Color = MaterialTheme.colors.onBackground,
backgroundColor: Color = Color.Transparent, backgroundColor: Color = Color.Transparent,
onClick: () -> Unit onClick: () -> Unit,
content: @Composable () -> Unit
) { ) {
TextButton( TextButton(
onClick = onClick, onClick = onClick,
@ -192,6 +226,22 @@ fun BorderlessHtmlButton(
contentColor = contentColor, contentColor = contentColor,
backgroundColor = backgroundColor backgroundColor = backgroundColor
) )
) { content() }
}
@Composable
fun BorderlessHtmlButton(
textId: Int,
modifier: Modifier = Modifier,
contentColor: Color = MaterialTheme.colors.onBackground,
backgroundColor: Color = Color.Transparent,
onClick: () -> Unit
) {
BorderlessButton(
modifier,
contentColor = contentColor,
backgroundColor = backgroundColor,
onClick = onClick
) { ) {
Text( Text(
text = annotatedStringResource(textId), text = annotatedStringResource(textId),

View File

@ -3,15 +3,27 @@ package org.thoughtcrime.securesms.ui.components
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.Placeholder
import androidx.compose.ui.text.PlaceholderVerticalAlign
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import org.thoughtcrime.securesms.ui.LocalDimensions import org.thoughtcrime.securesms.ui.LocalDimensions
import org.thoughtcrime.securesms.ui.base import org.thoughtcrime.securesms.ui.base
import org.thoughtcrime.securesms.ui.baseBold import org.thoughtcrime.securesms.ui.baseBold
@ -60,3 +72,34 @@ fun SessionOutlinedTextField(
} }
} }
} }
@Composable
fun AnnotatedTextWithIcon(
text: String,
icon: ImageVector,
modifier: Modifier = Modifier,
iconTint: Color = Color.Unspecified,
iconDescription: String = "",
iconSize: TextUnit = 12.sp,
textWidth: Dp = 100.dp
) {
val myId = "inlineContent"
val annotatedText = buildAnnotatedString {
append(text)
appendInlineContent(myId, "[icon]")
}
val inlineContent = mapOf(
myId to Placeholder(
width = iconSize,
height = iconSize,
placeholderVerticalAlign = PlaceholderVerticalAlign.AboveBaseline
).let { InlineTextContent(it) { Icon(icon, iconDescription, tint = iconTint) } }
)
Text(
text = annotatedText,
modifier = modifier.width(textWidth),
inlineContent = inlineContent
)
}