Skip to content

Commit

Permalink
finished JumpToPlayingAudioButton
Browse files Browse the repository at this point in the history
  • Loading branch information
borichellow committed Dec 17, 2024
1 parent 9add5f4 commit 5fee401
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.wire.kalium.logic.feature.message.GetNotificationsUseCase
import com.wire.kalium.logic.feature.message.GetPaginatedFlowOfMessagesByConversationUseCase
import com.wire.kalium.logic.feature.message.GetPaginatedFlowOfMessagesBySearchQueryAndConversationIdUseCase
import com.wire.kalium.logic.feature.message.GetSearchedConversationMessagePositionUseCase
import com.wire.kalium.logic.feature.message.GetSenderNameByMessageIdUseCase
import com.wire.kalium.logic.feature.message.MarkMessagesAsNotifiedUseCase
import com.wire.kalium.logic.feature.message.MessageScope
import com.wire.kalium.logic.feature.message.ObserveMessageReactionsUseCase
Expand Down Expand Up @@ -216,4 +217,9 @@ class MessageModule {
@Provides
fun provideRemoveMessageDraftUseCase(messageScope: MessageScope): RemoveMessageDraftUseCase =
messageScope.removeMessageDraftUseCase

@ViewModelScoped
@Provides
fun provideGetSenderNameByMessageIdUseCase(messageScope: MessageScope): GetSenderNameByMessageIdUseCase =
messageScope.getSenderNameByMessageId
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,13 @@ import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.shape.CircleShape
Expand Down Expand Up @@ -72,6 +71,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
Expand Down Expand Up @@ -170,7 +170,6 @@ import com.wire.android.ui.home.messagecomposer.state.rememberMessageComposerSta
import com.wire.android.ui.legalhold.dialog.subject.LegalHoldSubjectMessageDialog
import com.wire.android.ui.theme.WireTheme
import com.wire.android.ui.theme.wireColorScheme
import com.wire.android.ui.theme.wireDimensions
import com.wire.android.ui.theme.wireTypography
import com.wire.android.util.DateAndTimeParsers
import com.wire.android.util.normalizeLink
Expand Down Expand Up @@ -937,7 +936,6 @@ private fun ConversationScreen(
selectedMessageId = conversationMessagesViewState.searchedMessageId,
messageComposerStateHolder = messageComposerStateHolder,
messages = conversationMessagesViewState.messages,
playingAudiMessage = conversationMessagesViewState.playingAudiMessage,
onSendMessage = onSendMessage,
onPingOptionClicked = onPingOptionClicked,
onImagesPicked = onImagesPicked,
Expand Down Expand Up @@ -1044,7 +1042,6 @@ private fun ConversationScreenContent(
onNavigateToReplyOriginalMessage: (UIMessage) -> Unit,
openDrawingCanvas: () -> Unit,
currentTimeInMillisFlow: Flow<Long> = flow {},
playingAudiMessage: PlayingAudiMessage?,
) {
val lazyPagingMessages = messages.collectAsLazyPagingItems()

Expand Down Expand Up @@ -1084,8 +1081,7 @@ private fun ConversationScreenContent(
conversationDetailsData = conversationDetailsData,
selectedMessageId = selectedMessageId,
interactionAvailability = messageComposerStateHolder.messageComposerViewState.value.interactionAvailability,
currentTimeInMillisFlow = currentTimeInMillisFlow,
playingAudiMessage = playingAudiMessage
currentTimeInMillisFlow = currentTimeInMillisFlow
)
},
onChangeSelfDeletionClicked = onChangeSelfDeletionClicked,
Expand Down Expand Up @@ -1151,8 +1147,7 @@ fun MessageList(
interactionAvailability: InteractionAvailability,
clickActions: MessageClickActions.Content,
modifier: Modifier = Modifier,
currentTimeInMillisFlow: Flow<Long> = flow { },
playingAudiMessage: PlayingAudiMessage?
currentTimeInMillisFlow: Flow<Long> = flow { }
) {
val prevItemCount = remember { mutableStateOf(lazyPagingMessages.itemCount) }
val readLastMessageAtStartTriggered = remember { mutableStateOf(false) }
Expand Down Expand Up @@ -1281,9 +1276,9 @@ fun MessageList(
}
}
JumpToPlayingAudioButton(
lazyPagingMessages = lazyPagingMessages,
lazyListState = lazyListState,
playingAudiMessage = playingAudiMessage
lazyPagingMessages = lazyPagingMessages,
playingAudiMessage = audioMessagesState.playingAudiMessage
)
JumpToLastMessageButton(lazyListState = lazyListState)
}
Expand Down Expand Up @@ -1423,8 +1418,8 @@ fun JumpToLastMessageButton(
fun BoxScope.JumpToPlayingAudioButton(
lazyListState: LazyListState,
playingAudiMessage: PlayingAudiMessage?,
modifier: Modifier = Modifier,
lazyPagingMessages: LazyPagingItems<UIMessage>,
modifier: Modifier = Modifier,
coroutineScope: CoroutineScope = rememberCoroutineScope()
) {
val indexOfPlayedMessage = playingAudiMessage?.let {
Expand All @@ -1434,43 +1429,45 @@ fun BoxScope.JumpToPlayingAudioButton(

if (indexOfPlayedMessage < 0) return

// todo cyka try to remember indexes
val visible = playingAudiMessage?.let {
val firstVisibleIndex = lazyListState.firstVisibleItemIndex
val lastVisibleIndex = firstVisibleIndex + lazyListState.layoutInfo.visibleItemsInfo.size
indexOfPlayedMessage in firstVisibleIndex..lastVisibleIndex
} ?: false
val firstVisibleIndex = lazyListState.firstVisibleItemIndex
val lastVisibleIndex = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull()?.index ?: firstVisibleIndex

if (!visible) return
if (indexOfPlayedMessage in firstVisibleIndex..lastVisibleIndex) return

Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.wrapContentWidth()
.align(Alignment.TopCenter)
.padding(all = dimensions().spacing8x)
.clickable { coroutineScope.launch { lazyListState.animateScrollToItem(indexOfPlayedMessage) } }
.padding(horizontal = dimensions().spacing16x, vertical = dimensions().spacing8x)
.background(
color = colorsScheme().secondaryText,
shape = RoundedCornerShape(MaterialTheme.wireDimensions.buttonCornerSize)
shape = RoundedCornerShape(dimensions().corner16x)
)
.padding(horizontal = dimensions().spacing16x, vertical = dimensions().spacing8x)
) {
Icon(
modifier = Modifier.weight(1f),
modifier = Modifier.size(dimensions().systemMessageIconSize),
painter = painterResource(id = R.drawable.ic_play),
contentDescription = null,
tint = MaterialTheme.wireColorScheme.onPrimaryButtonEnabled
)
Spacer(Modifier.width(dimensions().spacing8x))
Text(
modifier = Modifier
.padding(horizontal = dimensions().spacing8x)
.weight(1f, fill = false),
text = playingAudiMessage!!.authorName,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = colorsScheme().onPrimaryButtonEnabled,
style = MaterialTheme.wireTypography.body04,
)
Spacer(Modifier.width(dimensions().spacing8x))
Text(
modifier = Modifier.weight(1f),
modifier = Modifier,
text = DateAndTimeParsers.audioMessageTime(playingAudiMessage.currentTimeMs.toLong()),
color = colorsScheme().onPrimaryButtonEnabled,
style = MaterialTheme.wireTypography.body04,
style = MaterialTheme.wireTypography.label03,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseC
import com.wire.kalium.logic.feature.message.DeleteMessageUseCase
import com.wire.kalium.logic.feature.message.GetMessageByIdUseCase
import com.wire.kalium.logic.feature.message.GetSearchedConversationMessagePositionUseCase
import com.wire.kalium.logic.feature.message.GetSenderNameByMessageIdUseCase
import com.wire.kalium.logic.feature.message.ToggleReactionUseCase
import com.wire.kalium.logic.feature.sessionreset.ResetSessionResult
import com.wire.kalium.logic.feature.sessionreset.ResetSessionUseCase
Expand All @@ -80,7 +81,6 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
Expand Down Expand Up @@ -110,7 +110,8 @@ class ConversationMessagesViewModel @Inject constructor(
private val getConversationUnreadEventsCount: GetConversationUnreadEventsCountUseCase,
private val clearUsersTypingEvents: ClearUsersTypingEventsUseCase,
private val getSearchedConversationMessagePosition: GetSearchedConversationMessagePositionUseCase,
private val deleteMessage: DeleteMessageUseCase
private val deleteMessage: DeleteMessageUseCase,
private val getSenderNameByMessageId: GetSenderNameByMessageIdUseCase
) : SavedStateViewModel(savedStateHandle) {

private val conversationNavArgs: ConversationNavArgs = savedStateHandle.navArgs()
Expand Down Expand Up @@ -195,36 +196,34 @@ class ConversationMessagesViewModel @Inject constructor(
val playingMessageData = observableAudioMessagesState
.map { audioMessageStates ->
audioMessageStates.firstNotNullOfOrNull { (messageId, audioState) ->
if (audioState.audioMediaPlayingState == AudioMediaPlayingState.Playing) messageId
else null
if (audioState.audioMediaPlayingState == AudioMediaPlayingState.Playing) messageId else null
}
}.distinctUntilChanged()
.map { messageId -> messageId?.let { getMessageByIdUseCase(conversationId, it) } }
.filterIsInstance<GetMessageByIdUseCase.Result.Success?>()
.map { it?.message }
}
.distinctUntilChanged()
.map { messageId ->
val senderNameResult = messageId?.let { getSenderNameByMessageId(conversationId, it) }
val senderName = if (senderNameResult is GetSenderNameByMessageIdUseCase.Result.Success) senderNameResult.name
else null

messageId to senderName
}

viewModelScope.launch {
combine(
observableAudioMessagesState,
conversationAudioMessagePlayer.audioSpeed,
playingMessageData
) { audioMessageStates, audioSpeed, playingMessage ->
val audioMessagesState = AudioMessagesState(audioMessageStates.toPersistentMap(), audioSpeed)
val playingAudiMessage = playingMessage?.let {
) { audioMessageStates, audioSpeed, (playingMessageId, playingMessageSenderName) ->
val playingAudiMessage = playingMessageId?.let {
PlayingAudiMessage(
messageId = playingMessage.id,
authorName = playingMessage.sender?.name ?: "",
currentTimeMs = audioMessageStates[playingMessage.id]?.currentPositionInMs ?: 0
messageId = playingMessageId,
authorName = playingMessageSenderName.orEmpty(),
currentTimeMs = audioMessageStates[playingMessageId]?.currentPositionInMs ?: 0
)
}
audioMessagesState to playingAudiMessage
AudioMessagesState(audioMessageStates.toPersistentMap(), audioSpeed, playingAudiMessage)
}
.collect { (audioMessagesState, playingAudiMessage) ->
conversationViewState = conversationViewState.copy(
audioMessagesState = audioMessagesState,
playingAudiMessage = playingAudiMessage
)
}
.collect { conversationViewState = conversationViewState.copy(audioMessagesState = it) }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ data class ConversationMessagesViewState(
val downloadedAssetDialogState: DownloadedAssetDialogVisibilityState = DownloadedAssetDialogVisibilityState.Hidden,
val audioMessagesState: AudioMessagesState = AudioMessagesState(),
val assetStatuses: PersistentMap<String, MessageAssetStatus> = persistentMapOf(),
val searchedMessageId: String? = null,
val playingAudiMessage: PlayingAudiMessage? = null
val searchedMessageId: String? = null
)

data class AudioMessagesState(
val audioStates: PersistentMap<String, AudioState> = persistentMapOf(),
val audioSpeed: AudioSpeed = AudioSpeed.NORMAL
val audioSpeed: AudioSpeed = AudioSpeed.NORMAL,
val playingAudiMessage: PlayingAudiMessage? = null
)

data class PlayingAudiMessage(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import com.wire.kalium.logic.feature.conversation.ObserveConversationDetailsUseC
import com.wire.kalium.logic.feature.message.DeleteMessageUseCase
import com.wire.kalium.logic.feature.message.GetMessageByIdUseCase
import com.wire.kalium.logic.feature.message.GetSearchedConversationMessagePositionUseCase
import com.wire.kalium.logic.feature.message.GetSenderNameByMessageIdUseCase
import com.wire.kalium.logic.feature.message.ToggleReactionUseCase
import com.wire.kalium.logic.feature.sessionreset.ResetSessionResult
import com.wire.kalium.logic.feature.sessionreset.ResetSessionUseCase
Expand Down Expand Up @@ -116,6 +117,9 @@ class ConversationMessagesViewModelArrangement {
@MockK
lateinit var deleteMessage: DeleteMessageUseCase

@MockK
lateinit var getSenderNameByMessageId: GetSenderNameByMessageIdUseCase

private val viewModel: ConversationMessagesViewModel by lazy {
ConversationMessagesViewModel(
savedStateHandle,
Expand All @@ -133,7 +137,8 @@ class ConversationMessagesViewModelArrangement {
getConversationUnreadEventsCount,
clearUsersTypingEvents,
getSearchedConversationMessagePosition,
deleteMessage
deleteMessage,
getSenderNameByMessageId
)
}

Expand All @@ -158,6 +163,7 @@ class ConversationMessagesViewModelArrangement {

coEvery { conversationAudioMessagePlayer.audioSpeed } returns flowOf(AudioSpeed.NORMAL)
coEvery { conversationAudioMessagePlayer.fetchWavesMask(any(), any()) } returns Unit
coEvery { getSenderNameByMessageId(any(), any()) } returns GetSenderNameByMessageIdUseCase.Result.Success("User Name")
}

fun withSuccessfulViewModelInit() = apply {
Expand Down Expand Up @@ -231,5 +237,9 @@ class ConversationMessagesViewModelArrangement {
return this
}

fun withGetSenderNameByMessageId(result: GetSenderNameByMessageIdUseCase.Result) = apply {
coEvery { getSenderNameByMessageId(any(), any()) } returns result
}

fun arrange() = this to viewModel
}
Loading

0 comments on commit 5fee401

Please sign in to comment.