Skip to content

Commit cfc436a

Browse files
authored
fix: bubble colors for multipart assets [WPB-22232] (#4466)
1 parent fd14b15 commit cfc436a

File tree

17 files changed

+244
-140
lines changed

17 files changed

+244
-140
lines changed

app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/item/MessageContentAndStatus.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,6 @@ private fun MessageContent(
369369
conversationId = message.conversationId,
370370
attachments = messageContent.attachments,
371371
messageStyle = messageStyle,
372-
accent = accent,
373372
onImageAttachmentClick = onMultipartImageClick
374373
)
375374
}

app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/preview/PreviewMesssageBubbleTypes.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
* You should have received a copy of the GNU General Public License
1616
* along with this program. If not, see http://www.gnu.org/licenses/.
1717
*/
18+
19+
@file:Suppress("TooManyFunctions")
20+
1821
package com.wire.android.ui.home.conversations.messages.preview
1922

2023
import androidx.compose.foundation.background
@@ -35,6 +38,7 @@ import com.wire.android.ui.home.conversations.mock.mockMessageWithMarkdownTables
3538
import com.wire.android.ui.home.conversations.mock.mockMessageWithMarkdownTextAndLinks
3639
import com.wire.android.ui.home.conversations.mock.mockMessageWithText
3740
import com.wire.android.ui.home.conversations.mock.mockMessageWithTextContent
41+
import com.wire.android.ui.home.conversations.mock.mockedMultipartMessage
3842
import com.wire.android.ui.home.conversations.model.ExpirationStatus
3943
import com.wire.android.ui.home.conversations.model.MessageEditStatus
4044
import com.wire.android.ui.home.conversations.model.MessageSource
@@ -407,3 +411,33 @@ fun PreviewMessageBubbleOtherWithMarkdownTablesAndBlocks() {
407411
}
408412
}
409413
}
414+
415+
@PreviewMultipleThemes
416+
@Composable
417+
fun PreviewMessageBubbleSelfWithMultipartAsset() {
418+
WireTheme {
419+
Box(modifier = Modifier.background(color = colorsScheme().surface)) {
420+
RegularMessageItem(
421+
message = mockedMultipartMessage(source = MessageSource.Self),
422+
conversationDetailsData = ConversationDetailsData.None(null),
423+
clickActions = MessageClickActions.Content(),
424+
isBubbleUiEnabled = true
425+
)
426+
}
427+
}
428+
}
429+
430+
@PreviewMultipleThemes
431+
@Composable
432+
fun PreviewMessageBubbleOtherWithMultipartAsset() {
433+
WireTheme {
434+
Box(modifier = Modifier.background(color = colorsScheme().surface)) {
435+
RegularMessageItem(
436+
message = mockedMultipartMessage(source = MessageSource.OtherUser),
437+
conversationDetailsData = ConversationDetailsData.None(null),
438+
clickActions = MessageClickActions.Content(),
439+
isBubbleUiEnabled = true
440+
)
441+
}
442+
}
443+
}

app/src/main/kotlin/com/wire/android/ui/home/conversations/mock/Mock.kt

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,15 @@ import com.wire.android.ui.home.conversations.model.messagetypes.image.VisualMed
3939
import com.wire.android.ui.home.conversationslist.model.Membership
4040
import com.wire.android.util.ui.UIText
4141
import com.wire.android.util.ui.toUIText
42+
import com.wire.kalium.logic.data.asset.AssetTransferStatus
4243
import com.wire.kalium.logic.data.id.ConversationId
4344
import com.wire.kalium.logic.data.id.QualifiedID
45+
import com.wire.kalium.logic.data.message.AssetContent.AssetMetadata
46+
import com.wire.kalium.logic.data.message.CellAssetContent
4447
import com.wire.kalium.logic.data.user.ConnectionState
4548
import com.wire.kalium.logic.data.user.UserAssetId
4649
import com.wire.kalium.logic.data.user.UserAvailabilityStatus
50+
import kotlinx.collections.immutable.persistentListOf
4751
import kotlinx.datetime.Instant
4852
import okio.Path.Companion.toPath
4953

@@ -440,6 +444,64 @@ fun mockedImageUIMessage(
440444
source = source
441445
)
442446

447+
private fun mockedCellAssetContent(
448+
name: String,
449+
id: String,
450+
mimeType: String,
451+
transferStatus: AssetTransferStatus = AssetTransferStatus.NOT_DOWNLOADED,
452+
metadata: AssetMetadata? = null
453+
) =
454+
CellAssetContent(
455+
id = id,
456+
versionId = "v1",
457+
mimeType = mimeType,
458+
assetPath = null,
459+
assetSize = 21957335,
460+
localPath = name,
461+
contentUrl = name,
462+
contentUrlExpiresAt = null,
463+
previewUrl = name,
464+
metadata = metadata,
465+
transferStatus = transferStatus
466+
)
467+
468+
fun mockedMultipartMessage(
469+
messageId: String = "messageId",
470+
messageStatus: MessageStatus = MessageStatus(
471+
flowStatus = MessageFlowStatus.Sent,
472+
expirationStatus = ExpirationStatus.NotExpirable
473+
),
474+
header: MessageHeader = MessageHeader(
475+
username = UIText.DynamicString("John Doe"),
476+
membership = Membership.External,
477+
showLegalHoldIndicator = false,
478+
messageTime = mockMessageTime,
479+
messageStatus = messageStatus,
480+
messageId = messageId,
481+
connectionState = ConnectionState.ACCEPTED,
482+
isSenderDeleted = false,
483+
isSenderUnavailable = false
484+
),
485+
source: MessageSource = MessageSource.Self,
486+
content: UIMessageContent.Regular = UIMessageContent.Multipart(
487+
messageBody = MessageBody(UIText.DynamicString("Text")),
488+
attachments = persistentListOf(
489+
mockedCellAssetContent(name = "1.zip", mimeType = "application/zip", id = "1"),
490+
mockedCellAssetContent(name = "2.pdf", mimeType = "application/pdf", id = "2"),
491+
mockedCellAssetContent(name = "3.txt", mimeType = "text/plain", id = "3", transferStatus = AssetTransferStatus.NOT_FOUND),
492+
mockedCellAssetContent(name = "4.png", mimeType = "image/png", id = "4", metadata = AssetMetadata.Image(1920, 1080)),
493+
mockedCellAssetContent(name = "5.mp4", mimeType = "video/mp4", id = "5", metadata = AssetMetadata.Video(1920, 1080, 60000L)),
494+
),
495+
)
496+
) = UIMessage.Regular(
497+
conversationId = ConversationId("value", "domain"),
498+
userAvatarData = UserAvatarData(null, UserAvailabilityStatus.AVAILABLE),
499+
header = header,
500+
messageContent = content,
501+
messageFooter = mockEmptyFooter,
502+
source = source
503+
)
504+
443505
@Suppress("LongMethod", "MagicNumber")
444506
fun getMockedMessages(): List<UIMessage> = listOf(
445507
UIMessage.Regular(

app/src/main/kotlin/com/wire/android/ui/home/conversations/model/messagetypes/multipart/MultipartAttachmentsView.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import androidx.compose.runtime.LaunchedEffect
2929
import androidx.compose.ui.Modifier
3030
import androidx.compose.ui.platform.LocalConfiguration
3131
import androidx.compose.ui.platform.LocalContext
32+
import androidx.compose.ui.platform.LocalInspectionMode
3233
import androidx.hilt.navigation.compose.hiltViewModel
3334
import coil.decode.Decoder
3435
import coil.request.ImageRequest
@@ -39,7 +40,6 @@ import com.wire.android.ui.common.multipart.toUiModel
3940
import com.wire.android.ui.home.conversations.messages.item.MessageStyle
4041
import com.wire.android.ui.home.conversations.model.messagetypes.multipart.grid.AssetGridPreview
4142
import com.wire.android.ui.home.conversations.model.messagetypes.multipart.standalone.AssetPreview
42-
import com.wire.android.ui.theme.Accent
4343
import com.wire.kalium.logic.data.asset.AssetTransferStatus
4444
import com.wire.kalium.logic.data.asset.isFailed
4545
import com.wire.kalium.logic.data.id.ConversationId
@@ -56,8 +56,10 @@ fun MultipartAttachmentsView(
5656
messageStyle: MessageStyle,
5757
onImageAttachmentClick: (String) -> Unit,
5858
modifier: Modifier = Modifier,
59-
accent: Accent = Accent.Unknown,
60-
viewModel: MultipartAttachmentsViewModel = hiltViewModel<MultipartAttachmentsViewModel>(key = conversationId.value),
59+
viewModel: MultipartAttachmentsViewModel = when {
60+
LocalInspectionMode.current -> MultipartAttachmentsViewModelPreview
61+
else -> hiltViewModel<MultipartAttachmentsViewModelImpl>(key = conversationId.value)
62+
}
6163
) {
6264

6365
// TODO I found out that empty attachments list is not handled here and it shows empty message with no information
@@ -66,7 +68,6 @@ fun MultipartAttachmentsView(
6668
AssetPreview(
6769
item = it,
6870
messageStyle = messageStyle,
69-
accent = accent,
7071
onClick = {
7172
viewModel.onClick(
7273
attachment = it,
@@ -106,7 +107,6 @@ fun MultipartAttachmentsView(
106107
openInImageViewer = onImageAttachmentClick,
107108
)
108109
},
109-
accent = accent
110110
)
111111
}
112112
}
@@ -121,7 +121,6 @@ fun MultipartAttachmentsView(
121121
private fun AttachmentsList(
122122
attachments: List<MultipartAttachmentUi>,
123123
messageStyle: MessageStyle,
124-
accent: Accent,
125124
onClick: (MultipartAttachmentUi) -> Unit,
126125
modifier: Modifier = Modifier,
127126
) {
@@ -135,7 +134,6 @@ private fun AttachmentsList(
135134
showWithPreview = true,
136135
onClick = { onClick(it) },
137136
modifier = modifier,
138-
accent = accent
139137
)
140138
}
141139
}

app/src/main/kotlin/com/wire/android/ui/home/conversations/model/messagetypes/multipart/MultipartAttachmentsViewModel.kt

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -44,29 +44,9 @@ import okio.Path.Companion.toPath
4444
import javax.inject.Inject
4545
import kotlin.time.Duration.Companion.hours
4646

47-
@HiltViewModel
48-
class MultipartAttachmentsViewModel @Inject constructor(
49-
private val refreshAsset: RefreshCellAssetStateUseCase,
50-
private val download: DownloadCellFileUseCase,
51-
private val fileManager: FileManager,
52-
private val kaliumFileSystem: KaliumFileSystem,
53-
) : ViewModel() {
54-
55-
private companion object {
56-
val DEFAULT_CONTENT_URL_EXPIRY_MS = 1.hours.inWholeMilliseconds
57-
}
58-
59-
private val refreshed = ExpiringMap<String, Unit>(
60-
scope = viewModelScope,
61-
expirationMs = DEFAULT_CONTENT_URL_EXPIRY_MS,
62-
delegate = mutableMapOf(),
63-
onEntryExpired = { key, _ ->
64-
viewModelScope.launch { refreshAsset(key) }
65-
}
66-
)
67-
68-
private val uploadProgress = mutableStateMapOf<String, Float>()
69-
47+
interface MultipartAttachmentsViewModel {
48+
fun onClick(attachment: MultipartAttachmentUi, openInImageViewer: (String) -> Unit)
49+
fun refreshAssetState(attachment: MultipartAttachmentUi)
7050
fun mapAttachments(
7151
attachments: List<MessageAttachment>
7252
): List<MultipartAttachmentGroup> {
@@ -107,8 +87,38 @@ class MultipartAttachmentsViewModel @Inject constructor(
10787
data class Media(val attachments: List<MultipartAttachmentUi>) : MultipartAttachmentGroup
10888
data class Files(val attachments: List<MultipartAttachmentUi>) : MultipartAttachmentGroup
10989
}
90+
}
91+
92+
@Suppress("EmptyFunctionBlock")
93+
object MultipartAttachmentsViewModelPreview : MultipartAttachmentsViewModel {
94+
override fun onClick(attachment: MultipartAttachmentUi, openInImageViewer: (String) -> Unit) {}
95+
override fun refreshAssetState(attachment: MultipartAttachmentUi) {}
96+
}
97+
98+
@HiltViewModel
99+
class MultipartAttachmentsViewModelImpl @Inject constructor(
100+
private val refreshAsset: RefreshCellAssetStateUseCase,
101+
private val download: DownloadCellFileUseCase,
102+
private val fileManager: FileManager,
103+
private val kaliumFileSystem: KaliumFileSystem,
104+
) : ViewModel(), MultipartAttachmentsViewModel {
105+
106+
private companion object {
107+
val DEFAULT_CONTENT_URL_EXPIRY_MS = 1.hours.inWholeMilliseconds
108+
}
109+
110+
private val refreshed = ExpiringMap<String, Unit>(
111+
scope = viewModelScope,
112+
expirationMs = DEFAULT_CONTENT_URL_EXPIRY_MS,
113+
delegate = mutableMapOf(),
114+
onEntryExpired = { key, _ ->
115+
viewModelScope.launch { refreshAsset(key) }
116+
}
117+
)
118+
119+
private val uploadProgress = mutableStateMapOf<String, Float>()
110120

111-
fun onClick(attachment: MultipartAttachmentUi, openInImageViewer: (String) -> Unit) {
121+
override fun onClick(attachment: MultipartAttachmentUi, openInImageViewer: (String) -> Unit) {
112122
when {
113123
attachment.isImage() && !attachment.fileNotFound() -> openInImageViewer(attachment.uuid)
114124
attachment.fileNotFound() -> { refreshAssetState(attachment) }
@@ -118,7 +128,7 @@ class MultipartAttachmentsViewModel @Inject constructor(
118128
}
119129
}
120130

121-
fun refreshAssetState(attachment: MultipartAttachmentUi) {
131+
override fun refreshAssetState(attachment: MultipartAttachmentUi) {
122132

123133
if (attachment.source != AssetSource.CELL) return
124134
if (refreshed.contains(attachment.uuid)) return

app/src/main/kotlin/com/wire/android/ui/home/conversations/model/messagetypes/multipart/grid/AssetGridPreview.kt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package com.wire.android.ui.home.conversations.model.messagetypes.multipart.grid
1919

2020
import androidx.compose.foundation.background
21+
import androidx.compose.foundation.border
2122
import androidx.compose.foundation.clickable
2223
import androidx.compose.foundation.layout.Arrangement
2324
import androidx.compose.foundation.layout.Box
@@ -39,7 +40,6 @@ import com.wire.android.ui.common.dimensions
3940
import com.wire.android.ui.common.multipart.AssetSource
4041
import com.wire.android.ui.common.multipart.MultipartAttachmentUi
4142
import com.wire.android.ui.home.conversations.messages.item.MessageStyle
42-
import com.wire.android.ui.home.conversations.messages.item.isBubble
4343
import com.wire.android.ui.home.conversations.model.messagetypes.multipart.transferProgressColor
4444
import com.wire.android.ui.theme.WireTheme
4545
import com.wire.android.util.ui.PreviewMultipleThemes
@@ -57,13 +57,24 @@ internal fun AssetGridPreview(
5757
modifier = modifier
5858
.aspectRatio(1f)
5959
.clickable { onClick() }
60-
.applyIf(messageStyle.isBubble()) {
60+
.clip(RoundedCornerShape(dimensions().messageAttachmentCornerSize))
61+
.applyIf(messageStyle == MessageStyle.BUBBLE_SELF) {
62+
background(colorsScheme().selfBubble.secondary)
63+
}
64+
.applyIf(messageStyle == MessageStyle.BUBBLE_OTHER) {
65+
background(colorsScheme().otherBubble.secondary)
66+
}
67+
.applyIf(messageStyle == MessageStyle.NORMAL) {
6168
background(
62-
color = colorsScheme().surfaceVariant,
69+
color = colorsScheme().surface,
70+
shape = RoundedCornerShape(dimensions().messageAttachmentCornerSize)
71+
)
72+
border(
73+
width = dimensions().spacing1x,
74+
color = colorsScheme().outline,
6375
shape = RoundedCornerShape(dimensions().messageAttachmentCornerSize)
6476
)
6577
}
66-
.clip(RoundedCornerShape(dimensions().messageAttachmentCornerSize))
6778
) {
6879

6980
if (item.transferStatus != AssetTransferStatus.NOT_FOUND) {
@@ -92,7 +103,7 @@ internal fun AssetGridPreview(
92103
)
93104
}
94105
} else {
95-
AssetNotAvailableGridPreview()
106+
AssetNotAvailableGridPreview(messageStyle)
96107
}
97108
}
98109
}

0 commit comments

Comments
 (0)