Add confirmation dialog for lowering a raised hand.
This commit is contained in:
parent
c2f5a6390e
commit
9ed80d46b6
17 changed files with 136 additions and 65 deletions
|
@ -437,7 +437,13 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
|||
participantUpdateWindow = new CallParticipantsListUpdatePopupWindow(callScreen);
|
||||
callStateUpdatePopupWindow = new CallStateUpdatePopupWindow(callScreen);
|
||||
wifiToCellularPopupWindow = new WifiToCellularPopupWindow(callScreen);
|
||||
callOverflowPopupWindow = new CallOverflowPopupWindow(this, callScreen);
|
||||
callOverflowPopupWindow = new CallOverflowPopupWindow(this, callScreen, () -> {
|
||||
CallParticipantsState state = viewModel.getCallParticipantsStateSnapshot();
|
||||
if (state == null) {
|
||||
return false;
|
||||
}
|
||||
return state.getLocalParticipant().isHandRaised();
|
||||
});
|
||||
}
|
||||
|
||||
private void initializeViewModel(boolean isLandscapeEnabled) {
|
||||
|
|
|
@ -12,22 +12,25 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.widget.PopupWindowCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.WebRtcCallActivity
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
|
||||
/**
|
||||
* A popup window for calls that holds extra actions, such as reactions, raise hand, and screen sharing.
|
||||
*
|
||||
*/
|
||||
class CallOverflowPopupWindow(private val activity: WebRtcCallActivity, parentViewGroup: ViewGroup) : PopupWindow(
|
||||
class CallOverflowPopupWindow(private val activity: FragmentActivity, parentViewGroup: ViewGroup, private val raisedHandDelegate: RaisedHandDelegate) : PopupWindow(
|
||||
LayoutInflater.from(activity).inflate(R.layout.call_overflow_holder, parentViewGroup, false),
|
||||
activity.resources.getDimension(R.dimen.calling_reaction_popup_menu_width).toInt(),
|
||||
activity.resources.getDimension(R.dimen.calling_reaction_popup_menu_height).toInt()
|
||||
|
||||
) {
|
||||
private val raiseHandLabel: TextView = (contentView as LinearLayout).findViewById(R.id.raise_hand_label)
|
||||
|
||||
init {
|
||||
val root = (contentView as LinearLayout)
|
||||
|
@ -36,8 +39,19 @@ class CallOverflowPopupWindow(private val activity: WebRtcCallActivity, parentVi
|
|||
dismiss()
|
||||
}
|
||||
root.findViewById<ConstraintLayout>(R.id.raise_hand_layout_parent).setOnClickListener {
|
||||
ApplicationDependencies.getSignalCallManager().raiseHand(true)
|
||||
dismiss()
|
||||
if (raisedHandDelegate.isSelfHandRaised()) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.CallOverflowPopupWindow__lower_your_hand)
|
||||
.setPositiveButton(R.string.CallOverflowPopupWindow__lower_hand) { _, _ ->
|
||||
ApplicationDependencies.getSignalCallManager().raiseHand(false)
|
||||
this@CallOverflowPopupWindow.dismiss()
|
||||
}
|
||||
.setNegativeButton(R.string.CallOverflowPopupWindow__cancel, null)
|
||||
.show()
|
||||
} else {
|
||||
ApplicationDependencies.getSignalCallManager().raiseHand(true)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +72,12 @@ class CallOverflowPopupWindow(private val activity: WebRtcCallActivity, parentVi
|
|||
val xOffset = windowWidth - popupWidth - margin
|
||||
val yOffset = -popupHeight - margin
|
||||
|
||||
raiseHandLabel.setText(if (raisedHandDelegate.isSelfHandRaised()) R.string.CallOverflowPopupWindow__lower_hand else R.string.CallOverflowPopupWindow__raise_hand)
|
||||
|
||||
PopupWindowCompat.showAsDropDown(this, anchor, xOffset, yOffset, Gravity.NO_GRAVITY)
|
||||
}
|
||||
|
||||
interface RaisedHandDelegate {
|
||||
fun isSelfHandRaised(): Boolean
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,11 @@ import android.content.Context
|
|||
import androidx.annotation.PluralsRes
|
||||
import androidx.annotation.StringRes
|
||||
import com.annimon.stream.OptionalLong
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcControls.FoldableState
|
||||
import org.thoughtcrime.securesms.events.CallParticipant
|
||||
import org.thoughtcrime.securesms.events.CallParticipant.Companion.HAND_LOWERED
|
||||
import org.thoughtcrime.securesms.events.CallParticipant.Companion.createLocal
|
||||
import org.thoughtcrime.securesms.events.GroupCallRaiseHandEvent
|
||||
import org.thoughtcrime.securesms.events.GroupCallReactionEvent
|
||||
|
@ -27,11 +29,10 @@ data class CallParticipantsState(
|
|||
val callState: WebRtcViewModel.State = WebRtcViewModel.State.CALL_DISCONNECTED,
|
||||
val groupCallState: WebRtcViewModel.GroupCallState = WebRtcViewModel.GroupCallState.IDLE,
|
||||
private val remoteParticipants: ParticipantCollection = ParticipantCollection(SMALL_GROUP_MAX),
|
||||
val localParticipant: CallParticipant = createLocal(CameraState.UNKNOWN, BroadcastVideoSink(), microphoneEnabled = false, isHandRaised = false),
|
||||
val localParticipant: CallParticipant = createLocal(CameraState.UNKNOWN, BroadcastVideoSink(), microphoneEnabled = false, handRaisedTimestamp = HAND_LOWERED),
|
||||
val focusedParticipant: CallParticipant = CallParticipant.EMPTY,
|
||||
val localRenderState: WebRtcLocalRenderState = WebRtcLocalRenderState.GONE,
|
||||
val reactions: List<GroupCallReactionEvent> = emptyList(),
|
||||
val raisedHands: List<GroupCallRaiseHandEvent> = emptyList(),
|
||||
val isInPipMode: Boolean = false,
|
||||
private val showVideoForOutgoing: Boolean = false,
|
||||
val isViewingFocusedParticipant: Boolean = false,
|
||||
|
@ -50,6 +51,15 @@ data class CallParticipantsState(
|
|||
val isLargeVideoGroup: Boolean = allRemoteParticipants.size > SMALL_GROUP_MAX
|
||||
val isIncomingRing: Boolean = callState == WebRtcViewModel.State.CALL_INCOMING
|
||||
|
||||
val raisedHands: List<GroupCallRaiseHandEvent>
|
||||
get() {
|
||||
val results = allRemoteParticipants.filter { it.isHandRaised }.map { GroupCallRaiseHandEvent(it.recipient, it.handRaisedTimestamp) }.toMutableList()
|
||||
if (localParticipant.isHandRaised) {
|
||||
results.add(GroupCallRaiseHandEvent(localParticipant.recipient, localParticipant.handRaisedTimestamp))
|
||||
}
|
||||
return results.toImmutableList()
|
||||
}
|
||||
|
||||
val gridParticipants: List<CallParticipant>
|
||||
get() {
|
||||
return remoteParticipants.gridParticipants
|
||||
|
@ -229,7 +239,6 @@ data class CallParticipantsState(
|
|||
localRenderState = localRenderState,
|
||||
showVideoForOutgoing = newShowVideoForOutgoing,
|
||||
recipient = webRtcViewModel.recipient,
|
||||
raisedHands = webRtcViewModel.raisedHands,
|
||||
remoteDevicesCount = webRtcViewModel.remoteDevicesCount,
|
||||
ringGroup = webRtcViewModel.ringGroup,
|
||||
isInOutgoingRingingMode = isInOutgoingRingingMode,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package org.thoughtcrime.securesms.components.webrtc.controls
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
@ -42,6 +43,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.lifecycle.toLiveData
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.reactivex.rxjava3.core.BackpressureStrategy
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import org.signal.core.ui.Rows
|
||||
|
@ -337,9 +339,10 @@ private fun CallParticipantRow(
|
|||
)
|
||||
|
||||
if (showIcons && showHandRaised && canLowerHand) {
|
||||
val context = LocalContext.current
|
||||
TextButton(onClick = {
|
||||
if (recipient.isSelf) {
|
||||
ApplicationDependencies.getSignalCallManager().raiseHand(false)
|
||||
showLowerHandDialog(context)
|
||||
}
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.CallOverflowPopupWindow__lower_hand))
|
||||
|
@ -391,6 +394,16 @@ private fun CallParticipantRow(
|
|||
}
|
||||
}
|
||||
|
||||
private fun showLowerHandDialog(context: Context) {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.CallOverflowPopupWindow__lower_your_hand)
|
||||
.setPositiveButton(
|
||||
R.string.CallOverflowPopupWindow__lower_hand
|
||||
) { _, _ -> ApplicationDependencies.getSignalCallManager().raiseHand(false) }
|
||||
.setNegativeButton(R.string.CallOverflowPopupWindow__cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun GroupMemberRow(
|
||||
groupMember: GroupMemberEntry.FullMember,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
package org.thoughtcrime.securesms.components.webrtc.controls
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
|
@ -41,6 +42,7 @@ import androidx.compose.ui.res.vectorResource
|
|||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.reactivex.rxjava3.core.BackpressureStrategy
|
||||
import kotlinx.coroutines.delay
|
||||
import org.signal.core.ui.theme.SignalTheme
|
||||
|
@ -50,7 +52,6 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
|||
import org.thoughtcrime.securesms.events.GroupCallRaiseHandEvent
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.time.Duration
|
||||
|
||||
/**
|
||||
* This is a UI element to display the status of one or more people with raised hands in a group call.
|
||||
|
@ -149,8 +150,9 @@ private fun RaiseHand(
|
|||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
if (state.raisedHands.first().sender.isSelf) {
|
||||
val context = LocalContext.current
|
||||
TextButton(onClick = {
|
||||
ApplicationDependencies.getSignalCallManager().raiseHand(false)
|
||||
showLowerHandDialog(context)
|
||||
}) {
|
||||
Text(text = stringResource(id = R.string.CallOverflowPopupWindow__lower_hand))
|
||||
}
|
||||
|
@ -167,6 +169,16 @@ private fun RaiseHand(
|
|||
}
|
||||
}
|
||||
|
||||
private fun showLowerHandDialog(context: Context) {
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.CallOverflowPopupWindow__lower_your_hand)
|
||||
.setPositiveButton(
|
||||
R.string.CallOverflowPopupWindow__lower_hand
|
||||
) { _, _ -> ApplicationDependencies.getSignalCallManager().raiseHand(false) }
|
||||
.setNegativeButton(R.string.CallOverflowPopupWindow__cancel, null)
|
||||
.show()
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun getSnackbarText(state: RaiseHandState): String {
|
||||
if (state.isEmpty()) {
|
||||
|
|
|
@ -16,7 +16,7 @@ data class CallParticipant constructor(
|
|||
val isForwardingVideo: Boolean = true,
|
||||
val isVideoEnabled: Boolean = false,
|
||||
val isMicrophoneEnabled: Boolean = false,
|
||||
val isHandRaised: Boolean = false,
|
||||
val handRaisedTimestamp: Long = HAND_LOWERED,
|
||||
val lastSpoke: Long = 0,
|
||||
val audioLevel: AudioLevel? = null,
|
||||
val isMediaKeysReceived: Boolean = true,
|
||||
|
@ -36,6 +36,9 @@ data class CallParticipant constructor(
|
|||
val isSelf: Boolean
|
||||
get() = recipient.isSelf
|
||||
|
||||
val isHandRaised: Boolean
|
||||
get() = handRaisedTimestamp > 0
|
||||
|
||||
fun getRecipientDisplayName(context: Context): String {
|
||||
return if (recipient.isSelf && isPrimary) {
|
||||
context.getString(R.string.CallParticipant__you)
|
||||
|
@ -72,6 +75,10 @@ data class CallParticipant constructor(
|
|||
return copy(isScreenSharing = enable)
|
||||
}
|
||||
|
||||
fun withHandRaisedTimestamp(timestamp: Long): CallParticipant {
|
||||
return copy(handRaisedTimestamp = timestamp)
|
||||
}
|
||||
|
||||
enum class DeviceOrdinal {
|
||||
PRIMARY, SECONDARY
|
||||
}
|
||||
|
@ -103,24 +110,28 @@ data class CallParticipant constructor(
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val HAND_LOWERED = -1L
|
||||
|
||||
@JvmField
|
||||
val EMPTY: CallParticipant = CallParticipant()
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun createLocal(
|
||||
cameraState: CameraState,
|
||||
renderer: BroadcastVideoSink,
|
||||
microphoneEnabled: Boolean,
|
||||
isHandRaised: Boolean
|
||||
handRaisedTimestamp: Long,
|
||||
callParticipantId: CallParticipantId = CallParticipantId(Recipient.self())
|
||||
): CallParticipant {
|
||||
return CallParticipant(
|
||||
callParticipantId = CallParticipantId(Recipient.self()),
|
||||
callParticipantId = callParticipantId,
|
||||
recipient = Recipient.self(),
|
||||
videoSink = renderer,
|
||||
cameraState = cameraState,
|
||||
isVideoEnabled = cameraState.isEnabled && cameraState.cameraCount > 0,
|
||||
isMicrophoneEnabled = microphoneEnabled,
|
||||
isHandRaised = isHandRaised
|
||||
handRaisedTimestamp = handRaisedTimestamp
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -133,7 +144,7 @@ data class CallParticipant constructor(
|
|||
isForwardingVideo: Boolean,
|
||||
audioEnabled: Boolean,
|
||||
videoEnabled: Boolean,
|
||||
isHandRaised: Boolean,
|
||||
handRaisedTimestamp: Long,
|
||||
lastSpoke: Long,
|
||||
mediaKeysReceived: Boolean,
|
||||
addedToCallTime: Long,
|
||||
|
@ -148,7 +159,7 @@ data class CallParticipant constructor(
|
|||
isForwardingVideo = isForwardingVideo,
|
||||
isVideoEnabled = videoEnabled,
|
||||
isMicrophoneEnabled = audioEnabled,
|
||||
isHandRaised = isHandRaised,
|
||||
handRaisedTimestamp = handRaisedTimestamp,
|
||||
lastSpoke = lastSpoke,
|
||||
isMediaKeysReceived = mediaKeysReceived,
|
||||
addedToCallTime = addedToCallTime,
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.events
|
|||
|
||||
import com.annimon.stream.OptionalLong
|
||||
import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink
|
||||
import org.thoughtcrime.securesms.events.CallParticipant.Companion.HAND_LOWERED
|
||||
import org.thoughtcrime.securesms.events.CallParticipant.Companion.createLocal
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
@ -92,7 +93,6 @@ class WebRtcViewModel(state: WebRtcServiceState) {
|
|||
val isRemoteVideoOffer: Boolean = state.getCallSetupState(state.callInfoState.activePeer?.callId).isRemoteVideoOffer
|
||||
val callConnectedTime: Long = state.callInfoState.callConnectedTime
|
||||
val remoteParticipants: List<CallParticipant> = state.callInfoState.remoteCallParticipants
|
||||
val raisedHands: List<GroupCallRaiseHandEvent> = state.callInfoState.raisedHands
|
||||
val identityChangedParticipants: Set<RecipientId> = state.callInfoState.identityChangedRecipients
|
||||
val remoteDevicesCount: OptionalLong = state.callInfoState.remoteDevicesCount
|
||||
val participantLimit: Long? = state.callInfoState.participantLimit
|
||||
|
@ -107,11 +107,11 @@ class WebRtcViewModel(state: WebRtcServiceState) {
|
|||
val availableDevices: Set<SignalAudioManager.AudioDevice> = state.localDeviceState.availableDevices
|
||||
val bluetoothPermissionDenied: Boolean = state.localDeviceState.bluetoothPermissionDenied
|
||||
|
||||
val localParticipant: CallParticipant = createLocal(
|
||||
val localParticipant: CallParticipant = state.callInfoState.localParticipant ?: createLocal(
|
||||
state.localDeviceState.cameraState,
|
||||
(if (state.videoState.localSink != null) state.videoState.localSink else BroadcastVideoSink())!!,
|
||||
state.localDeviceState.isMicrophoneEnabled,
|
||||
state.callInfoState.raisedHands.map { it.sender }.contains(Recipient.self())
|
||||
HAND_LOWERED
|
||||
)
|
||||
|
||||
val isCellularConnection: Boolean = when (state.localDeviceState.networkConnectionType) {
|
||||
|
|
|
@ -50,7 +50,7 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor {
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
currentState.getCallInfoState().getRaisedHands().contains(remotePeer.getRecipient()),
|
||||
CallParticipant.HAND_LOWERED,
|
||||
0,
|
||||
true,
|
||||
0,
|
||||
|
@ -109,7 +109,7 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor {
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
currentState.getCallInfoState().getRaisedHands().contains(remotePeer.getRecipient()),
|
||||
CallParticipant.HAND_LOWERED,
|
||||
0,
|
||||
true,
|
||||
0,
|
||||
|
|
|
@ -108,6 +108,8 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
|
|||
videoSink = new BroadcastVideoSink();
|
||||
}
|
||||
|
||||
long handRaisedTimestamp = callParticipant != null ? callParticipant.getHandRaisedTimestamp() : CallParticipant.HAND_LOWERED;
|
||||
|
||||
builder.putParticipant(callParticipantId,
|
||||
CallParticipant.createRemote(callParticipantId,
|
||||
recipient,
|
||||
|
@ -116,7 +118,7 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
|
|||
device.getForwardingVideo() == null || device.getForwardingVideo(),
|
||||
Boolean.FALSE.equals(device.getAudioMuted()),
|
||||
Boolean.FALSE.equals(device.getVideoMuted()),
|
||||
currentState.getCallInfoState().getRaisedHands().contains(recipient),
|
||||
handRaisedTimestamp,
|
||||
device.getSpeakerTime(),
|
||||
device.getMediaKeysReceived(),
|
||||
device.getAddedTime(),
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.signal.ringrtc.GroupCall;
|
|||
import org.signal.ringrtc.PeekInfo;
|
||||
import org.thoughtcrime.securesms.events.CallParticipant;
|
||||
import org.thoughtcrime.securesms.events.CallParticipantId;
|
||||
import org.thoughtcrime.securesms.events.GroupCallRaiseHandEvent;
|
||||
import org.thoughtcrime.securesms.events.GroupCallReactionEvent;
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
|
@ -24,18 +23,13 @@ import org.thoughtcrime.securesms.ringrtc.RemotePeer;
|
|||
import org.thoughtcrime.securesms.service.webrtc.state.CallInfoState;
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcEphemeralState;
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
|
||||
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ezvcard.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Process actions for when the call has at least once been connected and joined.
|
||||
|
@ -266,34 +260,38 @@ public class GroupConnectedActionProcessor extends GroupActionProcessor {
|
|||
|
||||
@Override
|
||||
protected @NonNull WebRtcServiceState handleGroupCallRaisedHand(@NonNull WebRtcServiceState currentState, List<Long> raisedHands) {
|
||||
Log.i(tag, "handleGroupCallRaisedHand():");
|
||||
List<GroupCallRaiseHandEvent> existingHands = currentState.getCallInfoState().getRaisedHands();
|
||||
Log.i(TAG, "handleGroupCallRaisedHand():");
|
||||
long now = System.currentTimeMillis();
|
||||
WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder().changeCallInfoState();
|
||||
Long localDemuxId = currentState.getCallInfoState().requireGroupCall().getLocalDeviceState().getDemuxId();
|
||||
|
||||
List<CallParticipant> participants = currentState.getCallInfoState().getRemoteCallParticipants();
|
||||
List<GroupCallRaiseHandEvent> currentRaisedHands = raisedHands
|
||||
.stream().map(demuxId -> {
|
||||
if (Objects.equals(demuxId, currentState.getCallInfoState().requireGroupCall().getLocalDeviceState().getDemuxId())) {
|
||||
return Recipient.self();
|
||||
}
|
||||
|
||||
CallParticipant participant = participants.stream().filter(it -> it.getCallParticipantId().getDemuxId() == demuxId).findFirst().orElse(null);
|
||||
if (participant == null) {
|
||||
Log.v(TAG, "Could not find CallParticipantId in list of call participants based on demuxId for raise hand.");
|
||||
return null;
|
||||
}
|
||||
return participant.getRecipient();
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.map(recipient -> {
|
||||
final Optional<GroupCallRaiseHandEvent> matchingEvent = existingHands.stream().filter(existingEvent -> existingEvent.getSender().equals(recipient)).findFirst();
|
||||
if (matchingEvent.isPresent()) {
|
||||
return matchingEvent.get();
|
||||
} else {
|
||||
return new GroupCallRaiseHandEvent(recipient, System.currentTimeMillis());
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
for (CallParticipant updatedParticipant : participants) {
|
||||
boolean isHandCurrentlyRaised = raisedHands.contains(updatedParticipant.getCallParticipantId().getDemuxId());
|
||||
boolean wasHandAlreadyRaised = updatedParticipant.isHandRaised();
|
||||
if (isHandCurrentlyRaised && !wasHandAlreadyRaised) {
|
||||
builder.putParticipant(updatedParticipant.getCallParticipantId(), updatedParticipant.withHandRaisedTimestamp(now));
|
||||
} else if (!isHandCurrentlyRaised && wasHandAlreadyRaised) {
|
||||
builder.putParticipant(updatedParticipant.getCallParticipantId(), updatedParticipant.withHandRaisedTimestamp(CallParticipant.HAND_LOWERED));
|
||||
}
|
||||
}
|
||||
|
||||
return currentState.builder().changeCallInfoState().setRaisedHand(currentRaisedHands).build();
|
||||
if (localDemuxId != null) {
|
||||
if (raisedHands.contains(localDemuxId)) {
|
||||
builder.setLocalParticipant(CallParticipant.createLocal(currentState.getLocalDeviceState().getCameraState(),
|
||||
currentState.getVideoState().requireLocalSink(),
|
||||
currentState.getLocalDeviceState().isMicrophoneEnabled(),
|
||||
now,
|
||||
new CallParticipantId(localDemuxId, Recipient.self().getId())));
|
||||
} else {
|
||||
builder.setLocalParticipant(CallParticipant.createLocal(currentState.getLocalDeviceState().getCameraState(),
|
||||
currentState.getVideoState().requireLocalSink(),
|
||||
currentState.getLocalDeviceState().isMicrophoneEnabled(),
|
||||
CallParticipant.HAND_LOWERED,
|
||||
new CallParticipantId(localDemuxId, Recipient.self().getId())));
|
||||
}
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
|
|||
true,
|
||||
true,
|
||||
true,
|
||||
currentState.getCallInfoState().getRaisedHands().contains(recipient),
|
||||
CallParticipant.HAND_LOWERED,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
|
|
|
@ -167,7 +167,7 @@ public final class IncomingGroupCallActionProcessor extends DeviceAwareActionPro
|
|||
true,
|
||||
true,
|
||||
false,
|
||||
currentState.getCallInfoState().getRaisedHands().contains(remotePeerGroup.getRecipient()),
|
||||
CallParticipant.HAND_LOWERED,
|
||||
0,
|
||||
true,
|
||||
0,
|
||||
|
|
|
@ -5,7 +5,6 @@ import org.signal.ringrtc.CallId
|
|||
import org.signal.ringrtc.GroupCall
|
||||
import org.thoughtcrime.securesms.events.CallParticipant
|
||||
import org.thoughtcrime.securesms.events.CallParticipantId
|
||||
import org.thoughtcrime.securesms.events.GroupCallRaiseHandEvent
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
|
@ -23,6 +22,7 @@ data class CallInfoState(
|
|||
var callRecipient: Recipient = Recipient.UNKNOWN,
|
||||
var callConnectedTime: Long = -1,
|
||||
@get:JvmName("getRemoteCallParticipantsMap") var remoteParticipants: MutableMap<CallParticipantId, CallParticipant> = mutableMapOf(),
|
||||
var localParticipant: CallParticipant? = null,
|
||||
var peerMap: MutableMap<Int, RemotePeer> = mutableMapOf(),
|
||||
var activePeer: RemotePeer? = null,
|
||||
var groupCall: GroupCall? = null,
|
||||
|
@ -31,8 +31,7 @@ data class CallInfoState(
|
|||
var remoteDevicesCount: OptionalLong = OptionalLong.empty(),
|
||||
var participantLimit: Long? = null,
|
||||
var pendingParticipants: PendingParticipantCollection = PendingParticipantCollection(),
|
||||
var callLinkDisconnectReason: CallLinkDisconnectReason? = null,
|
||||
var raisedHands: List<GroupCallRaiseHandEvent> = emptyList()
|
||||
var callLinkDisconnectReason: CallLinkDisconnectReason? = null
|
||||
) {
|
||||
|
||||
val remoteCallParticipants: List<CallParticipant>
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink;
|
|||
import org.thoughtcrime.securesms.components.webrtc.EglBaseWrapper;
|
||||
import org.thoughtcrime.securesms.events.CallParticipant;
|
||||
import org.thoughtcrime.securesms.events.CallParticipantId;
|
||||
import org.thoughtcrime.securesms.events.GroupCallRaiseHandEvent;
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
@ -366,8 +365,8 @@ public class WebRtcServiceStateBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public @NonNull CallInfoStateBuilder setRaisedHand(@NonNull List<GroupCallRaiseHandEvent> raisedHands) {
|
||||
toBuild.setRaisedHands(raisedHands);
|
||||
public @NonNull CallInfoStateBuilder setLocalParticipant(@NonNull CallParticipant callParticipant) {
|
||||
toBuild.setLocalParticipant(callParticipant);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1857,6 +1857,8 @@
|
|||
<string name="CallOverflowPopupWindow__lower_your_hand">Lower your hand?</string>
|
||||
<!-- A dialog button to confirm you would like to lower your hand -->
|
||||
<string name="CallOverflowPopupWindow__lower_hand">Lower hand</string>
|
||||
<!-- A negative button for a dialog confirming the user wants to lower their hand (withdraw a raised hand) -->
|
||||
<string name="CallOverflowPopupWindow__cancel">Cancel</string>
|
||||
<!-- A notification to the user that they successfully raised their hand -->
|
||||
<string name="CallOverflowPopupWindow__you_raised_your_hand">You raised your hand</string>
|
||||
<!-- A button to take you to a list of participants with raised hands -->
|
||||
|
|
|
@ -178,7 +178,7 @@ public class CallParticipantListUpdateTest {
|
|||
private static CallParticipant createParticipant(long recipientId, long deMuxId, @NonNull CallParticipant.DeviceOrdinal deviceOrdinal) {
|
||||
Recipient recipient = new Recipient(RecipientId.from(recipientId), mock(RecipientDetails.class), true);
|
||||
|
||||
return CallParticipant.createRemote(new CallParticipantId(deMuxId, recipient.getId()), recipient, null, new BroadcastVideoSink(), false, false, false, false, -1, false, 0, false, deviceOrdinal);
|
||||
return CallParticipant.createRemote(new CallParticipantId(deMuxId, recipient.getId()), recipient, null, new BroadcastVideoSink(), false, false, false, CallParticipant.HAND_LOWERED, -1, false, 0, false, deviceOrdinal);
|
||||
}
|
||||
|
||||
}
|
|
@ -243,7 +243,7 @@ public class ParticipantCollectionTest {
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
CallParticipant.HAND_LOWERED,
|
||||
lastSpoke,
|
||||
false,
|
||||
added,
|
||||
|
|
Loading…
Add table
Reference in a new issue