mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-02 08:23:00 +01:00
Add ability to set group member label from conversation settings.
This commit is contained in:
committed by
Cody Henthorne
parent
415dbd1b61
commit
7d1897a9d2
@@ -739,7 +739,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
|
||||
customPref(
|
||||
RecipientPreference.Model(
|
||||
recipient = group,
|
||||
onClick = {
|
||||
onRowClick = {
|
||||
CommunicationActions.startConversation(requireActivity(), group, null)
|
||||
requireActivity().finish()
|
||||
}
|
||||
@@ -787,13 +787,26 @@ class ConversationSettingsFragment : DSLSettingsFragment(
|
||||
)
|
||||
|
||||
for (member in groupState.members) {
|
||||
val canSetMemberLabel = member.member.isSelf && groupState.canSetOwnMemberLabel
|
||||
val memberLabel = member.getMemberLabel(groupState)
|
||||
|
||||
customPref(
|
||||
RecipientPreference.Model(
|
||||
recipient = member.member,
|
||||
isAdmin = member.isAdmin,
|
||||
memberLabel = member.getMemberLabel(groupState),
|
||||
memberLabel = memberLabel,
|
||||
canSetMemberLabel = canSetMemberLabel,
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
onClick = {
|
||||
onRowClick = {
|
||||
if (canSetMemberLabel && memberLabel == null) {
|
||||
val action = ConversationSettingsFragmentDirections
|
||||
.actionConversationSettingsFragmentToMemberLabelFragment(groupState.groupId)
|
||||
navController.safeNavigate(action)
|
||||
} else {
|
||||
RecipientBottomSheetDialogFragment.show(parentFragmentManager, member.member.id, groupState.groupId)
|
||||
}
|
||||
},
|
||||
onAvatarClick = {
|
||||
RecipientBottomSheetDialogFragment.show(parentFragmentManager, member.member.id, groupState.groupId)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -84,7 +84,8 @@ sealed class SpecificSettingsState {
|
||||
val membershipCountDescription: String = "",
|
||||
val legacyGroupState: LegacyGroupPreference.State = LegacyGroupPreference.State.NONE,
|
||||
val isAnnouncementGroup: Boolean = false,
|
||||
val memberLabelsByRecipientId: Map<RecipientId, MemberLabel> = emptyMap()
|
||||
val memberLabelsByRecipientId: Map<RecipientId, MemberLabel> = emptyMap(),
|
||||
val canSetOwnMemberLabel: Boolean = false
|
||||
) : SpecificSettingsState() {
|
||||
|
||||
override val isLoaded: Boolean = groupTitleLoaded && groupDescriptionLoaded
|
||||
|
||||
@@ -362,6 +362,7 @@ sealed class ConversationSettingsViewModel(
|
||||
|
||||
if (groupId.isV2) {
|
||||
loadMemberLabels(groupId.requireV2(), fullMembers)
|
||||
loadCanSetMemberLabel(groupId.requireV2())
|
||||
}
|
||||
|
||||
state.copy(
|
||||
@@ -520,6 +521,17 @@ sealed class ConversationSettingsViewModel(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadCanSetMemberLabel(v2GroupId: GroupId.V2) = viewModelScope.launch(SignalDispatchers.IO) {
|
||||
val canSetLabel = MemberLabelRepository.instance.canSetLabel(v2GroupId, Recipient.self())
|
||||
store.update {
|
||||
it.copy(
|
||||
specificSettingsState = it.requireGroupSettingsState().copy(
|
||||
canSetOwnMemberLabel = canSetLabel
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(
|
||||
|
||||
@@ -36,8 +36,10 @@ object RecipientPreference {
|
||||
val recipient: Recipient,
|
||||
val isAdmin: Boolean = false,
|
||||
val memberLabel: StyledMemberLabel? = null,
|
||||
val canSetMemberLabel: Boolean = false,
|
||||
val lifecycleOwner: LifecycleOwner? = null,
|
||||
val onClick: (() -> Unit)? = null
|
||||
val onRowClick: (() -> Unit)? = null,
|
||||
val onAvatarClick: (() -> Unit)? = null
|
||||
) : PreferenceModel<Model>() {
|
||||
override fun areItemsTheSame(newItem: Model): Boolean {
|
||||
return recipient.id == newItem.recipient.id
|
||||
@@ -47,7 +49,8 @@ object RecipientPreference {
|
||||
return super.areContentsTheSame(newItem) &&
|
||||
recipient.hasSameContent(newItem.recipient) &&
|
||||
isAdmin == newItem.isAdmin &&
|
||||
memberLabel == newItem.memberLabel
|
||||
memberLabel == newItem.memberLabel &&
|
||||
canSetMemberLabel == newItem.canSetMemberLabel
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,28 +59,36 @@ object RecipientPreference {
|
||||
private val name: TextView = itemView.findViewById(R.id.recipient_name)
|
||||
private val about: TextView? = itemView.findViewById(R.id.recipient_about)
|
||||
private val memberLabelView: MemberLabelPillView? = itemView.findViewById(R.id.recipient_member_label)
|
||||
private val addMemberLabelView: TextView? = itemView.findViewById(R.id.add_member_label)
|
||||
private val admin: View? = itemView.findViewById(R.id.admin)
|
||||
private val badge: BadgeImageView = itemView.findViewById(R.id.recipient_badge)
|
||||
|
||||
private var recipient: Recipient? = null
|
||||
private var canSetMemberLabel: Boolean = false
|
||||
|
||||
private val recipientObserver = Observer<Recipient> { recipient ->
|
||||
onRecipientChanged(recipient)
|
||||
onRecipientChanged(recipient = recipient, memberLabel = null, canSetMemberLabel = canSetMemberLabel)
|
||||
}
|
||||
|
||||
override fun bind(model: Model) {
|
||||
if (model.onClick != null) {
|
||||
itemView.setOnClickListener { model.onClick.invoke() }
|
||||
if (model.onRowClick != null) {
|
||||
itemView.setOnClickListener { model.onRowClick.invoke() }
|
||||
} else {
|
||||
itemView.setOnClickListener(null)
|
||||
}
|
||||
|
||||
if (model.onAvatarClick != null) {
|
||||
avatar.setOnClickListener { model.onAvatarClick.invoke() }
|
||||
} else {
|
||||
avatar.setOnClickListener(null)
|
||||
}
|
||||
|
||||
canSetMemberLabel = model.canSetMemberLabel
|
||||
|
||||
if (model.lifecycleOwner != null) {
|
||||
observeRecipient(model.lifecycleOwner, model.recipient)
|
||||
model.memberLabel?.let(::showMemberLabel)
|
||||
} else {
|
||||
onRecipientChanged(model.recipient, model.memberLabel)
|
||||
}
|
||||
onRecipientChanged(model.recipient, model.memberLabel, model.canSetMemberLabel)
|
||||
|
||||
admin?.visible = model.isAdmin
|
||||
}
|
||||
@@ -86,7 +97,7 @@ object RecipientPreference {
|
||||
unbind()
|
||||
}
|
||||
|
||||
private fun onRecipientChanged(recipient: Recipient, memberLabel: StyledMemberLabel? = null) {
|
||||
private fun onRecipientChanged(recipient: Recipient, memberLabel: StyledMemberLabel? = null, canSetMemberLabel: Boolean = false) {
|
||||
avatar.setRecipient(recipient)
|
||||
badge.setBadgeFromRecipient(recipient)
|
||||
name.text = if (recipient.isSelf) {
|
||||
@@ -104,17 +115,17 @@ object RecipientPreference {
|
||||
}
|
||||
}
|
||||
|
||||
val aboutText = recipient.combinedAboutAndEmoji
|
||||
when {
|
||||
memberLabel != null -> showMemberLabel(memberLabel)
|
||||
|
||||
!recipient.combinedAboutAndEmoji.isNullOrEmpty() -> {
|
||||
about?.text = recipient.combinedAboutAndEmoji
|
||||
about?.visible = true
|
||||
memberLabelView?.visible = false
|
||||
}
|
||||
recipient.isSelf && canSetMemberLabel -> showAddMemberLabel()
|
||||
|
||||
!aboutText.isNullOrBlank() -> showAbout(aboutText)
|
||||
|
||||
else -> {
|
||||
memberLabelView?.visible = false
|
||||
addMemberLabelView?.visible = false
|
||||
about?.visible = false
|
||||
}
|
||||
}
|
||||
@@ -131,9 +142,24 @@ object RecipientPreference {
|
||||
visible = true
|
||||
}
|
||||
|
||||
addMemberLabelView?.visible = false
|
||||
about?.visible = false
|
||||
}
|
||||
|
||||
private fun showAddMemberLabel() {
|
||||
addMemberLabelView?.visible = true
|
||||
memberLabelView?.visible = false
|
||||
about?.visible = false
|
||||
}
|
||||
|
||||
private fun showAbout(text: String) {
|
||||
about?.text = text
|
||||
about?.visible = true
|
||||
|
||||
memberLabelView?.visible = false
|
||||
addMemberLabelView?.visible = false
|
||||
}
|
||||
|
||||
private fun observeRecipient(lifecycleOwner: LifecycleOwner?, recipient: Recipient?) {
|
||||
this.recipient?.live()?.liveData?.removeObserver(recipientObserver)
|
||||
|
||||
|
||||
@@ -52,6 +52,12 @@ class MemberLabelRepository private constructor(
|
||||
@WorkerThread
|
||||
fun getLabelJava(groupId: GroupId.V2, recipient: Recipient): MemberLabel? = runBlocking { getLabel(groupId, recipient) }
|
||||
|
||||
/**
|
||||
* Checks whether the [Recipient] has permission to set their member label in the given group (blocking version for Java compatibility).
|
||||
*/
|
||||
@WorkerThread
|
||||
fun canSetLabelJava(groupId: GroupId.V2, recipient: Recipient): Boolean = runBlocking { canSetLabel(groupId, recipient) }
|
||||
|
||||
/**
|
||||
* Gets the member label for a specific recipient in the group.
|
||||
*/
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/Signal.Text.BodyLarge"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/recipient_member_label"
|
||||
app:layout_constraintBottom_toTopOf="@+id/recipient_info_container"
|
||||
app:layout_constraintEnd_toStartOf="@+id/admin"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toEndOf="@+id/recipient_avatar"
|
||||
@@ -63,47 +63,57 @@
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Miles Morales" />
|
||||
|
||||
<org.thoughtcrime.securesms.groups.memberlabel.MemberLabelPillView
|
||||
android:id="@+id/recipient_member_label"
|
||||
<FrameLayout
|
||||
android:id="@+id/recipient_info_container"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="1dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@+id/recipient_about"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/admin"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="@+id/recipient_name"
|
||||
app:layout_constraintTop_toBottomOf="@+id/recipient_name"
|
||||
app:layout_constraintWidth_default="wrap"
|
||||
app:layout_goneMarginEnd="0dp"
|
||||
tools:visibility="visible" />
|
||||
app:layout_constraintStart_toEndOf="@+id/recipient_avatar"
|
||||
app:layout_constraintTop_toBottomOf="@+id/recipient_name">
|
||||
|
||||
<org.thoughtcrime.securesms.groups.memberlabel.MemberLabelPillView
|
||||
android:id="@+id/recipient_member_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/add_member_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableEnd="@drawable/symbol_chevron_right_compact_bold_16"
|
||||
android:drawableTint="@color/signal_colorOnSurfaceVariant"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/GroupRecipientListItem__add_member_label"
|
||||
android:textAppearance="@style/Signal.Text.LabelMedium"
|
||||
android:textColor="@color/signal_colorOnSurfaceVariant"
|
||||
android:visibility="visible" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/recipient_about"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:gravity="start|center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
android:visibility="gone"
|
||||
tools:text="Hangin' around the web"
|
||||
tools:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.Barrier
|
||||
android:id="@+id/recipient_content_end_barrier"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
app:barrierDirection="end"
|
||||
app:constraint_referenced_ids="recipient_name, recipient_about" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/recipient_about"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="start|center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/Signal.Text.BodyMedium"
|
||||
android:textColor="@color/signal_text_secondary"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/admin"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toEndOf="@+id/recipient_avatar"
|
||||
app:layout_constraintTop_toBottomOf="@+id/recipient_member_label"
|
||||
tools:text="Hangin' around the web" />
|
||||
app:constraint_referenced_ids="recipient_name,recipient_info_container" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/admin"
|
||||
|
||||
@@ -5167,6 +5167,8 @@
|
||||
<!-- Button text to approve a user that has requested to join a group -->
|
||||
<string name="GroupRecipientListItem_approve_description">Approve</string>
|
||||
<string name="GroupRecipientListItem_deny_description">Deny</string>
|
||||
<!-- Placeholder shown in the group member list when the user has not yet set a member label. -->
|
||||
<string name="GroupRecipientListItem__add_member_label">Add member label</string>
|
||||
|
||||
|
||||
<!-- GroupsLearnMoreBottomSheetDialogFragment -->
|
||||
|
||||
Reference in New Issue
Block a user