mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Added chat room participant admin popup to remove a person from a group & give/remove admin rights
This commit is contained in:
parent
1c7b97d8db
commit
f07a8f6c2b
9 changed files with 269 additions and 15 deletions
|
|
@ -20,16 +20,22 @@
|
|||
package org.linphone.ui.main.chat.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.PopupWindow
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.core.view.doOnPreDraw
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import org.linphone.R
|
||||
import org.linphone.core.tools.Log
|
||||
import org.linphone.databinding.ChatInfoFragmentBinding
|
||||
import org.linphone.databinding.ChatParticipantAdminPopupMenuBinding
|
||||
import org.linphone.ui.main.chat.model.ParticipantModel
|
||||
import org.linphone.ui.main.chat.viewmodel.ConversationInfoViewModel
|
||||
import org.linphone.ui.main.fragment.GenericFragment
|
||||
|
||||
|
|
@ -111,8 +117,56 @@ class ConversationInfoFragment : GenericFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
viewModel.showParticipantAdminPopupMenuEvent.observe(viewLifecycleOwner) {
|
||||
it.consume { pair ->
|
||||
showParticipantAdminPopupMenu(pair.first, pair.second)
|
||||
}
|
||||
}
|
||||
|
||||
binding.setBackClickListener {
|
||||
goBack()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showParticipantAdminPopupMenu(view: View, participantModel: ParticipantModel) {
|
||||
val popupView: ChatParticipantAdminPopupMenuBinding = DataBindingUtil.inflate(
|
||||
LayoutInflater.from(requireContext()),
|
||||
R.layout.chat_participant_admin_popup_menu,
|
||||
null,
|
||||
false
|
||||
)
|
||||
|
||||
val popupWindow = PopupWindow(
|
||||
popupView.root,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
true
|
||||
)
|
||||
|
||||
val address = participantModel.sipUri
|
||||
val isAdmin = participantModel.isParticipantAdmin
|
||||
popupView.isParticipantAdmin = isAdmin
|
||||
|
||||
popupView.setRemoveParticipantClickListener {
|
||||
Log.w("$TAG Trying to remove participant [$address]")
|
||||
viewModel.removeParticipant(participantModel)
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
popupView.setSetAdminClickListener {
|
||||
Log.w("$TAG Trying to give admin rights to participant [$address]")
|
||||
viewModel.giveAdminRightsTo(participantModel)
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
popupView.setUnsetAdminClickListener {
|
||||
Log.w("$TAG Trying to remove admin rights from participant [$address]")
|
||||
viewModel.removeAdminRightsFrom(participantModel)
|
||||
popupWindow.dismiss()
|
||||
}
|
||||
|
||||
// Elevation is for showing a shadow around the popup
|
||||
popupWindow.elevation = 20f
|
||||
popupWindow.showAsDropDown(view, 0, 0, Gravity.BOTTOM)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,25 @@
|
|||
*/
|
||||
package org.linphone.ui.main.chat.model
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.annotation.WorkerThread
|
||||
import org.linphone.core.Address
|
||||
import org.linphone.core.Friend
|
||||
import org.linphone.ui.main.contacts.model.ContactAvatarModel
|
||||
|
||||
class ParticipantModel(friend: Friend, val isMyselfAdmin: Boolean, val isParticipantAdmin: Boolean) :
|
||||
ContactAvatarModel(friend)
|
||||
class ParticipantModel @WorkerThread constructor(
|
||||
friend: Friend,
|
||||
val address: Address,
|
||||
val isMyselfAdmin: Boolean,
|
||||
val isParticipantAdmin: Boolean,
|
||||
private val onMenuClicked: ((view: View, model: ParticipantModel) -> Unit)? = null
|
||||
) : ContactAvatarModel(friend) {
|
||||
|
||||
val sipUri = address.asStringUriOnly()
|
||||
|
||||
@UiThread
|
||||
fun openMenu(view: View) {
|
||||
onMenuClicked?.invoke(view, this)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
package org.linphone.ui.main.chat.viewmodel
|
||||
|
||||
import android.view.View
|
||||
import androidx.annotation.UiThread
|
||||
import androidx.annotation.WorkerThread
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
|
@ -59,9 +60,17 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() {
|
|||
|
||||
val chatRoomFoundEvent = MutableLiveData<Event<Boolean>>()
|
||||
|
||||
val groupLeftEvent = MutableLiveData<Event<Boolean>>()
|
||||
val groupLeftEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
|
||||
val historyDeletedEvent = MutableLiveData<Event<Boolean>>()
|
||||
val historyDeletedEvent: MutableLiveData<Event<Boolean>> by lazy {
|
||||
MutableLiveData<Event<Boolean>>()
|
||||
}
|
||||
|
||||
val showParticipantAdminPopupMenuEvent: MutableLiveData<Event<Pair<View, ParticipantModel>>> by lazy {
|
||||
MutableLiveData<Event<Pair<View, ParticipantModel>>>()
|
||||
}
|
||||
|
||||
private lateinit var chatRoom: ChatRoom
|
||||
|
||||
|
|
@ -70,21 +79,34 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() {
|
|||
private val chatRoomListener = object : ChatRoomListenerStub() {
|
||||
@WorkerThread
|
||||
override fun onParticipantAdded(chatRoom: ChatRoom, eventLog: EventLog) {
|
||||
Log.i("$TAG A participant has been added to the group [${chatRoom.subject}]")
|
||||
// TODO: show toast
|
||||
computeParticipantsList()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onParticipantRemoved(chatRoom: ChatRoom, eventLog: EventLog) {
|
||||
Log.i("$TAG A participant has been removed from the group [${chatRoom.subject}]")
|
||||
// TODO: show toast
|
||||
computeParticipantsList()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onParticipantAdminStatusChanged(chatRoom: ChatRoom, eventLog: EventLog) {
|
||||
Log.i(
|
||||
"$TAG A participant has been given/removed administration rights for group [${chatRoom.subject}]"
|
||||
)
|
||||
// TODO: show toast
|
||||
// TODO FIXME: list doesn't have the changes...
|
||||
computeParticipantsList()
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
override fun onSubjectChanged(chatRoom: ChatRoom, eventLog: EventLog) {
|
||||
Log.i(
|
||||
"$TAG Chat room [${LinphoneUtils.getChatRoomId(chatRoom)}] has a new subject [${chatRoom.subject}]"
|
||||
)
|
||||
// TODO: show toast
|
||||
subject.postValue(chatRoom.subject)
|
||||
}
|
||||
}
|
||||
|
|
@ -177,6 +199,69 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() {
|
|||
expandParticipants.value = expandParticipants.value == false
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun removeParticipant(participantModel: ParticipantModel) {
|
||||
coreContext.postOnCoreThread {
|
||||
val address = participantModel.address
|
||||
Log.i(
|
||||
"$TAG Removing participant [$address] from the conversation [${LinphoneUtils.getChatRoomId(
|
||||
chatRoom
|
||||
)}]"
|
||||
)
|
||||
val participant = chatRoom.participants.find {
|
||||
it.address.weakEqual(address)
|
||||
}
|
||||
if (participant != null) {
|
||||
chatRoom.removeParticipant(participant)
|
||||
Log.i("$TAG Participant removed")
|
||||
} else {
|
||||
Log.e("$TAG Couldn't find participant matching address [$address]!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun giveAdminRightsTo(participantModel: ParticipantModel) {
|
||||
coreContext.postOnCoreThread {
|
||||
val address = participantModel.address
|
||||
Log.i(
|
||||
"$TAG Granting admin rights to participant [$address] from the conversation [${LinphoneUtils.getChatRoomId(
|
||||
chatRoom
|
||||
)}]"
|
||||
)
|
||||
val participant = chatRoom.participants.find {
|
||||
it.address.weakEqual(address)
|
||||
}
|
||||
if (participant != null) {
|
||||
chatRoom.setParticipantAdminStatus(participant, true)
|
||||
Log.i("$TAG Participant will become admin soon")
|
||||
} else {
|
||||
Log.e("$TAG Couldn't find participant matching address [$address]!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@UiThread
|
||||
fun removeAdminRightsFrom(participantModel: ParticipantModel) {
|
||||
coreContext.postOnCoreThread {
|
||||
val address = participantModel.address
|
||||
Log.i(
|
||||
"$TAG Removing admin rights from participant [$address] from the conversation [${LinphoneUtils.getChatRoomId(
|
||||
chatRoom
|
||||
)}]"
|
||||
)
|
||||
val participant = chatRoom.participants.find {
|
||||
it.address.weakEqual(address)
|
||||
}
|
||||
if (participant != null) {
|
||||
chatRoom.setParticipantAdminStatus(participant, false)
|
||||
Log.i("$TAG Participant will be removed as admin soon")
|
||||
} else {
|
||||
Log.e("$TAG Couldn't find participant matching address [$address]!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun configureChatRoom() {
|
||||
isMuted.postValue(chatRoom.muted)
|
||||
|
|
@ -235,12 +320,9 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() {
|
|||
}
|
||||
|
||||
@WorkerThread
|
||||
private fun getParticipantModelForAddress(address: Address?, isAdmin: Boolean): ParticipantModel {
|
||||
private fun getParticipantModelForAddress(address: Address, isAdmin: Boolean): ParticipantModel {
|
||||
Log.i("$TAG Looking for participant model with address [${address?.asStringUriOnly()}]")
|
||||
if (address == null) {
|
||||
val fakeFriend = coreContext.core.createFriend()
|
||||
return ParticipantModel(fakeFriend, isMyselfAdmin.value == true, false)
|
||||
}
|
||||
val selfAdmin = chatRoom.me?.isAdmin == true
|
||||
|
||||
val clone = address.clone()
|
||||
clone.clean()
|
||||
|
|
@ -251,11 +333,17 @@ class ConversationInfoViewModel @UiThread constructor() : ViewModel() {
|
|||
|
||||
val friend = coreContext.contactsManager.findContactByAddress(clone)
|
||||
val avatar = if (friend != null) {
|
||||
ParticipantModel(friend, isMyselfAdmin.value == true, isAdmin)
|
||||
ParticipantModel(friend, clone, selfAdmin, isAdmin) { view, model ->
|
||||
// openMenu
|
||||
showParticipantAdminPopupMenuEvent.postValue(Event(Pair(view, model)))
|
||||
}
|
||||
} else {
|
||||
val fakeFriend = coreContext.core.createFriend()
|
||||
fakeFriend.address = clone
|
||||
ParticipantModel(fakeFriend, isMyselfAdmin.value == true, isAdmin)
|
||||
ParticipantModel(fakeFriend, clone, selfAdmin, isAdmin) { view, model ->
|
||||
// openMenu
|
||||
showParticipantAdminPopupMenuEvent.postValue(Event(Pair(view, model)))
|
||||
}
|
||||
}
|
||||
|
||||
avatarsMap[key] = avatar
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@
|
|||
android:background="@drawable/shape_round_popup_menu_background">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:onClick="@{manageProfileClickListener}"
|
||||
style="@style/default_text_style"
|
||||
android:id="@+id/manage_profile"
|
||||
android:onClick="@{manageProfileClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="20dp"
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@
|
|||
android:ellipsize="end"
|
||||
android:drawableStart="@drawable/plus_circle"
|
||||
android:drawablePadding="8dp"
|
||||
android:visibility="@{!viewModel.expandParticipants || !viewModel.isMyselfAdmin || viewModel.isGroup || viewModel.isReadOnly ? View.GONE : View.VISIBLE}"
|
||||
android:visibility="@{!viewModel.expandParticipants || !viewModel.isMyselfAdmin || !viewModel.isGroup || viewModel.isReadOnly ? View.GONE : View.VISIBLE}"
|
||||
app:drawableTint="@color/orange_main_500"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
@ -234,7 +234,7 @@
|
|||
android:id="@+id/participants_anchor"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="16dp"
|
||||
android:visibility="@{!viewModel.expandParticipants || !viewModel.isMyselfAdmin || viewModel.isGroup || viewModel.isReadOnly ? View.GONE : View.VISIBLE}"
|
||||
android:visibility="@{!viewModel.expandParticipants || !viewModel.isMyselfAdmin || !viewModel.isGroup || viewModel.isReadOnly ? View.GONE : View.VISIBLE}"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_participants"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<data>
|
||||
<import type="android.view.View" />
|
||||
<import type="android.graphics.Typeface" />
|
||||
<variable
|
||||
name="removeParticipantClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="setAdminClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="unsetAdminClickListener"
|
||||
type="View.OnClickListener" />
|
||||
<variable
|
||||
name="isParticipantAdmin"
|
||||
type="Boolean" />
|
||||
</data>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/shape_round_popup_menu_background">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style"
|
||||
android:id="@+id/remove_participant"
|
||||
android:onClick="@{removeParticipantClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="20dp"
|
||||
android:text="@string/conversation_info_admin_menu_remove_participant"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/red_danger_500"
|
||||
android:drawableStart="@drawable/trash_simple"
|
||||
android:drawablePadding="5dp"
|
||||
app:drawableTint="@color/red_danger_500"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/set_admin"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style"
|
||||
android:id="@+id/set_admin"
|
||||
android:onClick="@{setAdminClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="20dp"
|
||||
android:visibility="@{isParticipantAdmin ? View.GONE : View.VISIBLE}"
|
||||
android:text="@string/conversation_info_admin_menu_set_participant_admin"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/gray_main2_500"
|
||||
android:drawableStart="@drawable/trash_simple"
|
||||
android:drawablePadding="5dp"
|
||||
app:drawableTint="@color/gray_main2_700"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/remove_participant"
|
||||
app:layout_constraintBottom_toTopOf="@id/unset_admin"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
style="@style/default_text_style"
|
||||
android:id="@+id/unset_admin"
|
||||
android:onClick="@{unsetAdminClickListener}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:paddingEnd="20dp"
|
||||
android:paddingStart="20dp"
|
||||
android:visibility="@{isParticipantAdmin ? View.VISIBLE : View.GONE, default=gone}"
|
||||
android:text="@string/conversation_info_admin_menu_unset_participant_admin"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@color/gray_main2_500"
|
||||
android:drawableStart="@drawable/trash_simple"
|
||||
android:drawablePadding="5dp"
|
||||
app:drawableTint="@color/gray_main2_700"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/set_admin"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</layout>
|
||||
|
|
@ -81,6 +81,7 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/participant_menu"
|
||||
android:onClick="@{() -> model.openMenu(participantMenu)}"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:src="@drawable/dots_three_vertical"
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@
|
|||
android:id="@+id/required_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/required"
|
||||
android:textSize="12sp"
|
||||
|
|
|
|||
|
|
@ -354,6 +354,9 @@
|
|||
<string name="conversation_info_add_participants_label">Add participants</string>
|
||||
<string name="conversation_info_participant_is_admin_label">Admin</string>
|
||||
<string name="conversation_info_delete_history_action">Delete history</string>
|
||||
<string name="conversation_info_admin_menu_remove_participant">Remove from the group</string>
|
||||
<string name="conversation_info_admin_menu_set_participant_admin">Give admin rights</string>
|
||||
<string name="conversation_info_admin_menu_unset_participant_admin">Remove admin rights</string>
|
||||
|
||||
<string name="meetings_list_empty">No meeting for the moment…</string>
|
||||
<string name="meeting_schedule_title">New meeting</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue