diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallEventCache.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallEventCache.kt index 9dccab0721..3acaa0eee0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallEventCache.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallEventCache.kt @@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.RecipientId +import org.whispersystems.signalservice.api.groupsv2.DecryptedGroupUtil import java.util.concurrent.Executor import kotlin.math.max import kotlin.math.min @@ -67,7 +68,7 @@ class CallEventCache( val output = mutableListOf() val groupCallStateMap = mutableMapOf() - val canUserBeginCallMap = mutableMapOf() + val canUserBeginCallMap = mutableMapOf() val callLinksSeen = hashSetOf() while (recordIterator.hasNext()) { @@ -85,7 +86,7 @@ class CallEventCache( private fun ListIterator.readNextCallLog( filterState: FilterState, groupCallStateMap: MutableMap, - canUserBeginCallMap: MutableMap, + canUserBeginCallMap: MutableMap, callLinksSeen: MutableSet ): CallLogRow.Call? { val parent = next() @@ -143,14 +144,16 @@ class CallEventCache( return (child.timestamp - parent.timestamp) <= 4.hours.inWholeMilliseconds } - private fun canUserBeginCall(peer: Recipient, decryptedGroup: ByteArray?): Boolean { - return if (peer.isGroup && decryptedGroup != null) { + private fun canUserBeginCall(peer: Recipient, decryptedGroup: ByteArray?): CallLogRow.CanStartCall { + if (peer.isGroup && decryptedGroup != null) { val proto = DecryptedGroup.ADAPTER.decode(decryptedGroup) - return proto.isAnnouncementGroup != EnabledState.ENABLED || - proto.members.firstOrNull() { it.aciBytes == SignalStore.account.aci?.toByteString() }?.role == Member.Role.ADMINISTRATOR - } else { - true + when { + proto.terminated -> return CallLogRow.CanStartCall.GROUP_TERMINATED + DecryptedGroupUtil.findMemberByAci(proto.members, SignalStore.account.requireAci()).isEmpty -> return CallLogRow.CanStartCall.NOT_A_MEMBER + proto.isAnnouncementGroup == EnabledState.ENABLED && proto.members.firstOrNull { it.aciBytes == SignalStore.account.aci?.toByteString() }?.role != Member.Role.ADMINISTRATOR -> return CallLogRow.CanStartCall.ADMIN_ONLY + } } + return CallLogRow.CanStartCall.ALLOWED } private fun getGroupCallState(body: String?): CallLogRow.GroupCallState { @@ -167,7 +170,7 @@ class CallEventCache( children: Set, filterState: FilterState, groupCallStateCache: MutableMap, - canUserBeginCallMap: MutableMap + canUserBeginCallMap: MutableMap ): CallLogRow.Call { val peer = Recipient.resolved(RecipientId.from(parent.peer)) return CallLogRow.Call( @@ -195,10 +198,10 @@ class CallEventCache( searchQuery = filterState.query, callLinkPeekInfo = AppDependencies.signalCallManager.peekInfoSnapshot[peer.id], canUserBeginCall = if (peer.isGroup) { - if (peer.isActiveGroup) { - canUserBeginCallMap.getOrPut(parent.peer) { canUserBeginCall(peer, parent.decryptedGroupBytes) } - } else false - } else true + canUserBeginCallMap.getOrPut(parent.peer) { canUserBeginCall(peer, parent.decryptedGroupBytes) } + } else { + CallLogRow.CanStartCall.ALLOWED + } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt index b4a9c37e18..c643b94240 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogAdapter.kt @@ -223,7 +223,7 @@ class CallLogAdapter( binding: CallLogAdapterItemBinding, private val onCallLinkClicked: (CallLogRow.CallLink) -> Unit, private val onCallLinkLongClicked: (View, CallLogRow.CallLink) -> Boolean, - private val onStartVideoCallClicked: (Recipient, Boolean) -> Unit + private val onStartVideoCallClicked: (Recipient, CallLogRow.CanStartCall) -> Unit ) : BindingViewHolder(binding) { override fun bind(model: CallLinkModel) { if (payload.size == 1 && payload.contains(PAYLOAD_TIMESTAMP)) { @@ -280,7 +280,7 @@ class CallLogAdapter( } ) binding.groupCallButton.setOnClickListener { - onStartVideoCallClicked(model.callLink.recipient, true) + onStartVideoCallClicked(model.callLink.recipient, CallLogRow.CanStartCall.ALLOWED) } binding.callType.visible = false binding.groupCallButton.visible = true @@ -288,7 +288,7 @@ class CallLogAdapter( binding.callType.setImageResource(R.drawable.symbol_video_24) binding.callType.contentDescription = context.getString(R.string.CallLogAdapter__start_a_video_call) binding.callType.setOnClickListener { - onStartVideoCallClicked(model.callLink.recipient, true) + onStartVideoCallClicked(model.callLink.recipient, CallLogRow.CanStartCall.ALLOWED) } binding.callType.visible = true binding.groupCallButton.visible = false @@ -301,7 +301,7 @@ class CallLogAdapter( private val onCallClicked: (CallLogRow.Call) -> Unit, private val onCallLongClicked: (View, CallLogRow.Call) -> Boolean, private val onStartAudioCallClicked: (Recipient) -> Unit, - private val onStartVideoCallClicked: (Recipient, Boolean) -> Unit + private val onStartVideoCallClicked: (Recipient, CallLogRow.CanStartCall) -> Unit ) : BindingViewHolder(binding) { override fun bind(model: CallModel) { itemView.setOnClickListener { @@ -401,7 +401,7 @@ class CallLogAdapter( CallTable.Type.VIDEO_CALL -> { binding.callType.setImageResource(R.drawable.symbol_video_24) binding.callType.contentDescription = context.getString(R.string.CallLogAdapter__start_a_video_call) - binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer, true) } + binding.callType.setOnClickListener { onStartVideoCallClicked(model.call.peer, CallLogRow.CanStartCall.ALLOWED) } binding.callType.visible = true binding.groupCallButton.visible = false } @@ -574,6 +574,6 @@ class CallLogAdapter( /** * Invoked when user presses the video icon */ - fun onStartVideoCallClicked(recipient: Recipient, canUserBeginCall: Boolean) + fun onStartVideoCallClicked(recipient: Recipient, canUserBeginCall: CallLogRow.CanStartCall) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt index a644559427..f5c8bcfd21 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogFragment.kt @@ -364,18 +364,21 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal } } - override fun onStartVideoCallClicked(recipient: Recipient, canUserBeginCall: Boolean) { - if (canUserBeginCall) { - CommunicationActions.startVideoCall(this, recipient) { - mainNavigationViewModel.snackbarRegistry.emit( - SnackbarState( - getString(R.string.CommunicationActions__you_are_already_in_a_call), - hostKey = MainSnackbarHostKey.MainChrome + override fun onStartVideoCallClicked(recipient: Recipient, canUserBeginCall: CallLogRow.CanStartCall) { + when (canUserBeginCall) { + CallLogRow.CanStartCall.ALLOWED -> { + CommunicationActions.startVideoCall(this, recipient) { + mainNavigationViewModel.snackbarRegistry.emit( + SnackbarState( + getString(R.string.CommunicationActions__you_are_already_in_a_call), + hostKey = MainSnackbarHostKey.MainChrome + ) ) - ) + } } - } else { - ConversationDialogs.displayCannotStartGroupCallDueToPermissionsDialog(requireContext()) + CallLogRow.CanStartCall.GROUP_TERMINATED -> ConversationDialogs.displayCannotStartGroupCallDueToGroupEndedDialog(requireContext()) + CallLogRow.CanStartCall.NOT_A_MEMBER -> ConversationDialogs.displayCannotStartGroupCallDueToNoLongerAMemberDialog(requireContext()) + CallLogRow.CanStartCall.ADMIN_ONLY -> ConversationDialogs.displayCannotStartGroupCallDueToPermissionsDialog(requireContext()) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt index 82268f5d9d..0a707ddbc8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/calls/log/CallLogRow.kt @@ -41,7 +41,7 @@ sealed class CallLogRow { val children: Set, val searchQuery: String?, val callLinkPeekInfo: CallLinkPeekInfo?, - val canUserBeginCall: Boolean, + val canUserBeginCall: CanStartCall, override val id: Id = Id.Call(children) ) : CallLogRow() @@ -111,4 +111,11 @@ sealed class CallLogRow { } } } + + enum class CanStartCall { + ALLOWED, + ADMIN_ONLY, + NOT_A_MEMBER, + GROUP_TERMINATED + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationDialogs.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationDialogs.kt index bf2c81a2f9..5c56b2ac55 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationDialogs.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationDialogs.kt @@ -33,6 +33,20 @@ object ConversationDialogs { .show() } + fun displayCannotStartGroupCallDueToNoLongerAMemberDialog(context: Context) { + MaterialAlertDialogBuilder(context).setTitle(R.string.ConversationActivity_cant_start_group_call) + .setMessage(R.string.CallLogFragment__cant_start_call_no_longer_a_member) + .setPositiveButton(android.R.string.ok) { d: DialogInterface, _: Int -> d.dismiss() } + .show() + } + + fun displayCannotStartGroupCallDueToGroupEndedDialog(context: Context) { + MaterialAlertDialogBuilder(context).setTitle(R.string.ConversationActivity_cant_start_group_call) + .setMessage(R.string.conversation_activity__group_action_not_allowed_group_ended) + .setPositiveButton(android.R.string.ok) { d: DialogInterface, _: Int -> d.dismiss() } + .show() + } + fun displayChatSessionRefreshLearnMoreDialog(context: Context) { MaterialAlertDialogBuilder(context) .setView(R.layout.decryption_failed_dialog) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 584a25d3fa..b79614bba6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -7893,6 +7893,8 @@ Get started by calling a friend. Call links you\'ve created will no longer work for people who have them. + + You\'re no longer a member of this group.