From 8109290650ea41f5ae7ad94ae9fe1f76e5d36d0e Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 17 Jul 2026 15:33:28 +0200 Subject: [PATCH] code review --- .../components/ActiveCallTimelineItemView.kt | 47 ++++++++++++++----- .../event/TimelineItemContentFactory.kt | 35 +++++++------- .../TimelineItemRtcNotificationContent.kt | 2 +- .../api/timeline/item/event/EventContent.kt | 2 +- .../item/event/TimelineEventContentMapper.kt | 2 +- 5 files changed, 57 insertions(+), 31 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ActiveCallTimelineItemView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ActiveCallTimelineItemView.kt index fd2364316d..34e17f8ab6 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ActiveCallTimelineItemView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/ActiveCallTimelineItemView.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -92,9 +93,6 @@ internal fun ActiveCallTimelineItemView( } } - val elapsedMillis = (currentTime - state.callStartTsMillis).coerceAtLeast(0) - val formattedDuration = elapsedMillis.toHumanReadableDuration() - Column(modifier = modifier) { Row( modifier = Modifier @@ -142,18 +140,16 @@ internal fun ActiveCallTimelineItemView( ) { if (!state.isJoined) { Button( - text = "Join", + text = stringResource(CommonStrings.action_join), size = ButtonSize.Small, onClick = { onJoinCallClick(state.callIntent == CallIntent.AUDIO) } ) } - Text( - text = "($formattedDuration)", - style = ElementTheme.typography.fontBodyXsRegular, - color = ElementTheme.colors.textSecondary, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) + if (state.callStartTsMillis != null) { + CallDurationText( + state.callStartTsMillis, + ) + } } } @@ -188,7 +184,7 @@ private fun DirectMessageCallBody(state: RtcNotificationState.Active, modifier: ) Text( modifier = Modifier.padding(start = 6.dp), - text = "${caller.displayName ?: caller.userId} started a call", + text = stringResource(CommonStrings.common_user_started_a_call, caller.displayName ?: caller.userId), style = ElementTheme.typography.fontBodyMdMedium, color = ElementTheme.colors.textPrimary, ) @@ -283,6 +279,33 @@ private fun GroupCallBody(event: TimelineItem.Event, state: RtcNotificationState } } +@Composable +private fun CallDurationText( + startTsMillis: Long, + modifier: Modifier = Modifier, +) { + val duration by produceState( + initialValue = formatElapsed(startTsMillis), + startTsMillis, + ) { + while (true) { + delay(1.seconds) + value = formatElapsed(startTsMillis) + } + } + Text( + modifier = modifier, + text = "($duration)", + style = ElementTheme.typography.fontBodyXsRegular, + color = ElementTheme.colors.textSecondary, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) +} + +private fun formatElapsed(startTsMillis: Long): String = + (System.currentTimeMillis() - startTsMillis).coerceAtLeast(0).toHumanReadableDuration() + @PreviewsDayNight @PreviewWithLargeHeight @Composable diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt index d5367c872d..3bc7f9f070 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/event/TimelineItemContentFactory.kt @@ -111,22 +111,25 @@ class TimelineItemContentFactory( is UnableToDecryptContent -> utdFactory.create(itemContent) is CallNotifyContent -> TimelineItemRtcNotificationContent( callIntent = itemContent.callIntent, - state = if (itemContent.activeMembers.isNotEmpty()) { - RtcNotificationState.Active( - joinedMembers = itemContent.activeMembers.map { active -> - roomMembers.find { - it.userId == active - }?.toMatrixUser() ?: MatrixUser(active) - }, - isJoined = itemContent.isJoined, - callStartTsMillis = itemContent.callStartTsMillis, - callIntent = itemContent.callIntent - ) - } else { - if (itemContent.declinedBy.isEmpty()) { - RtcNotificationState.Started - } else { - RtcNotificationState.Declined(itemContent.declinedBy.any { it == sessionId }) + state = when { + itemContent.activeMembers.isNotEmpty() -> { + RtcNotificationState.Active( + joinedMembers = itemContent.activeMembers.map { active -> + roomMembers.find { + it.userId == active + }?.toMatrixUser() ?: MatrixUser(active) + }, + isJoined = itemContent.isJoined, + callStartTsMillis = itemContent.callStartTsMillis, + callIntent = itemContent.callIntent + ) + } + else -> { + if (itemContent.declinedBy.isEmpty()) { + RtcNotificationState.Started + } else { + RtcNotificationState.Declined(itemContent.declinedBy.any { it == sessionId }) + } } } ) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemRtcNotificationContent.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemRtcNotificationContent.kt index c48641982f..c0db3a7547 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemRtcNotificationContent.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/event/TimelineItemRtcNotificationContent.kt @@ -18,7 +18,7 @@ sealed interface RtcNotificationState { data class Active( val joinedMembers: List, val isJoined: Boolean, - val callStartTsMillis: Long, + val callStartTsMillis: Long?, val callIntent: CallIntent, ) : RtcNotificationState diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt index f60312e1d1..c2d388ecb0 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventContent.kt @@ -123,7 +123,7 @@ data class CallNotifyContent( val declinedBy: List, val activeMembers: List, val isJoined: Boolean, - val callStartTsMillis: Long, + val callStartTsMillis: Long?, ) : EventContent data object UnknownContent : EventContent diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt index 93f7c608d7..98efa505d0 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/TimelineEventContentMapper.kt @@ -156,7 +156,7 @@ class TimelineEventContentMapper( }, declinedBy = it.declinedBy.map(::UserId), activeMembers = it.activeMembers.map(::UserId), - callStartTsMillis = it.callStartTsMillis?.toLong() ?: 0, + callStartTsMillis = it.callStartTsMillis?.toLong(), isJoined = it.isJoined ) }