feat: call duration in system messages
surely calls will last multiple years
This commit is contained in:
parent
a8b2f61eb0
commit
100c06d8a5
|
|
@ -24,14 +24,17 @@ import androidx.compose.ui.draw.clip
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.stoat.R
|
||||
import chat.stoat.api.StoatAPI
|
||||
import chat.stoat.api.internals.ULID
|
||||
import chat.stoat.composables.markdown.prose.ChatMarkdown
|
||||
import chat.stoat.core.model.schemas.Message
|
||||
import kotlinx.datetime.Instant
|
||||
|
||||
enum class SystemMessageType(val type: String) {
|
||||
CHANNEL_OWNERSHIP_CHANGED("channel_ownership_changed"),
|
||||
|
|
@ -213,11 +216,23 @@ fun SystemMessage(
|
|||
}
|
||||
|
||||
SystemMessageType.CALL_STARTED -> {
|
||||
val callDuration = callDurationMillis(
|
||||
messageId = message.id,
|
||||
finishedAt = message.system!!.finishedAt
|
||||
)
|
||||
ChatMarkdown(
|
||||
stringResource(
|
||||
R.string.system_message_call_started,
|
||||
message.system!!.by.mention()
|
||||
),
|
||||
if (callDuration != null) {
|
||||
stringResource(
|
||||
R.string.system_message_call_started_with_finished_at,
|
||||
message.system!!.by.mention(),
|
||||
formatCallDuration(callDuration)
|
||||
)
|
||||
} else {
|
||||
stringResource(
|
||||
R.string.system_message_call_started,
|
||||
message.system!!.by.mention()
|
||||
)
|
||||
},
|
||||
serverId = serverId
|
||||
)
|
||||
}
|
||||
|
|
@ -230,6 +245,112 @@ fun SystemMessage(
|
|||
}
|
||||
}
|
||||
|
||||
internal fun callDurationMillis(messageId: String?, finishedAt: String?): Long? {
|
||||
if (messageId == null || finishedAt == null) return null
|
||||
|
||||
return runCatching {
|
||||
val duration = Math.subtractExact(
|
||||
Instant.parse(finishedAt).toEpochMilliseconds(),
|
||||
ULID.asTimestamp(messageId)
|
||||
)
|
||||
duration.takeIf { it >= 0 }
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
internal enum class CallDurationUnit {
|
||||
FEW_SECONDS,
|
||||
MINUTES,
|
||||
HOURS,
|
||||
DAYS,
|
||||
MONTHS,
|
||||
YEARS,
|
||||
}
|
||||
|
||||
internal data class CallDuration(
|
||||
val unit: CallDurationUnit,
|
||||
val quantity: Int = 0,
|
||||
)
|
||||
|
||||
internal fun humanizeCallDuration(durationMillis: Long): CallDuration {
|
||||
val seconds = durationMillis.coerceAtLeast(0) / MILLIS_PER_SECOND
|
||||
return when {
|
||||
seconds < SECONDS_PER_MINUTE -> CallDuration(CallDurationUnit.FEW_SECONDS)
|
||||
seconds < SECONDS_PER_HOUR -> CallDuration(
|
||||
CallDurationUnit.MINUTES,
|
||||
(seconds / SECONDS_PER_MINUTE).asQuantity()
|
||||
)
|
||||
|
||||
seconds < SECONDS_PER_DAY -> CallDuration(
|
||||
CallDurationUnit.HOURS,
|
||||
(seconds / SECONDS_PER_HOUR).asQuantity()
|
||||
)
|
||||
|
||||
seconds < SECONDS_PER_MONTH -> CallDuration(
|
||||
CallDurationUnit.DAYS,
|
||||
(seconds / SECONDS_PER_DAY).asQuantity()
|
||||
)
|
||||
|
||||
seconds < SECONDS_PER_YEAR -> CallDuration(
|
||||
CallDurationUnit.MONTHS,
|
||||
(seconds / SECONDS_PER_MONTH).asQuantity()
|
||||
)
|
||||
|
||||
else -> CallDuration(
|
||||
CallDurationUnit.YEARS,
|
||||
(seconds / SECONDS_PER_YEAR).asQuantity()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private const val MILLIS_PER_SECOND = 1_000L
|
||||
private const val SECONDS_PER_MINUTE = 60L
|
||||
private const val SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE
|
||||
private const val SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR
|
||||
private const val SECONDS_PER_MONTH = 30 * SECONDS_PER_DAY
|
||||
private const val SECONDS_PER_YEAR = 365 * SECONDS_PER_DAY
|
||||
|
||||
private fun Long.asQuantity(): Int = coerceAtMost(Int.MAX_VALUE.toLong()).toInt()
|
||||
|
||||
@Composable
|
||||
private fun formatCallDuration(durationMillis: Long): String {
|
||||
val duration = humanizeCallDuration(durationMillis)
|
||||
return when (duration.unit) {
|
||||
CallDurationUnit.FEW_SECONDS -> stringResource(
|
||||
R.string.system_message_call_duration_few_seconds
|
||||
)
|
||||
|
||||
CallDurationUnit.MINUTES -> pluralStringResource(
|
||||
R.plurals.system_message_call_duration_minutes,
|
||||
duration.quantity,
|
||||
duration.quantity
|
||||
)
|
||||
|
||||
CallDurationUnit.HOURS -> pluralStringResource(
|
||||
R.plurals.system_message_call_duration_hours,
|
||||
duration.quantity,
|
||||
duration.quantity
|
||||
)
|
||||
|
||||
CallDurationUnit.DAYS -> pluralStringResource(
|
||||
R.plurals.system_message_call_duration_days,
|
||||
duration.quantity,
|
||||
duration.quantity
|
||||
)
|
||||
|
||||
CallDurationUnit.MONTHS -> pluralStringResource(
|
||||
R.plurals.system_message_call_duration_months,
|
||||
duration.quantity,
|
||||
duration.quantity
|
||||
)
|
||||
|
||||
CallDurationUnit.YEARS -> pluralStringResource(
|
||||
R.plurals.system_message_call_duration_years,
|
||||
duration.quantity,
|
||||
duration.quantity
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SystemMessageIcon(type: SystemMessageType, modifier: Modifier = Modifier, size: Dp = 24.dp) {
|
||||
when (type) {
|
||||
|
|
|
|||
|
|
@ -316,6 +316,28 @@
|
|||
<string name="system_message_message_pinned">%1$s pinned a message to this channel</string>
|
||||
<string name="system_message_message_unpinned">%1$s unpinned a message from this channel</string>
|
||||
<string name="system_message_call_started">%1$s started a call</string>
|
||||
<string name="system_message_call_started_with_finished_at">%1$s started a call which lasted %2$s</string>
|
||||
<string name="system_message_call_duration_few_seconds">a few seconds</string>
|
||||
<plurals name="system_message_call_duration_minutes">
|
||||
<item quantity="one">%1$d minute</item>
|
||||
<item quantity="other">%1$d minutes</item>
|
||||
</plurals>
|
||||
<plurals name="system_message_call_duration_hours">
|
||||
<item quantity="one">%1$d hour</item>
|
||||
<item quantity="other">%1$d hours</item>
|
||||
</plurals>
|
||||
<plurals name="system_message_call_duration_days">
|
||||
<item quantity="one">%1$d day</item>
|
||||
<item quantity="other">%1$d days</item>
|
||||
</plurals>
|
||||
<plurals name="system_message_call_duration_months">
|
||||
<item quantity="one">%1$d month</item>
|
||||
<item quantity="other">%1$d months</item>
|
||||
</plurals>
|
||||
<plurals name="system_message_call_duration_years">
|
||||
<item quantity="one">%1$d year</item>
|
||||
<item quantity="other">%1$d years</item>
|
||||
</plurals>
|
||||
|
||||
<string name="today">Today</string>
|
||||
<string name="yesterday">Yesterday</string>
|
||||
|
|
|
|||
|
|
@ -111,7 +111,8 @@ data class SystemInfo(
|
|||
val by: String? = null,
|
||||
val from: String? = null,
|
||||
val to: String? = null,
|
||||
val content: String? = null
|
||||
val content: String? = null,
|
||||
@SerialName("finished_at") val finishedAt: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
|
|
|
|||
Loading…
Reference in New Issue