From bd38c7dc49b95ffe6d366e1fad4db4a48a40e580 Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Fri, 17 Nov 2023 23:05:20 +0100 Subject: [PATCH] Added ephemeral messages to conversation info --- .../chat/fragment/ConversationInfoFragment.kt | 35 +++ ...onConfigureEphemeralDurationDialogModel.kt | 42 ++++ .../linphone/ui/main/chat/model/EventModel.kt | 38 +++ .../viewmodel/ConversationInfoViewModel.kt | 17 ++ .../java/org/linphone/utils/DialogUtils.kt | 20 +- .../java/org/linphone/utils/TimestampUtils.kt | 7 - .../main/res/layout/chat_info_fragment.xml | 81 +++++- ...figure_conversation_ephemeral_messages.xml | 233 ++++++++++++++++++ app/src/main/res/values/strings.xml | 12 + 9 files changed, 471 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/org/linphone/ui/main/chat/model/ConversationConfigureEphemeralDurationDialogModel.kt create mode 100644 app/src/main/res/layout/dialog_configure_conversation_ephemeral_messages.xml diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt index a37cedb42..39829fc12 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt @@ -37,6 +37,7 @@ import org.linphone.core.tools.Log import org.linphone.databinding.ChatInfoFragmentBinding import org.linphone.databinding.ChatParticipantAdminPopupMenuBinding import org.linphone.ui.main.chat.adapter.ConversationParticipantsAdapter +import org.linphone.ui.main.chat.model.ConversationConfigureEphemeralDurationDialogModel import org.linphone.ui.main.chat.model.ConversationEditSubjectDialogModel import org.linphone.ui.main.chat.model.ParticipantModel import org.linphone.ui.main.chat.viewmodel.ConversationInfoViewModel @@ -193,6 +194,40 @@ class ConversationInfoFragment : GenericFragment() { Log.i("$TAG Showing dialog to edit conversation subject") dialog.show() } + + binding.setConfigureEphemeralMessagesClickListener { + val currentValue = viewModel.ephemeralLifetime.value ?: 0 + val model = ConversationConfigureEphemeralDurationDialogModel(currentValue) + + val dialog = DialogUtils.getConfigureChatMessagesEphemeralDurationDialog( + requireContext(), + model + ) + + model.dismissEvent.observe(viewLifecycleOwner) { + it.consume { + Log.i("$TAG Ephemeral lifetime value wasn't changed") + dialog.dismiss() + } + } + + model.newValueSelectedEvent.observe(viewLifecycleOwner) { + it.consume { duration -> + if (duration != currentValue) { + Log.i( + "$TAG Conversation chat message lifetime updated to [$duration] (previous one was [$currentValue])" + ) + viewModel.updateEphemeralLifetime(duration) + } + dialog.dismiss() + } + } + + Log.i( + "$TAG Showing dialog to change chat messages ephemeral duration (currently [$currentValue])" + ) + dialog.show() + } } private fun showParticipantAdminPopupMenu(view: View, participantModel: ParticipantModel) { diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationConfigureEphemeralDurationDialogModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationConfigureEphemeralDurationDialogModel.kt new file mode 100644 index 000000000..d4f34a054 --- /dev/null +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationConfigureEphemeralDurationDialogModel.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2010-2023 Belledonne Communications SARL. + * + * This file is part of linphone-android + * (see https://www.linphone.org). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.linphone.ui.main.chat.model + +import androidx.annotation.UiThread +import androidx.lifecycle.MutableLiveData +import org.linphone.utils.Event + +class ConversationConfigureEphemeralDurationDialogModel @UiThread constructor( + val currentlySelectedValue: Int +) { + val dismissEvent = MutableLiveData>() + + val newValueSelectedEvent = MutableLiveData>() + + @UiThread + fun dismiss() { + dismissEvent.value = Event(true) + } + + @UiThread + fun onValueSelected(value: Int) { + newValueSelectedEvent.value = Event(value) + } +} diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/EventModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/EventModel.kt index 49282e817..f3a1f325f 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/EventModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/EventModel.kt @@ -20,6 +20,7 @@ package org.linphone.ui.main.chat.model import androidx.annotation.WorkerThread +import java.util.Locale import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.R import org.linphone.core.EventLog @@ -64,6 +65,18 @@ class EventModel @WorkerThread constructor(private val eventLog: EventLog) { R.string.conversation_event_device_removed, getName() ) + EventLog.Type.ConferenceEphemeralMessageEnabled -> AppUtils.getString( + R.string.conversation_event_ephemeral_messages_enabled + ) + EventLog.Type.ConferenceEphemeralMessageDisabled -> AppUtils.getString( + R.string.conversation_event_ephemeral_messages_disabled + ) + EventLog.Type.ConferenceEphemeralMessageLifetimeChanged -> AppUtils.getFormattedString( + R.string.conversation_event_ephemeral_messages_lifetime_changed, + formatEphemeralExpiration(eventLog.ephemeralMessageLifetime).lowercase( + Locale.getDefault() + ) + ) else -> { eventLog.type.name } @@ -80,4 +93,29 @@ class EventModel @WorkerThread constructor(private val eventLog: EventLog) { } return name } + + @WorkerThread + private fun formatEphemeralExpiration(duration: Long): String { + return when (duration) { + 0L -> AppUtils.getString( + R.string.dialog_conversation_message_ephemeral_duration_disabled + ) + 60L -> AppUtils.getString( + R.string.dialog_conversation_message_ephemeral_duration_one_minute + ) + 3600L -> AppUtils.getString( + R.string.dialog_conversation_message_ephemeral_duration_one_hour + ) + 86400L -> AppUtils.getString( + R.string.dialog_conversation_message_ephemeral_duration_one_day + ) + 259200L -> AppUtils.getString( + R.string.dialog_conversation_message_ephemeral_duration_three_days + ) + 604800L -> AppUtils.getString( + R.string.dialog_conversation_message_ephemeral_duration_one_week + ) + else -> "$duration s" + } + } } diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt index 0fb73772d..f558baddd 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt @@ -50,12 +50,16 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() { val subject = MutableLiveData() + val sipUri = MutableLiveData() + val isReadOnly = MutableLiveData() val isMyselfAdmin = MutableLiveData() val isMuted = MutableLiveData() + val ephemeralLifetime = MutableLiveData() + val expandParticipants = MutableLiveData() val chatRoomFoundEvent = MutableLiveData>() @@ -324,6 +328,16 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() { } } + @UiThread + fun updateEphemeralLifetime(lifetime: Int) { + coreContext.postOnCoreThread { + Log.i("$TAG Updating chat messages ephemeral lifetime to [$lifetime]") + chatRoom.ephemeralLifetime = lifetime.toLong() + chatRoom.isEphemeralEnabled = lifetime != 0 + ephemeralLifetime.postValue(chatRoom.ephemeralLifetime.toInt()) + } + } + @WorkerThread private fun configureChatRoom() { isMuted.postValue(chatRoom.muted) @@ -341,6 +355,9 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() { } subject.postValue(chatRoom.subject) + sipUri.postValue(chatRoom.participants.firstOrNull()?.address?.asStringUriOnly()) + + ephemeralLifetime.postValue(chatRoom.ephemeralLifetime.toInt()) computeParticipantsList() } diff --git a/app/src/main/java/org/linphone/utils/DialogUtils.kt b/app/src/main/java/org/linphone/utils/DialogUtils.kt index 6fa38244e..f8a5e36fc 100644 --- a/app/src/main/java/org/linphone/utils/DialogUtils.kt +++ b/app/src/main/java/org/linphone/utils/DialogUtils.kt @@ -35,6 +35,7 @@ import org.linphone.databinding.DialogAccountModesExplanationBinding import org.linphone.databinding.DialogAssistantAcceptConditionsAndPolicyBinding import org.linphone.databinding.DialogAssistantCreateAccountConfirmPhoneNumberBinding import org.linphone.databinding.DialogCancelContactChangesBinding +import org.linphone.databinding.DialogConfigureConversationEphemeralMessagesBinding import org.linphone.databinding.DialogConfirmZrtpSasBinding import org.linphone.databinding.DialogContactConfirmTrustCallBinding import org.linphone.databinding.DialogContactTrustProcessBinding @@ -49,6 +50,7 @@ import org.linphone.databinding.DialogUpdateAvailableBinding import org.linphone.ui.assistant.model.AcceptConditionsAndPolicyDialogModel import org.linphone.ui.assistant.model.ConfirmPhoneNumberDialogModel import org.linphone.ui.call.model.ZrtpSasConfirmationDialogModel +import org.linphone.ui.main.chat.model.ConversationConfigureEphemeralDurationDialogModel import org.linphone.ui.main.chat.model.ConversationEditSubjectDialogModel import org.linphone.ui.main.contacts.model.NumberOrAddressPickerDialogModel import org.linphone.ui.main.contacts.model.TrustCallDialogModel @@ -283,6 +285,22 @@ class DialogUtils { return getDialog(context, binding) } + @UiThread + fun getConfigureChatMessagesEphemeralDurationDialog( + context: Context, + viewModel: ConversationConfigureEphemeralDurationDialogModel + ): Dialog { + val binding: DialogConfigureConversationEphemeralMessagesBinding = DataBindingUtil.inflate( + LayoutInflater.from(context), + R.layout.dialog_configure_conversation_ephemeral_messages, + null, + false + ) + binding.viewModel = viewModel + + return getDialog(context, binding) + } + @UiThread fun getUpdateAvailableDialog( context: Context, @@ -329,7 +347,7 @@ class DialogUtils { WindowManager.LayoutParams.MATCH_PARENT ) val d: Drawable = ColorDrawable( - AppUtils.getColor(R.color.gray_300) + AppUtils.getColor(R.color.gray_main2_800) ) d.alpha = 102 dialog.window?.setBackgroundDrawable(d) diff --git a/app/src/main/java/org/linphone/utils/TimestampUtils.kt b/app/src/main/java/org/linphone/utils/TimestampUtils.kt index 3f4ed28c8..5604fb781 100644 --- a/app/src/main/java/org/linphone/utils/TimestampUtils.kt +++ b/app/src/main/java/org/linphone/utils/TimestampUtils.kt @@ -145,13 +145,6 @@ class TimestampUtils { return dateFormat.format(cal.time) } - @AnyThread - private fun isSameYear(timestamp: Long, timestampInSecs: Boolean = true): Boolean { - val cal = Calendar.getInstance() - cal.timeInMillis = if (timestampInSecs) timestamp * 1000 else timestamp - return isSameYear(cal, Calendar.getInstance()) - } - @AnyThread fun toString( timestamp: Long, diff --git a/app/src/main/res/layout/chat_info_fragment.xml b/app/src/main/res/layout/chat_info_fragment.xml index 474f1201f..843dfb963 100644 --- a/app/src/main/res/layout/chat_info_fragment.xml +++ b/app/src/main/res/layout/chat_info_fragment.xml @@ -18,6 +18,9 @@ + @@ -80,6 +83,18 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> + + + + + + + app:layout_constraintTop_toBottomOf="@id/status" /> + app:layout_constraintTop_toBottomOf="@id/status" /> + app:layout_constraintTop_toBottomOf="@id/status" /> + + + + diff --git a/app/src/main/res/layout/dialog_configure_conversation_ephemeral_messages.xml b/app/src/main/res/layout/dialog_configure_conversation_ephemeral_messages.xml new file mode 100644 index 000000000..ec531eb21 --- /dev/null +++ b/app/src/main/res/layout/dialog_configure_conversation_ephemeral_messages.xml @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb9f504b2..130f16842 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -116,6 +116,14 @@ Blah blah blah Edit conversation subject Confirm + Enable ephemeral messages + New messages will be automatically deleted once read by everyone.\nChoose a duration: + Disabled + 1 minute + 1 hour + 1 day + 3 days + 1 week Invalid QR code! SIP address copied into clipboard @@ -350,6 +358,7 @@ Call Delete conversation Leave the group + Configure ephemeral messages New conversation Search contact Create a group conversation @@ -383,6 +392,9 @@ new subject: %s %s is admin %s is no longer admin + Ephemeral messages have been enabled + Ephemeral messages have been disabled + Ephemeral lifetime is now %s Read %s Received %s