mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Raise hand polish.
This commit is contained in:
committed by
Cody Henthorne
parent
d2e19c5129
commit
c03d3520d6
@@ -19,6 +19,8 @@ import androidx.fragment.app.FragmentActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
/**
|
||||
* A popup window for calls that holds extra actions, such as reactions, raise hand, and screen sharing.
|
||||
@@ -34,25 +36,33 @@ class CallOverflowPopupWindow(private val activity: FragmentActivity, parentView
|
||||
|
||||
init {
|
||||
val root = (contentView as LinearLayout)
|
||||
root.findViewById<CallReactionScrubber>(R.id.reaction_scrubber).initialize(activity.supportFragmentManager) {
|
||||
ApplicationDependencies.getSignalCallManager().react(it)
|
||||
dismiss()
|
||||
}
|
||||
root.findViewById<ConstraintLayout>(R.id.raise_hand_layout_parent).setOnClickListener {
|
||||
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)
|
||||
if (FeatureFlags.groupCallReactions()) {
|
||||
val reactionScrubber = root.findViewById<CallReactionScrubber>(R.id.reaction_scrubber)
|
||||
reactionScrubber.visible = true
|
||||
reactionScrubber.initialize(activity.supportFragmentManager) {
|
||||
ApplicationDependencies.getSignalCallManager().react(it)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
if (FeatureFlags.groupCallRaiseHand()) {
|
||||
val raiseHand = root.findViewById<ConstraintLayout>(R.id.raise_hand_layout_parent)
|
||||
raiseHand.visible = true
|
||||
raiseHand.setOnClickListener {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun show(anchor: View) {
|
||||
|
||||
@@ -132,9 +132,7 @@ public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestu
|
||||
|
||||
extraPaddingBottom = parent.getMeasuredHeight() + parent.getTop() - bottomBoundary;
|
||||
|
||||
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) child.getLayoutParams();
|
||||
layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin, layoutParams.rightMargin, extraPaddingBottom + framePadding);
|
||||
child.setLayoutParams(layoutParams);
|
||||
ViewUtil.setBottomMargin(child, extraPaddingBottom + framePadding);
|
||||
}
|
||||
|
||||
private boolean onGestureFinished(MotionEvent e) {
|
||||
|
||||
@@ -124,7 +124,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
private Stub<View> callLinkWarningCard;
|
||||
private RecyclerView groupReactionsFeed;
|
||||
private MultiReactionBurstLayout reactionViews;
|
||||
private Guideline aboveControlsGuideline;
|
||||
private ComposeView raiseHandSnackbar;
|
||||
|
||||
|
||||
@@ -204,7 +203,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
callLinkWarningCard = new Stub<>(findViewById(R.id.call_screen_call_link_warning));
|
||||
groupReactionsFeed = findViewById(R.id.call_screen_reactions_feed);
|
||||
reactionViews = findViewById(R.id.call_screen_reactions_container);
|
||||
aboveControlsGuideline = findViewById(R.id.call_screen_above_controls_guideline);
|
||||
raiseHandSnackbar = findViewById(R.id.call_screen_raise_hand_view);
|
||||
|
||||
View decline = findViewById(R.id.call_screen_decline_call);
|
||||
@@ -593,10 +591,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull View getPopupAnchor() {
|
||||
return aboveControlsGuideline;
|
||||
}
|
||||
|
||||
public void setStatusFromHangupType(@NonNull HangupMessage.Type hangupType) {
|
||||
switch (hangupType) {
|
||||
case NORMAL:
|
||||
@@ -921,8 +915,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
|
||||
public void onControlTopChanged(int top) {
|
||||
pictureInPictureGestureHelper.setBottomVerticalBoundary(top);
|
||||
|
||||
aboveControlsGuideline.setGuidelineBegin(top);
|
||||
}
|
||||
|
||||
public interface ControlsListener {
|
||||
|
||||
@@ -18,6 +18,7 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.constraintlayout.widget.Guideline
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.transition.AutoTransition
|
||||
@@ -71,6 +72,7 @@ class ControlsAndInfoController(
|
||||
private val callInfoComposeView: ComposeView
|
||||
private val raiseHandComposeView: ComposeView
|
||||
private val callControls: ConstraintLayout
|
||||
private val aboveControlsGuideline: Guideline
|
||||
private val bottomSheetVisibilityListeners = mutableSetOf<BottomSheetVisibilityListener>()
|
||||
private val scheduleHideControlsRunnable: Runnable = Runnable { onScheduledHide() }
|
||||
private val handler: Handler?
|
||||
@@ -88,6 +90,7 @@ class ControlsAndInfoController(
|
||||
callInfoComposeView = webRtcCallView.findViewById(R.id.call_info_compose)
|
||||
callControls = webRtcCallView.findViewById(R.id.call_controls_constraint_layout)
|
||||
raiseHandComposeView = webRtcCallView.findViewById(R.id.call_screen_raise_hand_view)
|
||||
aboveControlsGuideline = webRtcCallView.findViewById(R.id.call_screen_above_controls_guideline)
|
||||
|
||||
callInfoComposeView.apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
@@ -123,7 +126,11 @@ class ControlsAndInfoController(
|
||||
|
||||
coordinator.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
||||
val guidelineTop = max(frame.top, coordinator.height - behavior.peekHeight)
|
||||
webRtcCallView.post { webRtcCallView.onControlTopChanged(guidelineTop) }
|
||||
webRtcCallView.post { onControlTopChanged(guidelineTop) }
|
||||
}
|
||||
|
||||
raiseHandComposeView.addOnLayoutChangeListener { _, _, top, _, bottom, _, _, _, _ ->
|
||||
onControlTopChanged(guidelineTop = aboveControlsGuideline.top, composeViewSize = bottom - top)
|
||||
}
|
||||
|
||||
callControls.viewTreeObserver.addOnGlobalLayoutListener {
|
||||
@@ -135,7 +142,7 @@ class ControlsAndInfoController(
|
||||
behavior.maxHeight = (coordinator.height.toFloat() * 0.66f).toInt()
|
||||
|
||||
val guidelineTop = max(frame.top, coordinator.height - behavior.peekHeight)
|
||||
webRtcCallView.post { webRtcCallView.onControlTopChanged(guidelineTop) }
|
||||
webRtcCallView.post { onControlTopChanged(guidelineTop) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,7 +168,7 @@ class ControlsAndInfoController(
|
||||
callInfoComposeView.alpha = alphaCallInfo(slideOffset)
|
||||
callInfoComposeView.translationY = infoTranslationDistance - (infoTranslationDistance * callInfoComposeView.alpha)
|
||||
|
||||
webRtcCallView.onControlTopChanged(max(frame.top, coordinator.height - behavior.peekHeight))
|
||||
onControlTopChanged(max(frame.top, coordinator.height - behavior.peekHeight))
|
||||
}
|
||||
})
|
||||
|
||||
@@ -178,6 +185,11 @@ class ControlsAndInfoController(
|
||||
}
|
||||
}
|
||||
|
||||
fun onControlTopChanged(guidelineTop: Int, composeViewSize: Int = raiseHandComposeView.height) {
|
||||
aboveControlsGuideline.setGuidelineBegin(guidelineTop)
|
||||
webRtcCallView.onControlTopChanged(guidelineTop - composeViewSize)
|
||||
}
|
||||
|
||||
fun addVisibilityListener(listener: BottomSheetVisibilityListener): Boolean {
|
||||
return bottomSheetVisibilityListeners.add(listener)
|
||||
}
|
||||
@@ -188,7 +200,7 @@ class ControlsAndInfoController(
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
fun showControls() {
|
||||
private fun showControls() {
|
||||
cancelScheduledHide()
|
||||
behavior.isHideable = false
|
||||
behavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
@@ -223,7 +235,7 @@ class ControlsAndInfoController(
|
||||
overflowPopupWindow.dismiss()
|
||||
} else {
|
||||
cancelScheduledHide()
|
||||
overflowPopupWindow.show(webRtcCallView.popupAnchor)
|
||||
overflowPopupWindow.show(aboveControlsGuideline)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ package org.thoughtcrime.securesms.components.webrtc.controls
|
||||
import android.content.Context
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.expandIn
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkOut
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -59,11 +63,11 @@ import java.util.concurrent.TimeUnit
|
||||
*/
|
||||
object RaiseHandSnackbar {
|
||||
const val TAG = "RaiseHandSnackbar"
|
||||
val COLLAPSE_DELAY_MS = TimeUnit.SECONDS.toMillis(4L)
|
||||
private val COLLAPSE_DELAY_MS = TimeUnit.SECONDS.toMillis(4L)
|
||||
|
||||
@Composable
|
||||
fun View(webRtcCallViewModel: WebRtcCallViewModel, showCallInfoListener: () -> Unit, modifier: Modifier = Modifier) {
|
||||
var isExpanded by remember { mutableStateOf(ExpansionState(false, false)) }
|
||||
var isExpanded by remember { mutableStateOf(ExpansionState(isExpanded = false, forced = false)) }
|
||||
|
||||
val webRtcState by webRtcCallViewModel.callParticipantsState
|
||||
.toFlowable(BackpressureStrategy.LATEST)
|
||||
@@ -84,10 +88,10 @@ object RaiseHandSnackbar {
|
||||
|
||||
LaunchedEffect(isExpanded) {
|
||||
delay(COLLAPSE_DELAY_MS)
|
||||
isExpanded = ExpansionState(false, false)
|
||||
isExpanded = ExpansionState(isExpanded = false, forced = false)
|
||||
}
|
||||
|
||||
RaiseHand(state, modifier, { isExpanded = ExpansionState(true, true) }, showCallInfoListener)
|
||||
RaiseHand(state, modifier, { isExpanded = ExpansionState(isExpanded = true, forced = true) }, showCallInfoListener = showCallInfoListener)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +110,11 @@ private fun RaiseHand(
|
||||
setExpanded: (Boolean) -> Unit = {},
|
||||
showCallInfoListener: () -> Unit = {}
|
||||
) {
|
||||
AnimatedVisibility(visible = state.raisedHands.isNotEmpty()) {
|
||||
AnimatedVisibility(
|
||||
visible = state.raisedHands.isNotEmpty(),
|
||||
enter = fadeIn() + expandIn(expandFrom = Alignment.CenterEnd),
|
||||
exit = shrinkOut(shrinkTowards = Alignment.CenterEnd) + fadeOut()
|
||||
) {
|
||||
SignalTheme(
|
||||
isDarkMode = true
|
||||
) {
|
||||
@@ -115,10 +123,10 @@ private fun RaiseHand(
|
||||
.padding(horizontal = 16.dp)
|
||||
.clip(shape = RoundedCornerShape(16.dp, 16.dp, 16.dp, 16.dp))
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
) {
|
||||
val boxModifier = modifier
|
||||
.height(48.dp)
|
||||
.animateContentSize()
|
||||
) {
|
||||
val boxModifier = modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.clickable(
|
||||
!state.expansionState.isExpanded,
|
||||
@@ -207,7 +215,7 @@ private fun getShortDisplayName(raisedHands: List<GroupCallRaiseHandEvent>): Str
|
||||
|
||||
private data class RaiseHandState(
|
||||
val raisedHands: List<GroupCallRaiseHandEvent> = emptyList(),
|
||||
val expansionState: ExpansionState = ExpansionState(false, false)
|
||||
val expansionState: ExpansionState = ExpansionState(isExpanded = false, forced = false)
|
||||
) {
|
||||
|
||||
fun isEmpty(): Boolean {
|
||||
|
||||
@@ -14,14 +14,17 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/calling_reaction_emoji_height"
|
||||
android:background="@drawable/conversation_reaction_overlay_background"
|
||||
android:elevation="4dp" />
|
||||
android:elevation="4dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/raise_hand_layout_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/calling_reaction_emoji_height"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@drawable/conversation_reaction_overlay_background">
|
||||
android:background="@drawable/conversation_reaction_overlay_background"
|
||||
android:elevation="4dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/raise_hand_icon"
|
||||
|
||||
Reference in New Issue
Block a user