code review

This commit is contained in:
Valere
2026-07-17 15:33:28 +02:00
parent 2112e1bf04
commit 8109290650
5 changed files with 57 additions and 31 deletions
@@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment 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) { Column(modifier = modifier) {
Row( Row(
modifier = Modifier modifier = Modifier
@@ -142,18 +140,16 @@ internal fun ActiveCallTimelineItemView(
) { ) {
if (!state.isJoined) { if (!state.isJoined) {
Button( Button(
text = "Join", text = stringResource(CommonStrings.action_join),
size = ButtonSize.Small, size = ButtonSize.Small,
onClick = { onJoinCallClick(state.callIntent == CallIntent.AUDIO) } onClick = { onJoinCallClick(state.callIntent == CallIntent.AUDIO) }
) )
} }
Text( if (state.callStartTsMillis != null) {
text = "($formattedDuration)", CallDurationText(
style = ElementTheme.typography.fontBodyXsRegular, state.callStartTsMillis,
color = ElementTheme.colors.textSecondary, )
maxLines = 1, }
overflow = TextOverflow.Ellipsis,
)
} }
} }
@@ -188,7 +184,7 @@ private fun DirectMessageCallBody(state: RtcNotificationState.Active, modifier:
) )
Text( Text(
modifier = Modifier.padding(start = 6.dp), 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, style = ElementTheme.typography.fontBodyMdMedium,
color = ElementTheme.colors.textPrimary, 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 @PreviewsDayNight
@PreviewWithLargeHeight @PreviewWithLargeHeight
@Composable @Composable
@@ -111,22 +111,25 @@ class TimelineItemContentFactory(
is UnableToDecryptContent -> utdFactory.create(itemContent) is UnableToDecryptContent -> utdFactory.create(itemContent)
is CallNotifyContent -> TimelineItemRtcNotificationContent( is CallNotifyContent -> TimelineItemRtcNotificationContent(
callIntent = itemContent.callIntent, callIntent = itemContent.callIntent,
state = if (itemContent.activeMembers.isNotEmpty()) { state = when {
RtcNotificationState.Active( itemContent.activeMembers.isNotEmpty() -> {
joinedMembers = itemContent.activeMembers.map { active -> RtcNotificationState.Active(
roomMembers.find { joinedMembers = itemContent.activeMembers.map { active ->
it.userId == active roomMembers.find {
}?.toMatrixUser() ?: MatrixUser(active) it.userId == active
}, }?.toMatrixUser() ?: MatrixUser(active)
isJoined = itemContent.isJoined, },
callStartTsMillis = itemContent.callStartTsMillis, isJoined = itemContent.isJoined,
callIntent = itemContent.callIntent callStartTsMillis = itemContent.callStartTsMillis,
) callIntent = itemContent.callIntent
} else { )
if (itemContent.declinedBy.isEmpty()) { }
RtcNotificationState.Started else -> {
} else { if (itemContent.declinedBy.isEmpty()) {
RtcNotificationState.Declined(itemContent.declinedBy.any { it == sessionId }) RtcNotificationState.Started
} else {
RtcNotificationState.Declined(itemContent.declinedBy.any { it == sessionId })
}
} }
} }
) )
@@ -18,7 +18,7 @@ sealed interface RtcNotificationState {
data class Active( data class Active(
val joinedMembers: List<MatrixUser>, val joinedMembers: List<MatrixUser>,
val isJoined: Boolean, val isJoined: Boolean,
val callStartTsMillis: Long, val callStartTsMillis: Long?,
val callIntent: CallIntent, val callIntent: CallIntent,
) : RtcNotificationState ) : RtcNotificationState
@@ -123,7 +123,7 @@ data class CallNotifyContent(
val declinedBy: List<UserId>, val declinedBy: List<UserId>,
val activeMembers: List<UserId>, val activeMembers: List<UserId>,
val isJoined: Boolean, val isJoined: Boolean,
val callStartTsMillis: Long, val callStartTsMillis: Long?,
) : EventContent ) : EventContent
data object UnknownContent : EventContent data object UnknownContent : EventContent
@@ -156,7 +156,7 @@ class TimelineEventContentMapper(
}, },
declinedBy = it.declinedBy.map(::UserId), declinedBy = it.declinedBy.map(::UserId),
activeMembers = it.activeMembers.map(::UserId), activeMembers = it.activeMembers.map(::UserId),
callStartTsMillis = it.callStartTsMillis?.toLong() ?: 0, callStartTsMillis = it.callStartTsMillis?.toLong(),
isJoined = it.isJoined isJoined = it.isJoined
) )
} }