Add snackbar that is displayed if you're currently in a different call.
This commit is contained in:
parent
c36c6e62e2
commit
5bd3eda17d
24 changed files with 394 additions and 131 deletions
|
@ -53,6 +53,7 @@ import org.signal.core.util.concurrent.LifecycleDisposable;
|
|||
import org.signal.core.util.concurrent.RxExtensions;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar;
|
||||
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
|
||||
import org.thoughtcrime.securesms.contacts.ContactChipViewModel;
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionDisplayMode;
|
||||
|
@ -1009,12 +1010,16 @@ public final class ContactSelectionListFragment extends LoggingFragment {
|
|||
private class CallButtonClickCallbacks implements ContactSearchAdapter.CallButtonClickCallbacks {
|
||||
@Override
|
||||
public void onVideoCallButtonClicked(@NonNull Recipient recipient) {
|
||||
CommunicationActions.startVideoCall(ContactSelectionListFragment.this, recipient);
|
||||
CommunicationActions.startVideoCall(ContactSelectionListFragment.this, recipient, () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioCallButtonClicked(@NonNull Recipient recipient) {
|
||||
CommunicationActions.startVoiceCall(ContactSelectionListFragment.this, recipient);
|
||||
CommunicationActions.startVoiceCall(ContactSelectionListFragment.this, recipient, () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|||
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable;
|
||||
import org.signal.donations.StripeApi;
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar;
|
||||
import org.thoughtcrime.securesms.components.DebugLogsPromptDialogFragment;
|
||||
import org.thoughtcrime.securesms.components.DeviceSpecificNotificationBottomSheet;
|
||||
import org.thoughtcrime.securesms.components.PromptBatterySaverDialogFragment;
|
||||
|
@ -243,7 +244,9 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
private void handleCallLinkInIntent(Intent intent) {
|
||||
Uri data = intent.getData();
|
||||
if (data != null) {
|
||||
CommunicationActions.handlePotentialCallLinkUrl(this, data.toString());
|
||||
CommunicationActions.handlePotentialCallLinkUrl(this, data.toString(), () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(findViewById(android.R.id.content));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.signal.core.util.DimensionUnit;
|
|||
import org.signal.core.util.concurrent.LifecycleDisposable;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar;
|
||||
import org.thoughtcrime.securesms.components.menu.ActionItem;
|
||||
import org.thoughtcrime.securesms.components.menu.SignalContextMenu;
|
||||
import org.thoughtcrime.securesms.contacts.management.ContactsManagementRepository;
|
||||
|
@ -305,7 +306,9 @@ public class NewConversationActivity extends ContactSelectionActivity
|
|||
R.drawable.ic_phone_right_24,
|
||||
getString(R.string.NewConversationActivity__audio_call),
|
||||
R.color.signal_colorOnSurface,
|
||||
() -> CommunicationActions.startVoiceCall(this, recipient)
|
||||
() -> CommunicationActions.startVoiceCall(this, recipient, () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(findViewById(android.R.id.content));
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
|
@ -321,7 +324,9 @@ public class NewConversationActivity extends ContactSelectionActivity
|
|||
R.drawable.ic_video_call_24,
|
||||
getString(R.string.NewConversationActivity__video_call),
|
||||
R.color.signal_colorOnSurface,
|
||||
() -> CommunicationActions.startVideoCall(this, recipient)
|
||||
() -> CommunicationActions.startVideoCall(this, recipient, () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(findViewById(android.R.id.content));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.calls
|
||||
|
||||
import android.view.View
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.signal.core.ui.Snackbars
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* Snackbar which can be displayed whenever the user tries to join a call but is already in another.
|
||||
*/
|
||||
object YouAreAlreadyInACallSnackbar {
|
||||
/**
|
||||
* Composable component
|
||||
*/
|
||||
@Composable
|
||||
fun YouAreAlreadyInACallSnackbar(
|
||||
displaySnackbar: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val message = stringResource(R.string.CommunicationActions__you_are_already_in_a_call)
|
||||
val hostState = remember { SnackbarHostState() }
|
||||
Snackbars.Host(hostState, modifier = modifier)
|
||||
|
||||
LaunchedEffect(displaySnackbar) {
|
||||
if (displaySnackbar) {
|
||||
hostState.showSnackbar(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View system component
|
||||
*/
|
||||
@JvmStatic
|
||||
fun show(view: View) {
|
||||
Snackbar.make(
|
||||
view,
|
||||
view.context.getString(R.string.CommunicationActions__you_are_already_in_a_call),
|
||||
Snackbar.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import android.os.Bundle
|
|||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
|
@ -21,6 +22,7 @@ import androidx.compose.foundation.layout.wrapContentSize
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -36,21 +38,28 @@ import io.reactivex.rxjava3.kotlin.subscribeBy
|
|||
import org.signal.core.ui.BottomSheets
|
||||
import org.signal.core.ui.Buttons
|
||||
import org.signal.core.ui.Dividers
|
||||
import org.signal.core.ui.Previews
|
||||
import org.signal.core.ui.Rows
|
||||
import org.signal.core.ui.SignalPreview
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.signal.ringrtc.CallLinkState
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.calls.links.CallLinks
|
||||
import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment
|
||||
import org.thoughtcrime.securesms.calls.links.SignalCallRow
|
||||
import org.thoughtcrime.securesms.compose.ComposeBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CreateCallLinkResult
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkState
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.UpdateCallLinkResult
|
||||
import org.thoughtcrime.securesms.sharing.v2.ShareActivity
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions
|
||||
import org.thoughtcrime.securesms.util.Util
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Bottom sheet for creating call links
|
||||
|
@ -77,84 +86,21 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||
|
||||
@Composable
|
||||
override fun SheetContent() {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
) {
|
||||
val callLink: CallLinkTable.CallLink by viewModel.callLink
|
||||
val callLink: CallLinkTable.CallLink by viewModel.callLink
|
||||
val displayAlreadyInACallSnackbar: Boolean by viewModel.showAlreadyInACall.collectAsState(false)
|
||||
|
||||
BottomSheets.Handle(modifier = Modifier.align(Alignment.CenterHorizontally))
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__create_call_link),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
SignalCallRow(
|
||||
callLink = callLink,
|
||||
callLinkPeekInfo = null,
|
||||
onJoinClicked = this@CreateCallLinkBottomSheetDialogFragment::onJoinClicked
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(
|
||||
id = if (callLink.state.name.isEmpty()) {
|
||||
R.string.CreateCallLinkBottomSheetDialogFragment__add_call_name
|
||||
} else {
|
||||
R.string.CreateCallLinkBottomSheetDialogFragment__edit_call_name
|
||||
}
|
||||
),
|
||||
onClick = this@CreateCallLinkBottomSheetDialogFragment::onAddACallNameClicked
|
||||
)
|
||||
|
||||
Rows.ToggleRow(
|
||||
checked = callLink.state.restrictions == CallLinkState.Restrictions.ADMIN_APPROVAL,
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__require_admin_approval),
|
||||
onCheckChanged = this@CreateCallLinkBottomSheetDialogFragment::setApproveAllMembers,
|
||||
modifier = Modifier.clickable(onClick = this@CreateCallLinkBottomSheetDialogFragment::toggleApproveAllMembers)
|
||||
)
|
||||
|
||||
Dividers.Default()
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__share_link_via_signal),
|
||||
icon = painterResource(id = R.drawable.symbol_forward_24),
|
||||
onClick = this@CreateCallLinkBottomSheetDialogFragment::onShareViaSignalClicked
|
||||
)
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__copy_link),
|
||||
icon = painterResource(id = R.drawable.symbol_copy_android_24),
|
||||
onClick = this@CreateCallLinkBottomSheetDialogFragment::onCopyLinkClicked
|
||||
)
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__share_link),
|
||||
icon = painterResource(id = R.drawable.symbol_share_android_24),
|
||||
onClick = this@CreateCallLinkBottomSheetDialogFragment::onShareLinkClicked
|
||||
)
|
||||
|
||||
Buttons.MediumTonal(
|
||||
onClick = this@CreateCallLinkBottomSheetDialogFragment::onDoneClicked,
|
||||
modifier = Modifier
|
||||
.padding(end = dimensionResource(id = R.dimen.core_ui__gutter))
|
||||
.align(Alignment.End)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__done))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
}
|
||||
CreateCallLinkBottomSheetContent(
|
||||
callLink = callLink,
|
||||
onJoinClicked = this@CreateCallLinkBottomSheetDialogFragment::onJoinClicked,
|
||||
onAddACallNameClicked = this@CreateCallLinkBottomSheetDialogFragment::onAddACallNameClicked,
|
||||
onApproveAllMembersChanged = this@CreateCallLinkBottomSheetDialogFragment::setApproveAllMembers,
|
||||
onToggleApproveAllMembersClicked = this@CreateCallLinkBottomSheetDialogFragment::toggleApproveAllMembers,
|
||||
onShareViaSignalClicked = this@CreateCallLinkBottomSheetDialogFragment::onShareViaSignalClicked,
|
||||
onCopyLinkClicked = this@CreateCallLinkBottomSheetDialogFragment::onCopyLinkClicked,
|
||||
onShareLinkClicked = this@CreateCallLinkBottomSheetDialogFragment::onShareLinkClicked,
|
||||
onDoneClicked = this@CreateCallLinkBottomSheetDialogFragment::onDoneClicked,
|
||||
displayAlreadyInACallSnackbar = displayAlreadyInACallSnackbar
|
||||
)
|
||||
}
|
||||
|
||||
private fun setCallName(callName: String) {
|
||||
|
@ -195,7 +141,9 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||
lifecycleDisposable += viewModel.commitCallLink().subscribeBy(onSuccess = {
|
||||
when (it) {
|
||||
is EnsureCallLinkCreatedResult.Success -> {
|
||||
CommunicationActions.startVideoCall(requireActivity(), it.recipient)
|
||||
CommunicationActions.startVideoCall(requireActivity(), it.recipient) {
|
||||
viewModel.setShowAlreadyInACall(true)
|
||||
}
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
|
@ -282,3 +230,123 @@ class CreateCallLinkBottomSheetDialogFragment : ComposeBottomSheetDialogFragment
|
|||
Toast.makeText(requireContext(), R.string.CallLinkDetailsFragment__couldnt_save_changes, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CreateCallLinkBottomSheetContent(
|
||||
callLink: CallLinkTable.CallLink,
|
||||
displayAlreadyInACallSnackbar: Boolean,
|
||||
onJoinClicked: () -> Unit = {},
|
||||
onAddACallNameClicked: () -> Unit = {},
|
||||
onApproveAllMembersChanged: (Boolean) -> Unit = {},
|
||||
onToggleApproveAllMembersClicked: () -> Unit = {},
|
||||
onShareViaSignalClicked: () -> Unit = {},
|
||||
onCopyLinkClicked: () -> Unit = {},
|
||||
onShareLinkClicked: () -> Unit = {},
|
||||
onDoneClicked: () -> Unit = {}
|
||||
) {
|
||||
Box {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentSize(Alignment.Center)
|
||||
) {
|
||||
BottomSheets.Handle(modifier = Modifier.align(Alignment.CenterHorizontally))
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__create_call_link),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
|
||||
SignalCallRow(
|
||||
callLink = callLink,
|
||||
callLinkPeekInfo = null,
|
||||
onJoinClicked = onJoinClicked
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(
|
||||
id = if (callLink.state.name.isEmpty()) {
|
||||
R.string.CreateCallLinkBottomSheetDialogFragment__add_call_name
|
||||
} else {
|
||||
R.string.CreateCallLinkBottomSheetDialogFragment__edit_call_name
|
||||
}
|
||||
),
|
||||
onClick = onAddACallNameClicked
|
||||
)
|
||||
|
||||
Rows.ToggleRow(
|
||||
checked = callLink.state.restrictions == CallLinkState.Restrictions.ADMIN_APPROVAL,
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__require_admin_approval),
|
||||
onCheckChanged = onApproveAllMembersChanged,
|
||||
modifier = Modifier.clickable(onClick = onToggleApproveAllMembersClicked)
|
||||
)
|
||||
|
||||
Dividers.Default()
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__share_link_via_signal),
|
||||
icon = painterResource(id = R.drawable.symbol_forward_24),
|
||||
onClick = onShareViaSignalClicked
|
||||
)
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__copy_link),
|
||||
icon = painterResource(id = R.drawable.symbol_copy_android_24),
|
||||
onClick = onCopyLinkClicked
|
||||
)
|
||||
|
||||
Rows.TextRow(
|
||||
text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__share_link),
|
||||
icon = painterResource(id = R.drawable.symbol_share_android_24),
|
||||
onClick = onShareLinkClicked
|
||||
)
|
||||
|
||||
Buttons.MediumTonal(
|
||||
onClick = onDoneClicked,
|
||||
modifier = Modifier
|
||||
.padding(end = dimensionResource(id = R.dimen.core_ui__gutter))
|
||||
.align(Alignment.End)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.CreateCallLinkBottomSheetDialogFragment__done))
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
}
|
||||
|
||||
YouAreAlreadyInACallSnackbar(
|
||||
displaySnackbar = displayAlreadyInACallSnackbar,
|
||||
modifier = Modifier.align(Alignment.BottomCenter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@SignalPreview
|
||||
@Composable
|
||||
private fun CreateCallLinkBottomSheetContentPreview() {
|
||||
Previews.BottomSheetPreview {
|
||||
CreateCallLinkBottomSheetContent(
|
||||
callLink = CallLinkTable.CallLink(
|
||||
recipientId = RecipientId.UNKNOWN,
|
||||
roomId = CallLinkRoomId.fromBytes(byteArrayOf(1, 2, 3, 4)),
|
||||
credentials = null,
|
||||
state = SignalCallLinkState(
|
||||
name = "Test Call",
|
||||
restrictions = CallLinkState.Restrictions.ADMIN_APPROVAL,
|
||||
revoked = false,
|
||||
expiration = Instant.MAX
|
||||
),
|
||||
deletionTimestamp = 0L
|
||||
),
|
||||
displayAlreadyInACallSnackbar = true
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ import io.reactivex.rxjava3.core.Single
|
|||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.signal.ringrtc.CallLinkState.Restrictions
|
||||
import org.thoughtcrime.securesms.calls.links.CallLinks
|
||||
import org.thoughtcrime.securesms.calls.links.UpdateCallLinkRepository
|
||||
|
@ -47,6 +50,9 @@ class CreateCallLinkViewModel(
|
|||
val callLink: State<CallLinkTable.CallLink> = _callLink
|
||||
val linkKeyBytes: ByteArray = credentials.linkKeyBytes
|
||||
|
||||
private val internalShowAlreadyInACall = MutableStateFlow(false)
|
||||
val showAlreadyInACall: StateFlow<Boolean> = internalShowAlreadyInACall
|
||||
|
||||
private val disposables = CompositeDisposable()
|
||||
|
||||
init {
|
||||
|
@ -61,6 +67,10 @@ class CreateCallLinkViewModel(
|
|||
disposables.dispose()
|
||||
}
|
||||
|
||||
fun setShowAlreadyInACall(showAlreadyInACall: Boolean) {
|
||||
internalShowAlreadyInACall.update { showAlreadyInACall }
|
||||
}
|
||||
|
||||
fun commitCallLink(): Single<EnsureCallLinkCreatedResult> {
|
||||
return repository.ensureCallLinkCreated(credentials)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.Column
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
@ -37,6 +38,8 @@ import org.signal.core.util.concurrent.LifecycleDisposable
|
|||
import org.signal.core.util.logging.Log
|
||||
import org.signal.ringrtc.CallLinkState.Restrictions
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.calls.links.CallLinks
|
||||
import org.thoughtcrime.securesms.calls.links.EditCallLinkNameDialogFragment
|
||||
import org.thoughtcrime.securesms.calls.links.SignalCallRow
|
||||
|
@ -44,6 +47,7 @@ import org.thoughtcrime.securesms.compose.ComposeFragment
|
|||
import org.thoughtcrime.securesms.database.CallLinkTable
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkCredentials
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkState
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.UpdateCallLinkResult
|
||||
import org.thoughtcrime.securesms.sharing.v2.ShareActivity
|
||||
|
@ -79,9 +83,11 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback {
|
|||
@Composable
|
||||
override fun FragmentContent() {
|
||||
val state by viewModel.state
|
||||
val showAlreadyInACall by viewModel.showAlreadyInACall.collectAsState(false)
|
||||
|
||||
CallLinkDetails(
|
||||
state,
|
||||
showAlreadyInACall,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
@ -93,7 +99,9 @@ class CallLinkDetailsFragment : ComposeFragment(), CallLinkDetailsCallback {
|
|||
override fun onJoinClicked() {
|
||||
val recipientSnapshot = viewModel.recipientSnapshot
|
||||
if (recipientSnapshot != null) {
|
||||
CommunicationActions.startVideoCall(this, recipientSnapshot)
|
||||
CommunicationActions.startVideoCall(this, recipientSnapshot) {
|
||||
viewModel.showAlreadyInACall(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,7 +214,7 @@ private fun CallLinkDetailsPreview() {
|
|||
)
|
||||
CallLinkTable.CallLink(
|
||||
recipientId = RecipientId.UNKNOWN,
|
||||
roomId = credentials.roomId,
|
||||
roomId = CallLinkRoomId.fromBytes(byteArrayOf(1, 2, 3, 4)),
|
||||
credentials = credentials,
|
||||
state = SignalCallLinkState(
|
||||
name = "Call Name",
|
||||
|
@ -224,6 +232,7 @@ private fun CallLinkDetailsPreview() {
|
|||
false,
|
||||
callLink
|
||||
),
|
||||
true,
|
||||
object : CallLinkDetailsCallback {
|
||||
override fun onDeleteConfirmed() = Unit
|
||||
override fun onDeleteCanceled() = Unit
|
||||
|
@ -243,10 +252,14 @@ private fun CallLinkDetailsPreview() {
|
|||
@Composable
|
||||
private fun CallLinkDetails(
|
||||
state: CallLinkDetailsState,
|
||||
showAlreadyInACall: Boolean,
|
||||
callback: CallLinkDetailsCallback
|
||||
) {
|
||||
Scaffolds.Settings(
|
||||
title = stringResource(id = R.string.CallLinkDetailsFragment__call_details),
|
||||
snackbarHost = {
|
||||
YouAreAlreadyInACallSnackbar(showAlreadyInACall)
|
||||
},
|
||||
onNavigationClick = callback::onNavigationClicked,
|
||||
navigationIconPainter = painterResource(id = R.drawable.ic_arrow_left_24)
|
||||
) { paddingValues ->
|
||||
|
|
|
@ -17,6 +17,9 @@ import io.reactivex.rxjava3.kotlin.plusAssign
|
|||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import io.reactivex.rxjava3.subjects.BehaviorSubject
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.signal.ringrtc.CallLinkState
|
||||
import org.thoughtcrime.securesms.calls.links.CallLinks
|
||||
import org.thoughtcrime.securesms.calls.links.UpdateCallLinkRepository
|
||||
|
@ -44,6 +47,9 @@ class CallLinkDetailsViewModel(
|
|||
val recipientSnapshot: Recipient?
|
||||
get() = recipientSubject.value
|
||||
|
||||
private val internalShowAlreadyInACall = MutableStateFlow(false)
|
||||
val showAlreadyInACall: StateFlow<Boolean> = internalShowAlreadyInACall
|
||||
|
||||
init {
|
||||
disposables += repository.refreshCallLinkState(callLinkRoomId)
|
||||
disposables += CallLinks.watchCallLink(callLinkRoomId)
|
||||
|
@ -80,6 +86,10 @@ class CallLinkDetailsViewModel(
|
|||
disposables.dispose()
|
||||
}
|
||||
|
||||
fun showAlreadyInACall(showAlreadyInACall: Boolean) {
|
||||
internalShowAlreadyInACall.update { showAlreadyInACall }
|
||||
}
|
||||
|
||||
fun setDisplayRevocationDialog(displayRevocationDialog: Boolean) {
|
||||
_state.value = _state.value.copy(displayRevocationDialog = displayRevocationDialog)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsActivity
|
||||
import org.thoughtcrime.securesms.components.menu.ActionItem
|
||||
import org.thoughtcrime.securesms.components.menu.SignalContextMenu
|
||||
|
@ -72,7 +73,9 @@ class CallLogContextMenu(
|
|||
iconRes = R.drawable.symbol_video_24,
|
||||
title = fragment.getString(R.string.CallContextMenu__video_call)
|
||||
) {
|
||||
CommunicationActions.startVideoCall(fragment, peer)
|
||||
CommunicationActions.startVideoCall(fragment, peer) {
|
||||
YouAreAlreadyInACallSnackbar.show(fragment.requireView())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,7 +88,9 @@ class CallLogContextMenu(
|
|||
iconRes = R.drawable.symbol_phone_24,
|
||||
title = fragment.getString(R.string.CallContextMenu__audio_call)
|
||||
) {
|
||||
CommunicationActions.startVoiceCall(fragment, call.peer)
|
||||
CommunicationActions.startVoiceCall(fragment, call.peer) {
|
||||
YouAreAlreadyInACallSnackbar.show(fragment.requireView())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.signal.core.util.concurrent.addTo
|
|||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.MainActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsActivity
|
||||
import org.thoughtcrime.securesms.calls.new.NewCallActivity
|
||||
import org.thoughtcrime.securesms.components.Material3SearchToolbar
|
||||
|
@ -391,12 +392,16 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal
|
|||
}
|
||||
|
||||
override fun onStartAudioCallClicked(recipient: Recipient) {
|
||||
CommunicationActions.startVoiceCall(this, recipient)
|
||||
CommunicationActions.startVoiceCall(this, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartVideoCallClicked(recipient: Recipient, canUserBeginCall: Boolean) {
|
||||
if (canUserBeginCall) {
|
||||
CommunicationActions.startVideoCall(this, recipient)
|
||||
CommunicationActions.startVideoCall(this, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
} else {
|
||||
ConversationDialogs.displayCannotStartGroupCallDueToPermissionsDialog(requireContext())
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.ContactSelectionActivity
|
|||
import org.thoughtcrime.securesms.ContactSelectionListFragment
|
||||
import org.thoughtcrime.securesms.InviteActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionDisplayMode
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
|
@ -81,9 +82,13 @@ class NewCallActivity : ContactSelectionActivity(), ContactSelectionListFragment
|
|||
|
||||
private fun launch(recipient: Recipient) {
|
||||
if (recipient.isGroup) {
|
||||
CommunicationActions.startVideoCall(this, recipient)
|
||||
CommunicationActions.startVideoCall(this, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(findViewById(android.R.id.content))
|
||||
}
|
||||
} else {
|
||||
CommunicationActions.startVoiceCall(this, recipient)
|
||||
CommunicationActions.startVoiceCall(this, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(findViewById(android.R.id.content))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.thoughtcrime.securesms.badges.Badges
|
|||
import org.thoughtcrime.securesms.badges.Badges.displayBadges
|
||||
import org.thoughtcrime.securesms.badges.models.Badge
|
||||
import org.thoughtcrime.securesms.badges.view.ViewBadgeBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView
|
||||
import org.thoughtcrime.securesms.components.recyclerview.OnScrollAnimationHelper
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
|
@ -442,11 +443,15 @@ class ConversationSettingsFragment : DSLSettingsFragment(
|
|||
.setPositiveButton(android.R.string.ok) { d, _ -> d.dismiss() }
|
||||
.show()
|
||||
} else {
|
||||
CommunicationActions.startVideoCall(requireActivity(), state.recipient)
|
||||
CommunicationActions.startVideoCall(requireActivity(), state.recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
}
|
||||
},
|
||||
onAudioClick = {
|
||||
CommunicationActions.startVoiceCall(requireActivity(), state.recipient)
|
||||
CommunicationActions.startVoiceCall(requireActivity(), state.recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
},
|
||||
onMuteClick = {
|
||||
if (!state.buttonStripState.isMuted) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
|||
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar;
|
||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||
|
@ -214,7 +215,9 @@ public class SharedContactDetailsActivity extends PassphraseRequiredActivity {
|
|||
});
|
||||
|
||||
callButtonView.setOnClickListener(v -> {
|
||||
ContactUtil.selectRecipientThroughDialog(this, pushUsers, dynamicLanguage.getCurrentLocale(), recipient -> CommunicationActions.startVoiceCall(this, recipient));
|
||||
ContactUtil.selectRecipientThroughDialog(this, pushUsers, dynamicLanguage.getCurrentLocale(), recipient -> CommunicationActions.startVoiceCall(this, recipient, () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(callButtonView);
|
||||
}));
|
||||
});
|
||||
} else if (!systemUsers.isEmpty()) {
|
||||
inviteButtonView.setVisibility(View.VISIBLE);
|
||||
|
|
|
@ -108,6 +108,7 @@ import org.thoughtcrime.securesms.badges.gifts.viewgift.received.ViewReceivedGif
|
|||
import org.thoughtcrime.securesms.badges.gifts.viewgift.sent.ViewSentGiftBottomSheet
|
||||
import org.thoughtcrime.securesms.banner.banners.ServiceOutageBanner
|
||||
import org.thoughtcrime.securesms.banner.banners.UnauthorizedBanner
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar
|
||||
import org.thoughtcrime.securesms.components.AnimatingToggle
|
||||
import org.thoughtcrime.securesms.components.ComposeText
|
||||
import org.thoughtcrime.securesms.components.ConversationSearchBottomBar
|
||||
|
@ -1494,7 +1495,9 @@ class ConversationFragment :
|
|||
private fun handleVideoCall() {
|
||||
val recipient = viewModel.recipientSnapshot ?: return
|
||||
if (!recipient.isGroup) {
|
||||
CommunicationActions.startVideoCall(this, recipient)
|
||||
CommunicationActions.startVideoCall(this, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1510,7 +1513,9 @@ class ConversationFragment :
|
|||
if (notAllowed) {
|
||||
ConversationDialogs.displayCannotStartGroupCallDueToPermissionsDialog(requireContext())
|
||||
} else {
|
||||
CommunicationActions.startVideoCall(this, recipient)
|
||||
CommunicationActions.startVideoCall(this, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2962,7 +2967,9 @@ class ConversationFragment :
|
|||
override fun onJoinGroupCallClicked() {
|
||||
val activity = activity ?: return
|
||||
val recipient = viewModel.recipientSnapshot ?: return
|
||||
CommunicationActions.startVideoCall(activity, recipient)
|
||||
CommunicationActions.startVideoCall(activity, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInviteFriendsToGroupClicked(groupId: GroupId.V2) {
|
||||
|
@ -3280,7 +3287,9 @@ class ConversationFragment :
|
|||
}
|
||||
|
||||
override fun onJoinCallLink(callLinkRootKey: CallLinkRootKey) {
|
||||
CommunicationActions.startVideoCall(this@ConversationFragment, callLinkRootKey)
|
||||
CommunicationActions.startVideoCall(this@ConversationFragment, callLinkRootKey) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onShowSafetyTips(forGroup: Boolean) {
|
||||
|
@ -3420,7 +3429,9 @@ class ConversationFragment :
|
|||
|
||||
override fun handleDial() {
|
||||
val recipient: Recipient = viewModel.recipientSnapshot ?: return
|
||||
CommunicationActions.startVoiceCall(this@ConversationFragment, recipient)
|
||||
CommunicationActions.startVoiceCall(this@ConversationFragment, recipient) {
|
||||
YouAreAlreadyInACallSnackbar.show(requireView())
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleViewMedia() {
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.R;
|
|||
import org.thoughtcrime.securesms.avatar.view.AvatarView;
|
||||
import org.thoughtcrime.securesms.badges.BadgeImageView;
|
||||
import org.thoughtcrime.securesms.badges.view.ViewBadgeBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar;
|
||||
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon;
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.ButtonStripPreference;
|
||||
import org.thoughtcrime.securesms.fonts.SignalSymbols;
|
||||
|
@ -270,12 +271,12 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
|||
return Unit.INSTANCE;
|
||||
},
|
||||
() -> {
|
||||
viewModel.onSecureVideoCallClicked(requireActivity());
|
||||
viewModel.onSecureVideoCallClicked(requireActivity(), () -> YouAreAlreadyInACallSnackbar.show(requireView()));
|
||||
return Unit.INSTANCE;
|
||||
},
|
||||
() -> {
|
||||
if (buttonStripState.isAudioSecure()) {
|
||||
viewModel.onSecureCallClicked(requireActivity());
|
||||
viewModel.onSecureCallClicked(requireActivity(), () -> YouAreAlreadyInACallSnackbar.show(requireView()));
|
||||
} else {
|
||||
viewModel.onInsecureCallClicked(requireActivity());
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@ import android.widget.Toast;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
|
@ -162,16 +160,16 @@ final class RecipientDialogViewModel extends ViewModel {
|
|||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startConversation(activity, recipient, null));
|
||||
}
|
||||
|
||||
void onSecureCallClicked(@NonNull FragmentActivity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startVoiceCall(activity, recipient));
|
||||
void onSecureCallClicked(@NonNull FragmentActivity activity, @NonNull CommunicationActions.OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startVoiceCall(activity, recipient, onUserAlreadyInAnotherCall));
|
||||
}
|
||||
|
||||
void onInsecureCallClicked(@NonNull FragmentActivity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startInsecureCall(activity, recipient));
|
||||
}
|
||||
|
||||
void onSecureVideoCallClicked(@NonNull FragmentActivity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startVideoCall(activity, recipient));
|
||||
void onSecureVideoCallClicked(@NonNull FragmentActivity activity, @NonNull CommunicationActions.OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startVideoCall(activity, recipient, onUserAlreadyInAnotherCall));
|
||||
}
|
||||
|
||||
void onBlockClicked(@NonNull FragmentActivity activity) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor {
|
|||
@Override
|
||||
protected @NonNull WebRtcServiceState handleIsInCallQuery(@NonNull WebRtcServiceState currentState, @Nullable ResultReceiver resultReceiver) {
|
||||
if (resultReceiver != null) {
|
||||
resultReceiver.send(1, null);
|
||||
resultReceiver.send(1, ActiveCallData.fromCallState(currentState).toBundle());
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2024 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.service.webrtc
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import androidx.core.os.bundleOf
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.signal.core.util.getParcelableCompat
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState
|
||||
|
||||
/**
|
||||
* Active call data to be returned from calls to isInCallQuery.
|
||||
*/
|
||||
@Parcelize
|
||||
data class ActiveCallData(
|
||||
val recipientId: RecipientId
|
||||
) : Parcelable {
|
||||
|
||||
companion object {
|
||||
private const val KEY = "ACTIVE_CALL_DATA"
|
||||
|
||||
@JvmStatic
|
||||
fun fromCallState(webRtcServiceState: WebRtcServiceState): ActiveCallData {
|
||||
return ActiveCallData(
|
||||
webRtcServiceState.callInfoState.callRecipient.id
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun fromBundle(bundle: Bundle): ActiveCallData {
|
||||
return bundle.getParcelableCompat(KEY, ActiveCallData::class.java)!!
|
||||
}
|
||||
}
|
||||
|
||||
fun toBundle(): Bundle = bundleOf(KEY to this)
|
||||
}
|
|
@ -49,7 +49,7 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
|
|||
@Override
|
||||
protected @NonNull WebRtcServiceState handleIsInCallQuery(@NonNull WebRtcServiceState currentState, @Nullable ResultReceiver resultReceiver) {
|
||||
if (resultReceiver != null) {
|
||||
resultReceiver.send(1, null);
|
||||
resultReceiver.send(1, ActiveCallData.fromCallState(currentState).toBundle());
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class GroupJoiningActionProcessor extends GroupActionProcessor {
|
|||
@Override
|
||||
protected @NonNull WebRtcServiceState handleIsInCallQuery(@NonNull WebRtcServiceState currentState, @Nullable ResultReceiver resultReceiver) {
|
||||
if (resultReceiver != null) {
|
||||
resultReceiver.send(1, null);
|
||||
resultReceiver.send(1, ActiveCallData.fromCallState(currentState).toBundle());
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public abstract class WebRtcActionProcessor {
|
|||
|
||||
protected @NonNull WebRtcServiceState handleIsInCallQuery(@NonNull WebRtcServiceState currentState, @Nullable ResultReceiver resultReceiver) {
|
||||
if (resultReceiver != null) {
|
||||
resultReceiver.send(0, null);
|
||||
resultReceiver.send(0, ActiveCallData.fromCallState(currentState).toBundle());
|
||||
}
|
||||
return currentState;
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.thoughtcrime.securesms.profiles.manage.UsernameRepository;
|
|||
import org.thoughtcrime.securesms.profiles.manage.UsernameRepository.UsernameLinkConversionResult;
|
||||
import org.thoughtcrime.securesms.proxy.ProxyBottomSheetFragment;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.webrtc.ActiveCallData;
|
||||
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
|
@ -65,18 +66,18 @@ public class CommunicationActions {
|
|||
/**
|
||||
* Start a voice call. Assumes that permission request results will be routed to a handler on the Fragment.
|
||||
*/
|
||||
public static void startVoiceCall(@NonNull Fragment fragment, @NonNull Recipient recipient) {
|
||||
startVoiceCall(new FragmentCallContext(fragment), recipient);
|
||||
public static void startVoiceCall(@NonNull Fragment fragment, @NonNull Recipient recipient, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
startVoiceCall(new FragmentCallContext(fragment), recipient, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a voice call. Assumes that permission request results will be routed to a handler on the Activity.
|
||||
*/
|
||||
public static void startVoiceCall(@NonNull FragmentActivity activity, @NonNull Recipient recipient) {
|
||||
startVoiceCall(new ActivityCallContext(activity), recipient);
|
||||
public static void startVoiceCall(@NonNull FragmentActivity activity, @NonNull Recipient recipient, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
startVoiceCall(new ActivityCallContext(activity), recipient, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
private static void startVoiceCall(@NonNull CallContext callContext, @NonNull Recipient recipient) {
|
||||
private static void startVoiceCall(@NonNull CallContext callContext, @NonNull Recipient recipient, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
if (TelephonyUtil.isAnyPstnLineBusy(callContext.getContext())) {
|
||||
Toast.makeText(callContext.getContext(),
|
||||
R.string.CommunicationActions_a_cellular_call_is_already_in_progress,
|
||||
|
@ -90,7 +91,12 @@ public class CommunicationActions {
|
|||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
if (resultCode == 1) {
|
||||
startCallInternal(callContext, recipient, false, false);
|
||||
ActiveCallData activeCallData = ActiveCallData.fromBundle(resultData);
|
||||
if (Objects.equals(activeCallData.getRecipientId(), recipient.getId())) {
|
||||
startCallInternal(callContext, recipient, false, false);
|
||||
} else {
|
||||
onUserAlreadyInAnotherCall.onUserAlreadyInAnotherCall();
|
||||
}
|
||||
} else {
|
||||
new MaterialAlertDialogBuilder(callContext.getContext())
|
||||
.setMessage(R.string.CommunicationActions_start_voice_call)
|
||||
|
@ -109,18 +115,18 @@ public class CommunicationActions {
|
|||
/**
|
||||
* Start a video call. Assumes that permission request results will be routed to a handler on the Fragment.
|
||||
*/
|
||||
public static void startVideoCall(@NonNull Fragment fragment, @NonNull Recipient recipient) {
|
||||
startVideoCall(new FragmentCallContext(fragment), recipient, false);
|
||||
public static void startVideoCall(@NonNull Fragment fragment, @NonNull Recipient recipient, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
startVideoCall(new FragmentCallContext(fragment), recipient, false, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a video call. Assumes that permission request results will be routed to a handler on the Activity.
|
||||
*/
|
||||
public static void startVideoCall(@NonNull FragmentActivity activity, @NonNull Recipient recipient) {
|
||||
startVideoCall(new ActivityCallContext(activity), recipient, false);
|
||||
public static void startVideoCall(@NonNull FragmentActivity activity, @NonNull Recipient recipient, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
startVideoCall(new ActivityCallContext(activity), recipient, false, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
private static void startVideoCall(@NonNull CallContext callContext, @NonNull Recipient recipient, boolean fromCallLink) {
|
||||
private static void startVideoCall(@NonNull CallContext callContext, @NonNull Recipient recipient, boolean fromCallLink, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
if (TelephonyUtil.isAnyPstnLineBusy(callContext.getContext())) {
|
||||
Toast.makeText(callContext.getContext(),
|
||||
R.string.CommunicationActions_a_cellular_call_is_already_in_progress,
|
||||
|
@ -132,7 +138,16 @@ public class CommunicationActions {
|
|||
AppDependencies.getSignalCallManager().isCallActive(new ResultReceiver(new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
startCallInternal(callContext, recipient, resultCode != 1, fromCallLink);
|
||||
if (resultCode == 1) {
|
||||
ActiveCallData activeCallData = ActiveCallData.fromBundle(resultData);
|
||||
if (Objects.equals(activeCallData.getRecipientId(), recipient.getId())) {
|
||||
startCallInternal(callContext, recipient, false, fromCallLink);
|
||||
} else {
|
||||
onUserAlreadyInAnotherCall.onUserAlreadyInAnotherCall();
|
||||
}
|
||||
} else {
|
||||
startCallInternal(callContext, recipient, true, fromCallLink);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -307,7 +322,7 @@ public class CommunicationActions {
|
|||
}
|
||||
}
|
||||
|
||||
public static void handlePotentialCallLinkUrl(@NonNull FragmentActivity activity, @NonNull String potentialUrl) {
|
||||
public static void handlePotentialCallLinkUrl(@NonNull FragmentActivity activity, @NonNull String potentialUrl, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
if (!CallLinks.isCallLink(potentialUrl)) {
|
||||
return;
|
||||
}
|
||||
|
@ -323,7 +338,7 @@ public class CommunicationActions {
|
|||
return;
|
||||
}
|
||||
|
||||
startVideoCall(new ActivityCallContext(activity), rootKey);
|
||||
startVideoCall(new ActivityCallContext(activity), rootKey, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -332,11 +347,11 @@ public class CommunicationActions {
|
|||
*
|
||||
* @param fragment The fragment, which will be used for context and permissions routing.
|
||||
*/
|
||||
public static void startVideoCall(@NonNull Fragment fragment, @NonNull CallLinkRootKey rootKey) {
|
||||
startVideoCall(new FragmentCallContext(fragment), rootKey);
|
||||
public static void startVideoCall(@NonNull Fragment fragment, @NonNull CallLinkRootKey rootKey, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
startVideoCall(new FragmentCallContext(fragment), rootKey, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
|
||||
private static void startVideoCall(@NonNull CallContext callContext, @NonNull CallLinkRootKey rootKey) {
|
||||
private static void startVideoCall(@NonNull CallContext callContext, @NonNull CallLinkRootKey rootKey, @NonNull OnUserAlreadyInAnotherCall onUserAlreadyInAnotherCall) {
|
||||
SimpleTask.run(() -> {
|
||||
CallLinkRoomId roomId = CallLinkRoomId.fromBytes(rootKey.deriveRoomId());
|
||||
CallLinkTable.CallLink callLink = SignalDatabase.callLinks().getOrCreateCallLinkByRootKey(rootKey);
|
||||
|
@ -354,7 +369,7 @@ public class CommunicationActions {
|
|||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
} else {
|
||||
startVideoCall(callContext, callLinkRecipient.get(), true);
|
||||
startVideoCall(callContext, callLinkRecipient.get(), true, onUserAlreadyInAnotherCall);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -532,4 +547,8 @@ public class CommunicationActions {
|
|||
return fragment.getParentFragmentManager();
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnUserAlreadyInAnotherCall {
|
||||
void onUserAlreadyInAnotherCall();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -346,6 +346,8 @@
|
|||
<string name="CommunicationActions_invalid_link">Invalid link</string>
|
||||
<!-- Message on dialog when call link url cannot be parsed -->
|
||||
<string name="CommunicationActions_this_is_not_a_valid_call_link">This is not a valid call link. Make sure the entire link is intact and correct before attempting to join.</string>
|
||||
<!-- Displayed in a snackbar when the user is already in a call -->
|
||||
<string name="CommunicationActions__you_are_already_in_a_call">You are already in a call</string>
|
||||
|
||||
<!-- ConfirmIdentityDialog -->
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import androidx.compose.material3.SnackbarHost
|
|||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.material3.SnackbarVisuals
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import org.signal.core.ui.theme.LocalSnackbarColors
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
|
@ -24,8 +25,8 @@ import org.signal.core.ui.theme.SignalTheme
|
|||
*/
|
||||
object Snackbars {
|
||||
@Composable
|
||||
fun Host(snackbarHostState: SnackbarHostState) {
|
||||
SnackbarHost(hostState = snackbarHostState) {
|
||||
fun Host(snackbarHostState: SnackbarHostState, modifier: Modifier = Modifier) {
|
||||
SnackbarHost(hostState = snackbarHostState, modifier = modifier) {
|
||||
Default(snackbarData = it)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue