diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt index dfdb6108f8..89cee12b76 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt @@ -73,7 +73,6 @@ import org.thoughtcrime.securesms.components.settings.conversation.preferences.L import org.thoughtcrime.securesms.components.settings.conversation.preferences.LegacyGroupPreference import org.thoughtcrime.securesms.components.settings.conversation.preferences.RecipientPreference import org.thoughtcrime.securesms.components.settings.conversation.preferences.SharedMediaPreference -import org.thoughtcrime.securesms.components.settings.conversation.preferences.TerminatedBannerPreference import org.thoughtcrime.securesms.components.settings.conversation.preferences.Utils.formatMutedUntil import org.thoughtcrime.securesms.conversation.ConversationIntents import org.thoughtcrime.securesms.conversation.colors.ColorizerV2 @@ -306,7 +305,6 @@ class ConversationSettingsFragment : InternalPreference.register(adapter) GroupDescriptionPreference.register(adapter) LegacyGroupPreference.register(adapter) - TerminatedBannerPreference.register(adapter) CallPreference.register(adapter) val recipientId = args.recipientId @@ -369,17 +367,10 @@ class ConversationSettingsFragment : return@configure } - state.withGroupSettingsState { - if (it.isTerminated) { - customPref(TerminatedBannerPreference.Model()) - } - } - customPref( AvatarPreference.Model( recipient = state.recipient, storyViewState = state.storyViewState, - reduceTopMargin = state.isTerminatedGroup, onAvatarClick = { avatar -> val viewAvatarIntent = AvatarPreviewActivity.intentFromRecipientId(requireContext(), state.recipient.id) val viewAvatarTransitionBundle = AvatarPreviewActivity.createTransitionBundle(requireActivity(), avatar) @@ -434,7 +425,8 @@ class ConversationSettingsFragment : customPref( BioTextPreference.GroupModel( groupTitle = groupState.groupTitle, - groupMembershipDescription = groupMembershipDescription + groupMembershipDescription = groupMembershipDescription, + isTerminated = groupState.isTerminated ) ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/AvatarPreference.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/AvatarPreference.kt index 24b241cb70..3ff63e0512 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/AvatarPreference.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/AvatarPreference.kt @@ -1,9 +1,7 @@ package org.thoughtcrime.securesms.components.settings.conversation.preferences import android.view.View -import android.view.ViewGroup import androidx.core.view.ViewCompat -import org.signal.core.util.dp import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.avatar.view.AvatarView import org.thoughtcrime.securesms.badges.BadgeImageView @@ -27,7 +25,6 @@ object AvatarPreference { class Model( val recipient: Recipient, val storyViewState: StoryViewState, - val reduceTopMargin: Boolean = false, val onAvatarClick: (AvatarView) -> Unit, val onBadgeClick: (Badge) -> Unit ) : PreferenceModel() { @@ -38,8 +35,7 @@ object AvatarPreference { override fun areContentsTheSame(newItem: Model): Boolean { return super.areContentsTheSame(newItem) && recipient.hasSameContent(newItem.recipient) && - storyViewState == newItem.storyViewState && - reduceTopMargin == newItem.reduceTopMargin + storyViewState == newItem.storyViewState } } @@ -53,10 +49,6 @@ object AvatarPreference { } override fun bind(model: Model) { - (itemView.layoutParams as? ViewGroup.MarginLayoutParams)?.let { - it.topMargin = if (model.reduceTopMargin) 0.dp else 40.dp - } - if (model.recipient.isSelf) { badge.setBadge(null) badge.setOnClickListener(null) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/BioTextPreference.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/BioTextPreference.kt index fbe66435a6..dfb84ffc1f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/BioTextPreference.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/BioTextPreference.kt @@ -2,11 +2,13 @@ package org.thoughtcrime.securesms.components.settings.conversation.preferences import android.content.ClipData import android.content.Context +import android.text.SpannableStringBuilder import android.view.View import android.widget.TextView import android.widget.Toast import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.components.settings.PreferenceModel +import org.thoughtcrime.securesms.fonts.SignalSymbols import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.util.ServiceUtil import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory @@ -61,7 +63,8 @@ object BioTextPreference { class GroupModel( val groupTitle: String, - val groupMembershipDescription: String? + val groupMembershipDescription: String?, + val isTerminated: Boolean = false ) : BioTextPreferenceModel() { override fun getHeadlineText(context: Context): CharSequence = groupTitle @@ -72,7 +75,8 @@ object BioTextPreference { override fun areContentsTheSame(newItem: GroupModel): Boolean { return super.areContentsTheSame(newItem) && groupTitle == newItem.groupTitle && - groupMembershipDescription == newItem.groupMembershipDescription + groupMembershipDescription == newItem.groupMembershipDescription && + isTerminated == newItem.isTerminated } override fun areItemsTheSame(newItem: GroupModel): Boolean { @@ -85,6 +89,7 @@ object BioTextPreference { private val headline: TextView = itemView.findViewById(R.id.bio_preference_headline) private val subhead1: TextView = itemView.findViewById(R.id.bio_preference_subhead_1) protected val subhead2: TextView = itemView.findViewById(R.id.bio_preference_subhead_2) + private val terminatedPill: TextView = itemView.findViewById(R.id.bio_preference_terminated_pill) override fun bind(model: T) { headline.text = model.getHeadlineText(context) @@ -94,6 +99,17 @@ object BioTextPreference { headline.setOnClickListener { clickListener() } } + if (model is GroupModel && model.isTerminated) { + val glyphSpan = SignalSymbols.getSpannedString(context, SignalSymbols.Weight.REGULAR, SignalSymbols.Glyph.GROUP_X) + terminatedPill.text = SpannableStringBuilder() + .append(glyphSpan) + .append(" ") + .append(context.getString(R.string.ConversationSettingsFragment__this_group_was_ended)) + terminatedPill.visibility = View.VISIBLE + } else { + terminatedPill.visibility = View.GONE + } + model.getSubhead1Text(context).let { subhead1.text = it subhead1.visibility = if (it == null) View.GONE else View.VISIBLE diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/TerminatedBannerPreference.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/TerminatedBannerPreference.kt deleted file mode 100644 index 18442b24b0..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/preferences/TerminatedBannerPreference.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2025 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.thoughtcrime.securesms.components.settings.conversation.preferences - -import android.view.View -import org.thoughtcrime.securesms.R -import org.thoughtcrime.securesms.components.settings.PreferenceModel -import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory -import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter -import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder - -object TerminatedBannerPreference { - - fun register(adapter: MappingAdapter) { - adapter.registerFactory(Model::class.java, LayoutFactory(::ViewHolder, R.layout.conversation_settings_terminated_banner)) - } - - class Model : PreferenceModel() { - override fun areItemsTheSame(newItem: Model): Boolean = true - override fun areContentsTheSame(newItem: Model): Boolean = true - } - - private class ViewHolder(itemView: View) : MappingViewHolder(itemView) { - override fun bind(model: Model) = Unit - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index f11cb59bd0..3fbe7bd049 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -3675,11 +3675,18 @@ class ConversationFragment : } override fun onBlockJoinRequest(recipient: Recipient) { - MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.ConversationFragment__block_request) - .setMessage(getString(R.string.ConversationFragment__s_will_not_be_able_to_join_or_request_to_join_this_group_via_the_group_link, recipient.getDisplayName(requireContext()))) - .setNegativeButton(R.string.ConversationFragment__cancel, null) - .setPositiveButton(R.string.ConversationFragment__block_request_button) { _, _ -> handleBlockJoinRequest(recipient) } - .show() + if (conversationGroupViewModel.groupRecordSnapshot?.isTerminated == true) { + MaterialAlertDialogBuilder(requireContext()) + .setMessage(R.string.conversation_activity__group_action_not_allowed_group_ended) + .setPositiveButton(android.R.string.ok) { d, _ -> d.dismiss() } + .show() + } else { + MaterialAlertDialogBuilder(requireContext()).setTitle(R.string.ConversationFragment__block_request) + .setMessage(getString(R.string.ConversationFragment__s_will_not_be_able_to_join_or_request_to_join_this_group_via_the_group_link, recipient.getDisplayName(requireContext()))) + .setNegativeButton(R.string.ConversationFragment__cancel, null) + .setPositiveButton(R.string.ConversationFragment__block_request_button) { _, _ -> handleBlockJoinRequest(recipient) } + .show() + } } override fun onRecipientNameClicked(target: RecipientId) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java index 2cb91a94eb..b513528f28 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/GroupsV2UpdateMessageProducer.java @@ -236,12 +236,12 @@ final class GroupsV2UpdateMessageProducer { private void describeGroupTerminateUpdate(@NonNull GroupTerminateChangeUpdate update, @NonNull List updates) { if (update.updaterAci == null) { - updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_was_terminated), Glyph.X_CIRCLE)); + updates.add(updateDescription(context.getString(R.string.MessageRecord_the_group_was_terminated), Glyph.GROUP_X)); } else { if (selfIds.matches(update.updaterAci)) { - updates.add(updateDescription(context.getString(R.string.MessageRecord_you_terminated_the_group), Glyph.X_CIRCLE)); + updates.add(updateDescription(context.getString(R.string.MessageRecord_you_terminated_the_group), Glyph.GROUP_X)); } else { - updates.add(updateDescription(R.string.MessageRecord_s_terminated_the_group, update.updaterAci, Glyph.X_CIRCLE)); + updates.add(updateDescription(R.string.MessageRecord_s_terminated_the_group, update.updaterAci, Glyph.GROUP_X)); } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt b/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt index e5151806db..d5b73c9c49 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/fonts/SignalSymbols.kt @@ -113,6 +113,7 @@ object SignalSymbols { GIF('\uE037'), GIF_RECTANGLE('\uE097'), GROUP('\uE038'), + GROUP_X('\uE0AE'), HEART('\uE039'), INCOMING('\uE03A'), INFO('\uE03B'), diff --git a/app/src/main/res/drawable/terminated_banner_background.xml b/app/src/main/res/drawable/terminated_pill_background.xml similarity index 51% rename from app/src/main/res/drawable/terminated_banner_background.xml rename to app/src/main/res/drawable/terminated_pill_background.xml index f51ceb8706..a3a253f720 100644 --- a/app/src/main/res/drawable/terminated_banner_background.xml +++ b/app/src/main/res/drawable/terminated_pill_background.xml @@ -1,8 +1,6 @@ - - + + diff --git a/app/src/main/res/layout/conversation_settings_bio_preference_item.xml b/app/src/main/res/layout/conversation_settings_bio_preference_item.xml index 5b357776d5..5fdc686a50 100644 --- a/app/src/main/res/layout/conversation_settings_bio_preference_item.xml +++ b/app/src/main/res/layout/conversation_settings_bio_preference_item.xml @@ -20,6 +20,26 @@ app:layout_constraintTop_toTopOf="parent" tools:text="Miles Morales" /> + + - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9edbf4a9f2..75093e11b5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3640,7 +3640,7 @@ Send failed because the group was ended. You can no longer send and receive messages in this group. - You can no longer invite friends or add members to this group. + This action is unavailable because the group has ended. Message failed to delete. Check your connection and try again.