Added countdowns in chat bubbles for ephemeral messages

This commit is contained in:
Sylvain Berfini 2024-05-17 14:30:11 +02:00
parent 6ecc0839ea
commit 01d721d477
6 changed files with 125 additions and 0 deletions

View file

@ -19,6 +19,7 @@
*/
package org.linphone.ui.main.chat.model
import android.os.CountDownTimer
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.Spanned
@ -108,6 +109,10 @@ class MessageModel @WorkerThread constructor(
val statusIcon = MutableLiveData<Int>()
val isEphemeral = MutableLiveData<Boolean>()
val ephemeralLifetime = MutableLiveData<String>()
val text = MutableLiveData<Spannable>()
val reactions = MutableLiveData<String>()
@ -169,6 +174,8 @@ class MessageModel @WorkerThread constructor(
}
// End of voice record related fields
private lateinit var countDownTimer: CountDownTimer
private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private var transferringFileModel: FileModel? = null
@ -234,12 +241,20 @@ class MessageModel @WorkerThread constructor(
}
model?.transferProgress?.postValue(percent)
}
@WorkerThread
override fun onEphemeralMessageTimerStarted(message: ChatMessage) {
Log.d("$TAG Ephemeral timer started")
updateEphemeralTimer()
}
}
init {
groupedWithNextMessage.postValue(isGroupedWithNextOne)
groupedWithPreviousMessage.postValue(isGroupedWithPreviousOne)
isPlayingVoiceRecord.postValue(false)
isEphemeral.postValue(chatMessage.isEphemeral)
updateEphemeralTimer()
chatMessage.addListener(chatMessageListener)
statusIcon.postValue(LinphoneUtils.getChatIconResId(chatMessage.state))
@ -813,4 +828,33 @@ class MessageModel @WorkerThread constructor(
return ""
}
@WorkerThread
private fun updateEphemeralTimer() {
if (chatMessage.isEphemeral) {
if (chatMessage.ephemeralExpireTime == 0L) {
// This means the message hasn't been read by all participants yet, so the countdown hasn't started
// In this case we simply display the configured value for lifetime
ephemeralLifetime.postValue(
TimestampUtils.formatLifetime(chatMessage.ephemeralLifetime)
)
} else {
// Countdown has started, display remaining time
val remaining = chatMessage.ephemeralExpireTime - (System.currentTimeMillis() / 1000)
ephemeralLifetime.postValue(TimestampUtils.formatLifetime(remaining))
if (!::countDownTimer.isInitialized) {
countDownTimer = object : CountDownTimer(remaining * 1000, 1000) {
override fun onFinish() {}
override fun onTick(millisUntilFinished: Long) {
ephemeralLifetime.postValue(
TimestampUtils.formatLifetime(millisUntilFinished / 1000)
)
}
}
countDownTimer.start()
}
}
}
}
}

View file

@ -27,6 +27,7 @@ import java.util.Calendar
import java.util.Date
import java.util.Locale
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
class TimestampUtils {
companion object {
@ -217,6 +218,32 @@ class TimestampUtils {
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
}
@AnyThread
fun formatLifetime(seconds: Long): String {
val days = seconds / 86400
val hours = seconds / 3600
return when {
days >= 1L -> AppUtils.getStringWithPlural(
R.plurals.days,
days.toInt(),
"$days"
)
hours >= 1L -> {
String.format(
"%02d:%02d:%02d",
seconds / 3600,
(seconds % 3600) / 60,
(seconds % 60)
)
}
else -> String.format(
"%02d:%02d",
(seconds % 3600) / 60,
(seconds % 60)
)
}
}
@AnyThread
private fun isSameDay(
cal1: Calendar,

View file

@ -247,6 +247,29 @@
android:visibility="@{model.isFromGroup ? View.VISIBLE : View.GONE}"
app:tint="?attr/color_main1_500" />
<ImageView
style="@style/default_text_style_300"
android:id="@+id/countdown_clock"
android:layout_width="@dimen/small_icon_size"
android:layout_height="@dimen/small_icon_size"
android:layout_marginStart="5dp"
android:layout_marginTop="2dp"
android:contentDescription="@null"
android:src="@drawable/clock_countdown"
app:tint="?attr/color_main2_600"
android:visibility="@{model.isEphemeral ? View.VISIBLE : View.GONE, default=gone}" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_300"
android:id="@+id/ephemeral_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:textAlignment="textEnd"
android:text="@{model.ephemeralLifetime, default=`00:00`}"
android:textSize="12sp"
android:visibility="@{model.isEphemeral ? View.VISIBLE : View.GONE, default=gone}"/>
</LinearLayout>
</LinearLayout>

View file

@ -198,6 +198,28 @@
android:gravity="center_vertical"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_300"
android:id="@+id/ephemeral_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{model.ephemeralLifetime, default=`00:00`}"
android:textSize="12sp"
android:visibility="@{model.isEphemeral ? View.VISIBLE : View.GONE, default=gone}"/>
<ImageView
style="@style/default_text_style_300"
android:id="@+id/countdown_clock"
android:layout_width="@dimen/small_icon_size"
android:layout_height="@dimen/small_icon_size"
android:layout_gravity="center_vertical|start"
android:layout_marginStart="2dp"
android:layout_marginTop="2dp"
android:contentDescription="@null"
android:src="@drawable/clock_countdown"
app:tint="?attr/color_main2_600"
android:visibility="@{model.isEphemeral ? View.VISIBLE : View.GONE, default=gone}" />
<androidx.appcompat.widget.AppCompatTextView
style="@style/default_text_style_300"
android:id="@+id/date_time"
@ -205,6 +227,7 @@
android:onLongClick="@{onLongClickListener}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@{model.time, default=`13:40`}"
android:textSize="12sp" />

View file

@ -18,6 +18,10 @@
<string name="start">Commencer</string>
<string name="today">Aujourd\'hui</string>
<string name="yesterday">Hier</string>
<plurals name="days" tools:ignore="MissingQuantity">
<item quantity="one">%s jour</item>
<item quantity="other">%s jours</item>
</plurals>
<plurals name="selection_count_label" tools:ignore="MissingQuantity">
<item quantity="one">%s selectionné</item>

View file

@ -53,6 +53,10 @@
<string name="start">Start</string>
<string name="today">Today</string>
<string name="yesterday">Yesterday</string>
<plurals name="days">
<item quantity="one">%s day</item>
<item quantity="other">%s days</item>
</plurals>
<plurals name="selection_count_label">
<item quantity="one">%s selected</item>