Add 'unencrypted room' badges and labels (#4445)
* Add 'unencrypted room' icon and label to composer * Modify colors for room details screen info labels * Add exception to Konsist's preview check * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
committed by
GitHub
parent
56683259d9
commit
bb97015e59
@@ -73,7 +73,7 @@ class AttachmentsPreviewPresenter @AssistedInject constructor(
|
||||
|
||||
val markdownTextEditorState = rememberMarkdownTextEditorState(initialText = null, initialFocus = false)
|
||||
val textEditorState by rememberUpdatedState(
|
||||
TextEditorState.Markdown(markdownTextEditorState)
|
||||
TextEditorState.Markdown(markdownTextEditorState, isRoomEncrypted = null)
|
||||
)
|
||||
|
||||
val ongoingSendAttachmentJob = remember { mutableStateOf<Job?>(null) }
|
||||
|
||||
@@ -141,6 +141,8 @@ class MessageComposerPresenter @AssistedInject constructor(
|
||||
override fun present(): MessageComposerState {
|
||||
val localCoroutineScope = rememberCoroutineScope()
|
||||
|
||||
val roomInfo by room.roomInfoFlow.collectAsState()
|
||||
|
||||
val richTextEditorState = richTextEditorStateFactory.remember()
|
||||
if (isTesting) {
|
||||
richTextEditorState.isReadyToProcessActions = true
|
||||
@@ -242,9 +244,9 @@ class MessageComposerPresenter @AssistedInject constructor(
|
||||
|
||||
val textEditorState by rememberUpdatedState(
|
||||
if (showTextFormatting) {
|
||||
TextEditorState.Rich(richTextEditorState)
|
||||
TextEditorState.Rich(richTextEditorState, roomInfo.isEncrypted == true)
|
||||
} else {
|
||||
TextEditorState.Markdown(markdownTextEditorState)
|
||||
TextEditorState.Markdown(markdownTextEditorState, roomInfo.isEncrypted == true)
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -469,14 +469,14 @@ private fun RoomBadge.toMatrixBadgeData(): MatrixBadgeAtom.MatrixBadgeData {
|
||||
MatrixBadgeAtom.MatrixBadgeData(
|
||||
text = stringResource(R.string.screen_room_details_badge_not_encrypted),
|
||||
icon = CompoundIcons.LockOff(),
|
||||
type = MatrixBadgeAtom.Type.Neutral,
|
||||
type = MatrixBadgeAtom.Type.Info,
|
||||
)
|
||||
}
|
||||
RoomBadge.PUBLIC -> {
|
||||
MatrixBadgeAtom.MatrixBadgeData(
|
||||
text = stringResource(R.string.screen_room_details_badge_public),
|
||||
icon = CompoundIcons.Public(),
|
||||
type = MatrixBadgeAtom.Type.Neutral,
|
||||
type = MatrixBadgeAtom.Type.Info,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.designsystem.components.Badge
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.badgeInfoBackgroundColor
|
||||
import io.element.android.libraries.designsystem.theme.badgeInfoContentColor
|
||||
import io.element.android.libraries.designsystem.theme.badgeNegativeBackgroundColor
|
||||
import io.element.android.libraries.designsystem.theme.badgeNegativeContentColor
|
||||
import io.element.android.libraries.designsystem.theme.badgeNeutralBackgroundColor
|
||||
@@ -31,7 +33,8 @@ object MatrixBadgeAtom {
|
||||
enum class Type {
|
||||
Positive,
|
||||
Neutral,
|
||||
Negative
|
||||
Negative,
|
||||
Info,
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -42,16 +45,19 @@ object MatrixBadgeAtom {
|
||||
Type.Positive -> ElementTheme.colors.badgePositiveBackgroundColor
|
||||
Type.Neutral -> ElementTheme.colors.badgeNeutralBackgroundColor
|
||||
Type.Negative -> ElementTheme.colors.badgeNegativeBackgroundColor
|
||||
Type.Info -> ElementTheme.colors.badgeInfoBackgroundColor
|
||||
}
|
||||
val textColor = when (data.type) {
|
||||
Type.Positive -> ElementTheme.colors.badgePositiveContentColor
|
||||
Type.Neutral -> ElementTheme.colors.badgeNeutralContentColor
|
||||
Type.Negative -> ElementTheme.colors.badgeNegativeContentColor
|
||||
Type.Info -> ElementTheme.colors.badgeInfoContentColor
|
||||
}
|
||||
val iconColor = when (data.type) {
|
||||
Type.Positive -> ElementTheme.colors.iconSuccessPrimary
|
||||
Type.Neutral -> ElementTheme.colors.iconSecondary
|
||||
Type.Negative -> ElementTheme.colors.iconCriticalPrimary
|
||||
Type.Info -> ElementTheme.colors.iconInfoPrimary
|
||||
}
|
||||
Badge(
|
||||
text = data.text,
|
||||
@@ -98,3 +104,15 @@ internal fun MatrixBadgeAtomNegativePreview() = ElementPreview {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun MatrixBadgeAtomInfoPreview() = ElementPreview {
|
||||
MatrixBadgeAtom.View(
|
||||
MatrixBadgeAtom.MatrixBadgeData(
|
||||
text = "Not encrypted",
|
||||
icon = CompoundIcons.LockOff(),
|
||||
type = MatrixBadgeAtom.Type.Info,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -165,6 +165,14 @@ val SemanticColors.badgeNegativeBackgroundColor
|
||||
val SemanticColors.badgeNegativeContentColor
|
||||
get() = if (isLight) LightColorTokens.colorRed1100 else DarkColorTokens.colorRed1100
|
||||
|
||||
@OptIn(CoreColorToken::class)
|
||||
val SemanticColors.badgeInfoBackgroundColor
|
||||
get() = if (isLight) LightColorTokens.colorAlphaBlue300 else DarkColorTokens.colorAlphaBlue300
|
||||
|
||||
@OptIn(CoreColorToken::class)
|
||||
val SemanticColors.badgeInfoContentColor
|
||||
get() = if (isLight) LightColorTokens.colorBlue1100 else DarkColorTokens.colorBlue1100
|
||||
|
||||
@OptIn(CoreColorToken::class)
|
||||
val SemanticColors.pinnedMessageBannerIndicator
|
||||
get() = if (isLight) LightColorTokens.colorAlphaGray600 else DarkColorTokens.colorAlphaGray600
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
|
||||
package io.element.android.libraries.textcomposer
|
||||
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
@@ -37,14 +37,18 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.designsystem.components.media.createFakeWaveform
|
||||
import io.element.android.libraries.designsystem.preview.DAY_MODE_NAME
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.NIGHT_MODE_NAME
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.IconColorButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
@@ -281,6 +285,7 @@ fun TextComposer(
|
||||
if (showTextFormatting && textFormattingOptions != null) {
|
||||
TextFormattingLayout(
|
||||
modifier = layoutModifier,
|
||||
isRoomEncrypted = state.isRoomEncrypted,
|
||||
textInput = textInput,
|
||||
dismissTextFormattingButton = {
|
||||
IconColorButton(
|
||||
@@ -295,6 +300,7 @@ fun TextComposer(
|
||||
StandardLayout(
|
||||
voiceMessageState = voiceMessageState,
|
||||
enableVoiceMessages = enableVoiceMessages,
|
||||
isRoomEncrypted = state.isRoomEncrypted,
|
||||
modifier = layoutModifier,
|
||||
composerOptionsButton = composerOptionsButton,
|
||||
textInput = textInput,
|
||||
@@ -330,6 +336,7 @@ fun TextComposer(
|
||||
private fun StandardLayout(
|
||||
voiceMessageState: VoiceMessageState,
|
||||
enableVoiceMessages: Boolean,
|
||||
isRoomEncrypted: Boolean?,
|
||||
textInput: @Composable () -> Unit,
|
||||
composerOptionsButton: @Composable () -> Unit,
|
||||
voiceRecording: @Composable () -> Unit,
|
||||
@@ -337,58 +344,85 @@ private fun StandardLayout(
|
||||
endButton: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.Bottom,
|
||||
) {
|
||||
if (enableVoiceMessages && voiceMessageState !is VoiceMessageState.Idle) {
|
||||
if (voiceMessageState is VoiceMessageState.Preview || voiceMessageState is VoiceMessageState.Recording) {
|
||||
Column(modifier = modifier) {
|
||||
if (isRoomEncrypted == false) {
|
||||
Spacer(Modifier.height(16.dp))
|
||||
NotEncryptedBadge()
|
||||
Spacer(Modifier.height(4.dp))
|
||||
}
|
||||
Row(verticalAlignment = Alignment.Bottom) {
|
||||
if (enableVoiceMessages && voiceMessageState !is VoiceMessageState.Idle) {
|
||||
if (voiceMessageState is VoiceMessageState.Preview || voiceMessageState is VoiceMessageState.Recording) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 5.dp, top = 5.dp, end = 3.dp, start = 3.dp)
|
||||
.size(48.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
voiceDeleteButton()
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 5.dp, top = 5.dp, end = 3.dp, start = 3.dp)
|
||||
.size(48.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
.padding(bottom = 8.dp, top = 8.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
voiceDeleteButton()
|
||||
voiceRecording()
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Box(
|
||||
Modifier
|
||||
.padding(bottom = 5.dp, top = 5.dp, start = 3.dp)
|
||||
) {
|
||||
composerOptionsButton()
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 8.dp, top = 8.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
textInput()
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 8.dp, top = 8.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
voiceRecording()
|
||||
}
|
||||
} else {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(bottom = 5.dp, top = 5.dp, start = 3.dp)
|
||||
.padding(bottom = 5.dp, top = 5.dp, end = 6.dp, start = 6.dp)
|
||||
.size(48.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
composerOptionsButton()
|
||||
endButton()
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(bottom = 8.dp, top = 8.dp)
|
||||
.weight(1f)
|
||||
) {
|
||||
textInput()
|
||||
}
|
||||
}
|
||||
Box(
|
||||
Modifier
|
||||
.padding(bottom = 5.dp, top = 5.dp, end = 6.dp, start = 6.dp)
|
||||
.size(48.dp),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
endButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NotEncryptedBadge() {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(16.dp),
|
||||
imageVector = CompoundIcons.LockOff(),
|
||||
contentDescription = null,
|
||||
tint = ElementTheme.colors.iconInfoPrimary,
|
||||
)
|
||||
Spacer(Modifier.width(4.dp))
|
||||
Text(
|
||||
text = stringResource(CommonStrings.common_not_encrypted),
|
||||
style = ElementTheme.typography.fontBodySmRegular,
|
||||
color = ElementTheme.colors.textSecondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TextFormattingLayout(
|
||||
isRoomEncrypted: Boolean?,
|
||||
textInput: @Composable () -> Unit,
|
||||
dismissTextFormattingButton: @Composable () -> Unit,
|
||||
textFormatting: @Composable () -> Unit,
|
||||
@@ -399,6 +433,10 @@ private fun TextFormattingLayout(
|
||||
modifier = modifier.padding(vertical = 4.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
if (isRoomEncrypted == false) {
|
||||
NotEncryptedBadge()
|
||||
Spacer(Modifier.height(8.dp))
|
||||
}
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
@@ -438,7 +476,7 @@ private fun TextInputBox(
|
||||
placeholder: String,
|
||||
showPlaceholder: Boolean,
|
||||
subcomposing: Boolean,
|
||||
textInput: @Composable BoxScope.() -> Unit,
|
||||
textInput: @Composable () -> Unit,
|
||||
) {
|
||||
val bgColor = ElementTheme.colors.bgSubtleSecondary
|
||||
val borderColor = ElementTheme.colors.borderDisabled
|
||||
@@ -539,24 +577,26 @@ private fun TextInput(
|
||||
}
|
||||
}
|
||||
|
||||
private fun aTextEditorStateMarkdownList() = persistentListOf(
|
||||
aTextEditorStateMarkdown(initialText = "", initialFocus = true),
|
||||
aTextEditorStateMarkdown(initialText = "A message", initialFocus = true),
|
||||
private fun aTextEditorStateMarkdownList(isRoomEncrypted: Boolean? = null) = persistentListOf(
|
||||
aTextEditorStateMarkdown(initialText = "", initialFocus = true, isRoomEncrypted = isRoomEncrypted),
|
||||
aTextEditorStateMarkdown(initialText = "A message", initialFocus = true, isRoomEncrypted = isRoomEncrypted),
|
||||
aTextEditorStateMarkdown(
|
||||
initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow",
|
||||
initialFocus = true,
|
||||
isRoomEncrypted = isRoomEncrypted,
|
||||
),
|
||||
aTextEditorStateMarkdown(initialText = "A message without focus", initialFocus = false),
|
||||
aTextEditorStateMarkdown(initialText = "A message without focus", initialFocus = false, isRoomEncrypted = isRoomEncrypted),
|
||||
)
|
||||
|
||||
private fun aTextEditorStateRichList() = persistentListOf(
|
||||
aTextEditorStateRich(initialFocus = true),
|
||||
aTextEditorStateRich(initialText = "A message", initialFocus = true),
|
||||
private fun aTextEditorStateRichList(isRoomEncrypted: Boolean? = null) = persistentListOf(
|
||||
aTextEditorStateRich(initialFocus = true, isRoomEncrypted = isRoomEncrypted),
|
||||
aTextEditorStateRich(initialText = "A message", initialFocus = true, isRoomEncrypted = isRoomEncrypted),
|
||||
aTextEditorStateRich(
|
||||
initialText = "A message\nWith several lines\nTo preview larger textfields and long lines with overflow",
|
||||
initialFocus = true
|
||||
initialFocus = true,
|
||||
isRoomEncrypted = isRoomEncrypted,
|
||||
),
|
||||
aTextEditorStateRich(initialText = "A message without focus", initialFocus = false),
|
||||
aTextEditorStateRich(initialText = "A message without focus", initialFocus = false, isRoomEncrypted = isRoomEncrypted),
|
||||
)
|
||||
|
||||
@PreviewsDayNight
|
||||
@@ -574,6 +614,21 @@ internal fun TextComposerSimplePreview() = ElementPreview {
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerSimpleNotEncryptedPreview() = ElementPreview {
|
||||
PreviewColumn(
|
||||
items = aTextEditorStateMarkdownList(isRoomEncrypted = false),
|
||||
) { _, textEditorState ->
|
||||
ATextComposer(
|
||||
state = textEditorState,
|
||||
voiceMessageState = VoiceMessageState.Idle,
|
||||
composerMode = MessageComposerMode.Normal,
|
||||
enableVoiceMessages = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerFormattingPreview() = ElementPreview {
|
||||
@@ -590,6 +645,22 @@ internal fun TextComposerFormattingPreview() = ElementPreview {
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerFormattingNotEncryptedPreview() = ElementPreview {
|
||||
PreviewColumn(
|
||||
items = aTextEditorStateRichList(isRoomEncrypted = false)
|
||||
) { _, textEditorState ->
|
||||
ATextComposer(
|
||||
state = textEditorState,
|
||||
voiceMessageState = VoiceMessageState.Idle,
|
||||
showTextFormatting = true,
|
||||
composerMode = MessageComposerMode.Normal,
|
||||
enableVoiceMessages = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerEditPreview() = ElementPreview {
|
||||
@@ -605,6 +676,21 @@ internal fun TextComposerEditPreview() = ElementPreview {
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerEditNotEncryptedPreview() = ElementPreview {
|
||||
PreviewColumn(
|
||||
items = aTextEditorStateRichList(isRoomEncrypted = false)
|
||||
) { _, textEditorState ->
|
||||
ATextComposer(
|
||||
state = textEditorState,
|
||||
voiceMessageState = VoiceMessageState.Idle,
|
||||
composerMode = aMessageComposerModeEdit(),
|
||||
enableVoiceMessages = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerEditCaptionPreview() = ElementPreview {
|
||||
@@ -674,6 +760,31 @@ internal fun TextComposerReplyPreview(@PreviewParameter(InReplyToDetailsProvider
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(
|
||||
name = DAY_MODE_NAME,
|
||||
heightDp = 800,
|
||||
)
|
||||
@Preview(
|
||||
name = NIGHT_MODE_NAME,
|
||||
uiMode = Configuration.UI_MODE_NIGHT_YES,
|
||||
heightDp = 800,
|
||||
)
|
||||
@Composable
|
||||
internal fun TextComposerReplyNotEncryptedPreview(@PreviewParameter(InReplyToDetailsProvider::class) inReplyToDetails: InReplyToDetails) = ElementPreview {
|
||||
PreviewColumn(
|
||||
items = aTextEditorStateRichList(isRoomEncrypted = false)
|
||||
) { _, textEditorState ->
|
||||
ATextComposer(
|
||||
state = textEditorState,
|
||||
voiceMessageState = VoiceMessageState.Idle,
|
||||
composerMode = aMessageComposerModeReply(
|
||||
replyToDetails = inReplyToDetails,
|
||||
),
|
||||
enableVoiceMessages = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerCaptionPreview() = ElementPreview {
|
||||
@@ -734,6 +845,47 @@ internal fun TextComposerVoicePreview() = ElementPreview {
|
||||
}
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextComposerVoiceNotEncryptedPreview() = ElementPreview {
|
||||
PreviewColumn(
|
||||
items = persistentListOf(
|
||||
VoiceMessageState.Recording(61.seconds, createFakeWaveform()),
|
||||
VoiceMessageState.Preview(
|
||||
isSending = false,
|
||||
isPlaying = false,
|
||||
showCursor = false,
|
||||
waveform = createFakeWaveform(),
|
||||
time = 0.seconds,
|
||||
playbackProgress = 0.0f
|
||||
),
|
||||
VoiceMessageState.Preview(
|
||||
isSending = false,
|
||||
isPlaying = true,
|
||||
showCursor = true,
|
||||
waveform = createFakeWaveform(),
|
||||
time = 3.seconds,
|
||||
playbackProgress = 0.2f
|
||||
),
|
||||
VoiceMessageState.Preview(
|
||||
isSending = true,
|
||||
isPlaying = false,
|
||||
showCursor = false,
|
||||
waveform = createFakeWaveform(),
|
||||
time = 61.seconds,
|
||||
playbackProgress = 0.0f
|
||||
),
|
||||
)
|
||||
) { _, voiceMessageState ->
|
||||
ATextComposer(
|
||||
state = aTextEditorStateRich(initialFocus = true, isRoomEncrypted = false),
|
||||
voiceMessageState = voiceMessageState,
|
||||
composerMode = MessageComposerMode.Normal,
|
||||
enableVoiceMessages = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun <T> PreviewColumn(
|
||||
items: ImmutableList<T>,
|
||||
@@ -741,6 +893,7 @@ private fun <T> PreviewColumn(
|
||||
) {
|
||||
Column {
|
||||
items.forEachIndexed { index, item ->
|
||||
HorizontalDivider()
|
||||
Box(
|
||||
modifier = Modifier.height(IntrinsicSize.Min)
|
||||
) {
|
||||
|
||||
@@ -12,12 +12,14 @@ import io.element.android.wysiwyg.compose.RichTextEditorState
|
||||
fun aTextEditorStateMarkdown(
|
||||
initialText: String? = "",
|
||||
initialFocus: Boolean = false,
|
||||
isRoomEncrypted: Boolean? = null,
|
||||
): TextEditorState {
|
||||
return TextEditorState.Markdown(
|
||||
aMarkdownTextEditorState(
|
||||
initialText = initialText,
|
||||
initialFocus = initialFocus,
|
||||
)
|
||||
),
|
||||
isRoomEncrypted = isRoomEncrypted,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -36,6 +38,7 @@ fun aTextEditorStateRich(
|
||||
initialHtml: String = initialText,
|
||||
initialMarkdown: String = initialText,
|
||||
initialFocus: Boolean = false,
|
||||
isRoomEncrypted: Boolean? = null,
|
||||
): TextEditorState {
|
||||
return TextEditorState.Rich(
|
||||
aRichTextEditorState(
|
||||
@@ -43,7 +46,8 @@ fun aTextEditorStateRich(
|
||||
initialHtml = initialHtml,
|
||||
initialMarkdown = initialMarkdown,
|
||||
initialFocus = initialFocus,
|
||||
)
|
||||
),
|
||||
isRoomEncrypted = isRoomEncrypted,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,12 +13,16 @@ import io.element.android.wysiwyg.compose.RichTextEditorState
|
||||
|
||||
@Immutable
|
||||
sealed interface TextEditorState {
|
||||
val isRoomEncrypted: Boolean?
|
||||
|
||||
data class Markdown(
|
||||
val state: MarkdownTextEditorState,
|
||||
override val isRoomEncrypted: Boolean?,
|
||||
) : TextEditorState
|
||||
|
||||
data class Rich(
|
||||
val richTextEditorState: RichTextEditorState
|
||||
val richTextEditorState: RichTextEditorState,
|
||||
override val isRoomEncrypted: Boolean?,
|
||||
) : TextEditorState
|
||||
|
||||
fun messageHtml(): String? = when (this) {
|
||||
|
||||
@@ -75,6 +75,7 @@ class KonsistPreviewTest {
|
||||
"MatrixBadgeAtomPositivePreview",
|
||||
"MatrixBadgeAtomNeutralPreview",
|
||||
"MatrixBadgeAtomNegativePreview",
|
||||
"MatrixBadgeAtomInfoPreview",
|
||||
"MentionSpanPreview",
|
||||
"MessageComposerViewVoicePreview",
|
||||
"MessagesReactionButtonAddPreview",
|
||||
@@ -106,14 +107,19 @@ class KonsistPreviewTest {
|
||||
"TextComposerAddCaptionPreview",
|
||||
"TextComposerCaptionPreview",
|
||||
"TextComposerEditPreview",
|
||||
"TextComposerEditNotEncryptedPreview",
|
||||
"TextComposerEditCaptionPreview",
|
||||
"TextComposerFormattingPreview",
|
||||
"TextComposerFormattingNotEncryptedPreview",
|
||||
"TextComposerLinkDialogCreateLinkPreview",
|
||||
"TextComposerLinkDialogCreateLinkWithoutTextPreview",
|
||||
"TextComposerLinkDialogEditLinkPreview",
|
||||
"TextComposerReplyPreview",
|
||||
"TextComposerReplyNotEncryptedPreview",
|
||||
"TextComposerSimplePreview",
|
||||
"TextComposerSimpleNotEncryptedPreview",
|
||||
"TextComposerVoicePreview",
|
||||
"TextComposerVoiceNotEncryptedPreview",
|
||||
"TimelineImageWithCaptionRowPreview",
|
||||
"TimelineItemEventRowForDirectRoomPreview",
|
||||
"TimelineItemEventRowShieldPreview",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user