From fdafcfd7a45b76e5424b54d5a13c8f0e5274796b Mon Sep 17 00:00:00 2001 From: Sylvain Berfini Date: Wed, 24 Apr 2024 14:33:40 +0200 Subject: [PATCH] Added dialog to confirm removing a participant from conference --- .../ConferenceParticipantsListFragment.kt | 36 ++++++ .../model/ConferenceParticipantModel.kt | 8 +- .../viewmodel/ConferenceViewModel.kt | 42 ++++++- .../java/org/linphone/utils/DialogUtils.kt | 22 ++++ .../layout/dialog_kick_from_conference.xml | 103 ++++++++++++++++++ app/src/main/res/values-fr/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + 7 files changed, 209 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/layout/dialog_kick_from_conference.xml diff --git a/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceParticipantsListFragment.kt b/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceParticipantsListFragment.kt index 1b59ed6b7..93595ee47 100644 --- a/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceParticipantsListFragment.kt +++ b/app/src/main/java/org/linphone/ui/call/conference/fragment/ConferenceParticipantsListFragment.kt @@ -29,11 +29,14 @@ import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import org.linphone.R +import org.linphone.core.Participant import org.linphone.core.tools.Log import org.linphone.databinding.CallConferenceParticipantsListFragmentBinding import org.linphone.ui.call.adapter.ConferenceParticipantsListAdapter import org.linphone.ui.call.fragment.GenericCallFragment import org.linphone.ui.call.viewmodel.CurrentCallViewModel +import org.linphone.ui.main.history.model.ConfirmationDialogModel +import org.linphone.utils.DialogUtils class ConferenceParticipantsListFragment : GenericCallFragment() { companion object { @@ -102,5 +105,38 @@ class ConferenceParticipantsListFragment : GenericCallFragment() { Log.i("$TAG participants list updated with [${it.size}] items") adapter.submitList(it) } + + viewModel.conferenceModel.removeParticipantEvent.observe(viewLifecycleOwner) { + it.consume { pair -> + val displayName = pair.first + val participant = pair.second + showKickParticipantDialog(displayName, participant) + } + } + } + + private fun showKickParticipantDialog(displayName: String, participant: Participant) { + val model = ConfirmationDialogModel() + val dialog = DialogUtils.getKickConferenceParticipantConfirmationDialog( + requireActivity(), + model, + displayName + ) + + model.dismissEvent.observe(viewLifecycleOwner) { + it.consume { + dialog.dismiss() + } + } + + model.confirmEvent.observe(viewLifecycleOwner) { + it.consume { + viewModel.conferenceModel.kickParticipant(participant) + // TODO: notify participant was kicked out + dialog.dismiss() + } + } + + dialog.show() } } diff --git a/app/src/main/java/org/linphone/ui/call/conference/model/ConferenceParticipantModel.kt b/app/src/main/java/org/linphone/ui/call/conference/model/ConferenceParticipantModel.kt index e5b311f9f..bad5f8f48 100644 --- a/app/src/main/java/org/linphone/ui/call/conference/model/ConferenceParticipantModel.kt +++ b/app/src/main/java/org/linphone/ui/call/conference/model/ConferenceParticipantModel.kt @@ -25,10 +25,12 @@ import androidx.lifecycle.MutableLiveData import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.core.Participant import org.linphone.core.tools.Log +import org.linphone.ui.main.contacts.model.ContactAvatarModel class ConferenceParticipantModel @WorkerThread constructor( val participant: Participant, - val isMyselfAdmin: Boolean, + val avatarModel: ContactAvatarModel, + isMyselfAdmin: Boolean, val isMyself: Boolean, private val removeFromConference: ((participant: Participant) -> Unit)?, private val changeAdminStatus: ((participant: Participant, setAdmin: Boolean) -> Unit)? @@ -39,10 +41,6 @@ class ConferenceParticipantModel @WorkerThread constructor( val sipUri = participant.address.asStringUriOnly() - val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( - participant.address - ) - val isAdmin = MutableLiveData() val isMeAdmin = MutableLiveData() diff --git a/app/src/main/java/org/linphone/ui/call/conference/viewmodel/ConferenceViewModel.kt b/app/src/main/java/org/linphone/ui/call/conference/viewmodel/ConferenceViewModel.kt index 332e94e7d..23d3b4aa5 100644 --- a/app/src/main/java/org/linphone/ui/call/conference/viewmodel/ConferenceViewModel.kt +++ b/app/src/main/java/org/linphone/ui/call/conference/viewmodel/ConferenceViewModel.kt @@ -76,6 +76,10 @@ class ConferenceViewModel { MutableLiveData>() } + val removeParticipantEvent: MutableLiveData>> by lazy { + MutableLiveData>>() + } + private lateinit var conference: Conference private val conferenceListener = object : ConferenceListenerStub() { @@ -311,6 +315,16 @@ class ConferenceViewModel { } } + @WorkerThread + fun kickParticipant(participant: Participant) { + coreContext.postOnCoreThread { + Log.i( + "$TAG Kicking participant [${participant.address.asStringUriOnly()}] out of conference" + ) + conference.removeParticipant(participant) + } + } + @WorkerThread fun setNewLayout(newLayout: Int) { val call = conference.call @@ -408,12 +422,18 @@ class ConferenceViewModel { Log.i( "$TAG Participant [${participant.address.asStringUriOnly()}] has [${devices.size}] devices and role [${role.name}]" ) + val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( + participant.address + ) val participantModel = ConferenceParticipantModel( participant, + avatarModel, admin, false, { participant -> // Remove from conference - conference.removeParticipant(participant) + removeParticipantEvent.postValue( + Event(Pair(avatarModel.name.value.orEmpty(), participant)) + ) }, { participant, setAdmin -> // Change admin status conference.setParticipantAdminStatus(participant, setAdmin) @@ -443,7 +463,17 @@ class ConferenceViewModel { "$TAG [${devicesList.size}] participant devices for [${participantsList.size}] participants will be displayed (not counting ourselves)" ) - val meParticipantModel = ConferenceParticipantModel(meParticipant, admin, true, null, null) + val meAvatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( + meParticipant.address + ) + val meParticipantModel = ConferenceParticipantModel( + meParticipant, + meAvatarModel, + admin, + true, + null, + null + ) participantsList.add(meParticipantModel) val ourDevices = conference.me.devices @@ -558,12 +588,18 @@ class ConferenceViewModel { val list = arrayListOf() list.addAll(participants.value.orEmpty()) + val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress( + participant.address + ) val newModel = ConferenceParticipantModel( participant, + avatarModel, isMeAdmin.value == true, false, { participant -> // Remove from conference - conference.removeParticipant(participant) + removeParticipantEvent.postValue( + Event(Pair(avatarModel.name.value.orEmpty(), participant)) + ) }, { participant, setAdmin -> // Change admin status conference.setParticipantAdminStatus(participant, setAdmin) diff --git a/app/src/main/java/org/linphone/utils/DialogUtils.kt b/app/src/main/java/org/linphone/utils/DialogUtils.kt index ccbb601da..ea8dd9b88 100644 --- a/app/src/main/java/org/linphone/utils/DialogUtils.kt +++ b/app/src/main/java/org/linphone/utils/DialogUtils.kt @@ -41,6 +41,7 @@ import org.linphone.databinding.DialogConfirmZrtpSasBinding import org.linphone.databinding.DialogContactConfirmTrustCallBinding import org.linphone.databinding.DialogContactTrustProcessBinding import org.linphone.databinding.DialogDeleteContactBinding +import org.linphone.databinding.DialogKickFromConferenceBinding import org.linphone.databinding.DialogManageAccountInternationalPrefixHelpBinding import org.linphone.databinding.DialogMergeCallsIntoConferenceBinding import org.linphone.databinding.DialogPickNumberOrAddressBinding @@ -355,6 +356,27 @@ class DialogUtils { return getDialog(context, binding) } + @UiThread + fun getKickConferenceParticipantConfirmationDialog( + context: Context, + viewModel: ConfirmationDialogModel, + displayName: String + ): Dialog { + val binding: DialogKickFromConferenceBinding = DataBindingUtil.inflate( + LayoutInflater.from(context), + R.layout.dialog_kick_from_conference, + null, + false + ) + binding.viewModel = viewModel + binding.title.text = context.getString( + R.string.conference_confirm_removing_participant_dialog_title, + displayName + ) + + return getDialog(context, binding) + } + @UiThread fun getCancelMeetingDialog( context: Context, diff --git a/app/src/main/res/layout/dialog_kick_from_conference.xml b/app/src/main/res/layout/dialog_kick_from_conference.xml new file mode 100644 index 000000000..352ac071f --- /dev/null +++ b/app/src/main/res/layout/dialog_kick_from_conference.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6981a2d94..340a5500b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -38,6 +38,7 @@ Ne plus me montrer ce message Non Oui + Retirer &appName; notifications d\'appels en cours @@ -585,6 +586,8 @@ %s participant %s participants + Retirer %s de la conférence ? + Voulez-vous vraiment retirer ce participant de la conférence ? En train de rejoindre… En pause partage son écran diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d51b6b870..8632faa94 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -73,6 +73,7 @@ Do not show this dialog anymore No Yes + Remove &appName; active calls notifications @@ -621,6 +622,8 @@ %s participant %s participants + Remove %s from conference? + Are you sure you want to remove this participant from the conference? Joining… Paused is sharing it\'s screen