Skip to content

Commit 15ec417

Browse files
committed
fix: message text typing (WPB-16897)
1 parent 493260f commit 15ec417

File tree

5 files changed

+118
-55
lines changed

5 files changed

+118
-55
lines changed

app/src/main/kotlin/com/wire/android/di/accountScoped/MessageModule.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ import com.wire.kalium.logic.feature.asset.GetMessageAssetUseCase
2626
import com.wire.kalium.logic.feature.asset.GetPaginatedFlowOfAssetMessageByConversationIdUseCase
2727
import com.wire.kalium.logic.feature.asset.ObserveAssetStatusesUseCase
2828
import com.wire.kalium.logic.feature.asset.ObservePaginatedAssetImageMessages
29-
import com.wire.kalium.logic.feature.asset.upload.ScheduleNewAssetMessageUseCase
3029
import com.wire.kalium.logic.feature.asset.UpdateAssetMessageTransferStatusUseCase
30+
import com.wire.kalium.logic.feature.asset.upload.ScheduleNewAssetMessageUseCase
3131
import com.wire.kalium.logic.feature.incallreaction.SendInCallReactionUseCase
3232
import com.wire.kalium.logic.feature.message.DeleteMessageUseCase
3333
import com.wire.kalium.logic.feature.message.GetMessageByIdUseCase
@@ -49,7 +49,7 @@ import com.wire.kalium.logic.feature.message.SendMultipartMessageUseCase
4949
import com.wire.kalium.logic.feature.message.SendTextMessageUseCase
5050
import com.wire.kalium.logic.feature.message.ToggleReactionUseCase
5151
import com.wire.kalium.logic.feature.message.composite.SendButtonActionMessageUseCase
52-
import com.wire.kalium.logic.feature.message.draft.ObserveMessageDraftUseCase
52+
import com.wire.kalium.logic.feature.message.draft.GetMessageDraftUseCase
5353
import com.wire.kalium.logic.feature.message.draft.RemoveMessageDraftUseCase
5454
import com.wire.kalium.logic.feature.message.draft.SaveMessageDraftUseCase
5555
import com.wire.kalium.logic.feature.message.ephemeral.EnqueueMessageSelfDeletionUseCase
@@ -218,8 +218,8 @@ class MessageModule {
218218

219219
@ViewModelScoped
220220
@Provides
221-
fun provideObserveMessageDraftUseCase(messageScope: MessageScope): ObserveMessageDraftUseCase =
222-
messageScope.observeMessageDraftUseCase
221+
fun provideGetMessageDraftUseCase(messageScope: MessageScope): GetMessageDraftUseCase =
222+
messageScope.getMessageDraftUseCase
223223

224224
@ViewModelScoped
225225
@Provides

app/src/main/kotlin/com/wire/android/ui/home/conversations/messages/draft/MessageDraftViewModel.kt

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,25 @@ import androidx.lifecycle.viewModelScope
2424
import com.wire.android.ui.home.conversations.ConversationNavArgs
2525
import com.wire.android.ui.home.conversations.model.UIQuotedMessage
2626
import com.wire.android.ui.home.conversations.model.toUiMention
27-
import com.wire.android.ui.home.conversations.usecase.ObserveQuoteMessageForConversationUseCase
27+
import com.wire.android.ui.home.conversations.usecase.GetQuoteMessageForConversationUseCase
2828
import com.wire.android.ui.home.messagecomposer.model.MessageComposition
2929
import com.wire.android.ui.home.messagecomposer.model.toDraft
3030
import com.wire.android.ui.home.messagecomposer.model.update
3131
import com.wire.android.ui.navArgs
3232
import com.wire.android.util.EMPTY
3333
import com.wire.kalium.logic.data.id.QualifiedID
3434
import com.wire.kalium.logic.data.message.draft.MessageDraft
35-
import com.wire.kalium.logic.feature.message.draft.ObserveMessageDraftUseCase
35+
import com.wire.kalium.logic.feature.message.draft.GetMessageDraftUseCase
3636
import com.wire.kalium.logic.feature.message.draft.SaveMessageDraftUseCase
3737
import dagger.hilt.android.lifecycle.HiltViewModel
38-
import kotlinx.coroutines.flow.flatMapLatest
39-
import kotlinx.coroutines.flow.flowOf
40-
import kotlinx.coroutines.flow.map
4138
import kotlinx.coroutines.launch
4239
import javax.inject.Inject
4340

4441
@HiltViewModel
4542
class MessageDraftViewModel @Inject constructor(
4643
val savedStateHandle: SavedStateHandle,
47-
private val observeMessageDraft: ObserveMessageDraftUseCase,
48-
private val observeQuotedMessage: ObserveQuoteMessageForConversationUseCase,
44+
private val getMessageDraft: GetMessageDraftUseCase,
45+
private val getQuotedMessage: GetQuoteMessageForConversationUseCase,
4946
private val saveMessageDraft: SaveMessageDraftUseCase,
5047
) : ViewModel() {
5148

@@ -56,7 +53,7 @@ class MessageDraftViewModel @Inject constructor(
5653
private set
5754

5855
init {
59-
observeMessageDraft()
56+
loadMessageDraft()
6057
}
6158

6259
fun clearDraft() {
@@ -74,34 +71,28 @@ class MessageDraftViewModel @Inject constructor(
7471
}
7572
}
7673

77-
private fun observeMessageDraft() = viewModelScope.launch {
78-
observeMessageDraft(conversationId)
79-
.flatMapLatest { draft ->
80-
observeQuoted(draft?.quotedMessageId)
81-
.map { quotedMessage -> draft to quotedMessage }
82-
}.collect { (draft, quotedMessage) ->
83-
if (draft == null) {
84-
state.update { messageComposition ->
85-
MessageComposition(conversationId = conversationId)
86-
}
87-
} else {
88-
state.update { messageComposition ->
89-
messageComposition.copy(
90-
draftText = draft.text,
91-
selectedMentions = draft.selectedMentionList.mapNotNull { it.toUiMention(draft.text) },
92-
editMessageId = draft.editMessageId,
93-
quotedMessage = quotedMessage as? UIQuotedMessage.UIQuotedData,
94-
quotedMessageId = (quotedMessage as? UIQuotedMessage.UIQuotedData)?.messageId,
95-
)
96-
}
97-
}
74+
private fun loadMessageDraft() = viewModelScope.launch {
75+
getMessageDraft(conversationId)?.let { draft ->
76+
77+
val quotedMessage = draft.quotedMessageId?.let { quotedMessageId ->
78+
getQuotedMessage(conversationId, quotedMessageId)
9879
}
99-
}
10080

101-
private suspend fun observeQuoted(quotedMessageId: String?) =
102-
quotedMessageId?.let { quotedMessageId ->
103-
observeQuotedMessage(conversationId, quotedMessageId)
104-
} ?: flowOf(UIQuotedMessage.UnavailableData)
81+
state.update { messageComposition ->
82+
messageComposition.copy(
83+
draftText = draft.text,
84+
selectedMentions = draft.selectedMentionList.mapNotNull { it.toUiMention(draft.text) },
85+
editMessageId = draft.editMessageId,
86+
quotedMessage = quotedMessage as? UIQuotedMessage.UIQuotedData,
87+
quotedMessageId = (quotedMessage as? UIQuotedMessage.UIQuotedData)?.messageId,
88+
)
89+
}
90+
} ?: run {
91+
state.update { messageComposition ->
92+
MessageComposition(conversationId = conversationId)
93+
}
94+
}
95+
}
10596

10697
fun saveDraft(messageDraft: MessageDraft) {
10798
viewModelScope.launch {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Wire
3+
* Copyright (C) 2025 Wire Swiss GmbH
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see http://www.gnu.org/licenses/.
17+
*/
18+
19+
package com.wire.android.ui.home.conversations.usecase
20+
21+
import com.wire.android.mapper.MessageMapper
22+
import com.wire.android.ui.home.conversations.model.UIMessage
23+
import com.wire.android.ui.home.conversations.model.UIQuotedMessage
24+
import com.wire.android.ui.home.conversations.model.mapToQuotedContent
25+
import com.wire.android.util.dispatchers.DispatcherProvider
26+
import com.wire.android.util.ui.toUIText
27+
import com.wire.kalium.logic.data.id.ConversationId
28+
import com.wire.kalium.logic.data.message.Message
29+
import com.wire.kalium.logic.feature.message.GetMessageByIdUseCase
30+
import kotlinx.coroutines.withContext
31+
import javax.inject.Inject
32+
33+
class GetQuoteMessageForConversationUseCase @Inject constructor(
34+
private val getMessageById: GetMessageByIdUseCase,
35+
private val getUsersForMessage: GetUsersForMessageUseCase,
36+
private val messageMapper: MessageMapper,
37+
private val dispatchers: DispatcherProvider,
38+
) {
39+
40+
suspend operator fun invoke(conversationId: ConversationId, quotedMessageId: String): UIQuotedMessage = withContext(dispatchers.io()) {
41+
when (val result = getMessageById(conversationId, quotedMessageId)) {
42+
is GetMessageByIdUseCase.Result.Failure -> UIQuotedMessage.UnavailableData
43+
is GetMessageByIdUseCase.Result.Success -> {
44+
when (val message = result.message) {
45+
is Message.Regular -> {
46+
val usersForMessage = getUsersForMessage(message)
47+
when (val uiMessage = messageMapper.toUIMessage(usersForMessage, message)) {
48+
is UIMessage.Regular -> uiMessage.mapToQuotedContent()?.let { quotedContent ->
49+
uiMessage.header.userId?.let { senderId ->
50+
UIQuotedMessage.UIQuotedData(
51+
messageId = uiMessage.header.messageId,
52+
senderId = senderId,
53+
senderName = uiMessage.header.username,
54+
originalMessageDateDescription = "".toUIText(),
55+
editedTimeDescription = "".toUIText(),
56+
quotedContent = quotedContent,
57+
senderAccent = uiMessage.header.accent
58+
)
59+
}
60+
} ?: UIQuotedMessage.UnavailableData
61+
62+
is UIMessage.System -> UIQuotedMessage.UnavailableData
63+
null -> UIQuotedMessage.UnavailableData
64+
}
65+
}
66+
67+
is Message.Signaling -> UIQuotedMessage.UnavailableData
68+
is Message.System -> UIQuotedMessage.UnavailableData
69+
}
70+
}
71+
}
72+
}
73+
}

app/src/test/kotlin/com/wire/android/ui/home/conversations/messages/draft/MessageDraftViewModelTest.kt

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,20 @@ import com.wire.android.config.mockUri
2626
import com.wire.android.framework.TestConversation
2727
import com.wire.android.ui.home.conversations.ConversationNavArgs
2828
import com.wire.android.ui.home.conversations.model.UIQuotedMessage
29-
import com.wire.android.ui.home.conversations.usecase.ObserveQuoteMessageForConversationUseCase
29+
import com.wire.android.ui.home.conversations.usecase.GetQuoteMessageForConversationUseCase
3030
import com.wire.android.ui.navArgs
3131
import com.wire.android.ui.theme.Accent
3232
import com.wire.android.util.ui.UIText
3333
import com.wire.kalium.logic.data.message.draft.MessageDraft
3434
import com.wire.kalium.logic.data.user.UserId
35-
import com.wire.kalium.logic.feature.message.draft.ObserveMessageDraftUseCase
35+
import com.wire.kalium.logic.feature.message.draft.GetMessageDraftUseCase
3636
import com.wire.kalium.logic.feature.message.draft.SaveMessageDraftUseCase
3737
import io.mockk.MockKAnnotations
3838
import io.mockk.coEvery
3939
import io.mockk.coVerify
4040
import io.mockk.every
4141
import io.mockk.impl.annotations.MockK
4242
import kotlinx.coroutines.ExperimentalCoroutinesApi
43-
import kotlinx.coroutines.flow.flowOf
4443
import kotlinx.coroutines.test.advanceUntilIdle
4544
import kotlinx.coroutines.test.runTest
4645
import org.junit.jupiter.api.Assertions.assertEquals
@@ -71,7 +70,7 @@ class MessageDraftViewModelTest {
7170
// then
7271
assertEquals(messageDraft.text, viewModel.state.value.draftText)
7372
coVerify(exactly = 1) {
74-
arrangement.observeMessageDraft(any())
73+
arrangement.getMessageDraft(any())
7574
}
7675
}
7776

@@ -88,7 +87,7 @@ class MessageDraftViewModelTest {
8887
// then
8988
assertEquals(true, viewModel.state.value.draftText.isEmpty())
9089
coVerify(exactly = 1) {
91-
arrangement.observeMessageDraft(any())
90+
arrangement.getMessageDraft(any())
9291
}
9392
}
9493

@@ -125,10 +124,10 @@ class MessageDraftViewModelTest {
125124
assertEquals(quotedData, viewModel.state.value.quotedMessage)
126125

127126
coVerify(exactly = 1) {
128-
arrangement.observeMessageDraft(any())
127+
arrangement.getMessageDraft(any())
129128
}
130129
coVerify(exactly = 1) {
131-
arrangement.observeQuoteMessageForConversation(any(), any())
130+
arrangement.getQuoteMessageForConversation(any(), any())
132131
}
133132
}
134133

@@ -157,10 +156,10 @@ class MessageDraftViewModelTest {
157156
assertEquals(null, viewModel.state.value.quotedMessageId)
158157

159158
coVerify(exactly = 1) {
160-
arrangement.observeMessageDraft(any())
159+
arrangement.getMessageDraft(any())
161160
}
162161
coVerify(exactly = 1) {
163-
arrangement.observeQuoteMessageForConversation(any(), any())
162+
arrangement.getQuoteMessageForConversation(any(), any())
164163
}
165164
}
166165

@@ -179,33 +178,33 @@ class MessageDraftViewModelTest {
179178
private lateinit var savedStateHandle: SavedStateHandle
180179

181180
@MockK
182-
lateinit var observeMessageDraft: ObserveMessageDraftUseCase
181+
lateinit var getMessageDraft: GetMessageDraftUseCase
183182

184183
@MockK
185184
lateinit var saveMessageDraft: SaveMessageDraftUseCase
186185

187186
@MockK
188-
lateinit var observeQuoteMessageForConversation: ObserveQuoteMessageForConversationUseCase
187+
lateinit var getQuoteMessageForConversation: GetQuoteMessageForConversationUseCase
189188

190189
private val viewModel by lazy {
191190
MessageDraftViewModel(
192191
savedStateHandle,
193-
observeMessageDraft,
194-
observeQuoteMessageForConversation,
192+
getMessageDraft,
193+
getQuoteMessageForConversation,
195194
saveMessageDraft,
196195
)
197196
}
198197

199198
fun withNoMessageDraft() = apply {
200-
coEvery { observeMessageDraft(any()) } returns flowOf()
199+
coEvery { getMessageDraft(any()) } returns null
201200
}
202201

203202
fun withMessageDraft(messageDraft: MessageDraft) = apply {
204-
coEvery { observeMessageDraft(any()) } returns flowOf(messageDraft)
203+
coEvery { getMessageDraft(any()) } returns messageDraft
205204
}
206205

207206
fun withQuotedMessage(quotedMessage: UIQuotedMessage) = apply {
208-
coEvery { observeQuoteMessageForConversation(any(), any()) } returns flowOf(quotedMessage)
207+
coEvery { getQuoteMessageForConversation(any(), any()) } returns quotedMessage
209208
}
210209

211210
fun arrange() = this to viewModel

0 commit comments

Comments
 (0)