mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-25 20:23:19 +00:00
Move switch camera button to self pip.
This commit is contained in:
@@ -148,6 +148,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
private FullscreenHelper fullscreenHelper;
|
||||
private WebRtcCallView callScreen;
|
||||
private TooltipPopup videoTooltip;
|
||||
private TooltipPopup switchCameraTooltip;
|
||||
private WebRtcCallViewModel viewModel;
|
||||
private boolean enableVideoIfAvailable;
|
||||
private boolean hasWarnedAboutBluetooth;
|
||||
@@ -549,6 +550,20 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
}
|
||||
} else if (event instanceof WebRtcCallViewModel.Event.ShowWifiToCellularPopup) {
|
||||
wifiToCellularPopupWindow.show();
|
||||
} else if (event instanceof WebRtcCallViewModel.Event.ShowSwitchCameraTooltip) {
|
||||
if (switchCameraTooltip == null) {
|
||||
switchCameraTooltip = TooltipPopup.forTarget(callScreen.getSwitchCameraTooltipTarget())
|
||||
.setBackgroundTint(ContextCompat.getColor(this, R.color.core_ultramarine))
|
||||
.setTextColor(ContextCompat.getColor(this, R.color.core_white))
|
||||
.setText(R.string.WebRtcCallActivity__flip_camera_tooltip)
|
||||
.setOnDismissListener(() -> viewModel.onDismissedSwitchCameraTooltip())
|
||||
.show(TooltipPopup.POSITION_ABOVE);
|
||||
}
|
||||
} else if (event instanceof WebRtcCallViewModel.Event.DismissSwitchCameraTooltip) {
|
||||
if (switchCameraTooltip != null) {
|
||||
switchCameraTooltip.dismiss();
|
||||
switchCameraTooltip = null;
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown event: " + event);
|
||||
}
|
||||
|
||||
@@ -171,21 +171,23 @@ public class TooltipPopup extends PopupWindow {
|
||||
ShapeAppearanceModel.Builder shapeAppearanceModel = ShapeAppearanceModel.builder()
|
||||
.setAllCornerSizes(DimensionUnit.DP.toPixels(18));
|
||||
|
||||
// If the arrow is within the last 20dp of the right hand side, use RIGHT and set corner to 9dp
|
||||
onLayout(() -> {
|
||||
if (arrow.getX() > getContentView().getWidth() / 2f) {
|
||||
arrow.setImageResource(R.drawable.ic_tooltip_arrow_up_right);
|
||||
}
|
||||
if (position == POSITION_BELOW) {
|
||||
// If the arrow is within the last 20dp of the right hand side, use RIGHT and set corner to 9dp
|
||||
onLayout(() -> {
|
||||
if (arrow.getX() > getContentView().getWidth() / 2f) {
|
||||
arrow.setImageResource(R.drawable.ic_tooltip_arrow_up_right);
|
||||
}
|
||||
|
||||
float arrowEnd = arrow.getX() + arrow.getRight();
|
||||
if (arrowEnd > getContentView().getRight() - DimensionUnit.DP.toPixels(20)) {
|
||||
shapeableBubbleBackground.setShapeAppearanceModel(shapeAppearanceModel.setTopRightCornerSize(DimensionUnit.DP.toPixels(9f)).build());
|
||||
bubble.setBackground(shapeableBubbleBackground);
|
||||
} else if (arrowEnd < DimensionUnit.DP.toPixels(20)) {
|
||||
shapeableBubbleBackground.setShapeAppearanceModel(shapeAppearanceModel.setTopLeftCornerSize(DimensionUnit.DP.toPixels(9f)).build());
|
||||
bubble.setBackground(shapeableBubbleBackground);
|
||||
}
|
||||
});
|
||||
float arrowEnd = arrow.getX() + arrow.getRight();
|
||||
if (arrowEnd > getContentView().getRight() - DimensionUnit.DP.toPixels(20)) {
|
||||
shapeableBubbleBackground.setShapeAppearanceModel(shapeAppearanceModel.setTopRightCornerSize(DimensionUnit.DP.toPixels(9f)).build());
|
||||
bubble.setBackground(shapeableBubbleBackground);
|
||||
} else if (arrowEnd < DimensionUnit.DP.toPixels(20)) {
|
||||
shapeableBubbleBackground.setShapeAppearanceModel(shapeAppearanceModel.setTopLeftCornerSize(DimensionUnit.DP.toPixels(9f)).build());
|
||||
bubble.setBackground(shapeableBubbleBackground);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
showAsDropDown(anchor, xoffset, yoffset);
|
||||
|
||||
@@ -74,6 +74,8 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
private EmojiTextView infoMessage;
|
||||
private Button infoMoreInfo;
|
||||
private AppCompatImageView infoIcon;
|
||||
private View switchCameraIconFrame;
|
||||
private View switchCameraIcon;
|
||||
|
||||
public CallParticipantView(@NonNull Context context) {
|
||||
super(context);
|
||||
@@ -92,18 +94,20 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
backgroundAvatar = findViewById(R.id.call_participant_background_avatar);
|
||||
avatar = findViewById(R.id.call_participant_item_avatar);
|
||||
pipAvatar = findViewById(R.id.call_participant_item_pip_avatar);
|
||||
rendererFrame = findViewById(R.id.call_participant_renderer_frame);
|
||||
renderer = findViewById(R.id.call_participant_renderer);
|
||||
audioIndicator = findViewById(R.id.call_participant_audio_indicator);
|
||||
infoOverlay = findViewById(R.id.call_participant_info_overlay);
|
||||
infoIcon = findViewById(R.id.call_participant_info_icon);
|
||||
infoMessage = findViewById(R.id.call_participant_info_message);
|
||||
infoMoreInfo = findViewById(R.id.call_participant_info_more_info);
|
||||
badge = findViewById(R.id.call_participant_item_badge);
|
||||
pipBadge = findViewById(R.id.call_participant_item_pip_badge);
|
||||
backgroundAvatar = findViewById(R.id.call_participant_background_avatar);
|
||||
avatar = findViewById(R.id.call_participant_item_avatar);
|
||||
pipAvatar = findViewById(R.id.call_participant_item_pip_avatar);
|
||||
rendererFrame = findViewById(R.id.call_participant_renderer_frame);
|
||||
renderer = findViewById(R.id.call_participant_renderer);
|
||||
audioIndicator = findViewById(R.id.call_participant_audio_indicator);
|
||||
infoOverlay = findViewById(R.id.call_participant_info_overlay);
|
||||
infoIcon = findViewById(R.id.call_participant_info_icon);
|
||||
infoMessage = findViewById(R.id.call_participant_info_message);
|
||||
infoMoreInfo = findViewById(R.id.call_participant_info_more_info);
|
||||
badge = findViewById(R.id.call_participant_item_badge);
|
||||
pipBadge = findViewById(R.id.call_participant_item_pip_badge);
|
||||
switchCameraIconFrame = findViewById(R.id.call_participant_switch_camera);
|
||||
switchCameraIcon = findViewById(R.id.call_participant_switch_camera_icon);
|
||||
|
||||
avatar.setFallbackPhotoProvider(FALLBACK_PHOTO_PROVIDER);
|
||||
useLargeAvatar();
|
||||
@@ -249,6 +253,27 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(6)
|
||||
);
|
||||
|
||||
constraints.setVisibility(R.id.call_participant_switch_camera, View.VISIBLE);
|
||||
constraints.setMargin(
|
||||
R.id.call_participant_switch_camera,
|
||||
ConstraintSet.END,
|
||||
ViewUtil.dpToPx(6)
|
||||
);
|
||||
constraints.setMargin(
|
||||
R.id.call_participant_switch_camera,
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(6)
|
||||
);
|
||||
constraints.constrainWidth(R.id.call_participant_switch_camera, ViewUtil.dpToPx(28));
|
||||
constraints.constrainHeight(R.id.call_participant_switch_camera, ViewUtil.dpToPx(28));
|
||||
|
||||
ViewGroup.LayoutParams params = switchCameraIcon.getLayoutParams();
|
||||
params.width = params.height = ViewUtil.dpToPx(16);
|
||||
switchCameraIcon.setLayoutParams(params);
|
||||
|
||||
switchCameraIconFrame.setClickable(false);
|
||||
switchCameraIconFrame.setEnabled(false);
|
||||
}
|
||||
case EXPANDED_SELF_PIP -> {
|
||||
constraints.connect(
|
||||
@@ -267,6 +292,27 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(8)
|
||||
);
|
||||
|
||||
constraints.setVisibility(R.id.call_participant_switch_camera, View.VISIBLE);
|
||||
constraints.setMargin(
|
||||
R.id.call_participant_switch_camera,
|
||||
ConstraintSet.END,
|
||||
ViewUtil.dpToPx(8)
|
||||
);
|
||||
constraints.setMargin(
|
||||
R.id.call_participant_switch_camera,
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(8)
|
||||
);
|
||||
constraints.constrainWidth(R.id.call_participant_switch_camera, ViewUtil.dpToPx(48));
|
||||
constraints.constrainHeight(R.id.call_participant_switch_camera, ViewUtil.dpToPx(48));
|
||||
|
||||
ViewGroup.LayoutParams params = switchCameraIcon.getLayoutParams();
|
||||
params.width = params.height = ViewUtil.dpToPx(24);
|
||||
switchCameraIcon.setLayoutParams(params);
|
||||
|
||||
switchCameraIconFrame.setClickable(true);
|
||||
switchCameraIconFrame.setEnabled(true);
|
||||
}
|
||||
case MINI_SELF_PIP -> {
|
||||
constraints.connect(
|
||||
@@ -288,6 +334,7 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(6)
|
||||
);
|
||||
constraints.setVisibility(R.id.call_participant_switch_camera, View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -278,6 +278,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
});
|
||||
|
||||
cameraDirectionToggle.setOnClickListener(v -> runIfNonNull(controlsListener, ControlsListener::onCameraDirectionChanged));
|
||||
smallLocalRender.findViewById(R.id.call_participant_switch_camera).setOnClickListener(v -> runIfNonNull(controlsListener, ControlsListener::onCameraDirectionChanged));
|
||||
|
||||
overflow.setOnClickListener(v -> {
|
||||
runIfNonNull(controlsListener, ControlsListener::onOverflowClicked);
|
||||
@@ -794,6 +795,10 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
return videoToggle;
|
||||
}
|
||||
|
||||
public @NonNull View getSwitchCameraTooltipTarget() {
|
||||
return smallLocalRenderFrame;
|
||||
}
|
||||
|
||||
public void showSpeakerViewHint() {
|
||||
groupCallSpeakerHint.get().setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@@ -81,17 +81,18 @@ public class WebRtcCallViewModel extends ViewModel {
|
||||
private final Runnable elapsedTimeRunnable = this::handleTick;
|
||||
private final Runnable stopOutgoingRingingMode = this::stopOutgoingRingingMode;
|
||||
|
||||
private boolean canDisplayTooltipIfNeeded = true;
|
||||
private boolean canDisplayPopupIfNeeded = true;
|
||||
private boolean hasEnabledLocalVideo = false;
|
||||
private boolean wasInOutgoingRingingMode = false;
|
||||
private long callConnectedTime = -1;
|
||||
private boolean answerWithVideoAvailable = false;
|
||||
private boolean canEnterPipMode = false;
|
||||
private List<CallParticipant> previousParticipantsList = Collections.emptyList();
|
||||
private boolean callStarting = false;
|
||||
private boolean switchOnFirstScreenShare = true;
|
||||
private boolean showScreenShareTip = true;
|
||||
private boolean canDisplayTooltipIfNeeded = true;
|
||||
private boolean canDisplaySwitchCameraTooltipIfNeeded = true;
|
||||
private boolean canDisplayPopupIfNeeded = true;
|
||||
private boolean hasEnabledLocalVideo = false;
|
||||
private boolean wasInOutgoingRingingMode = false;
|
||||
private long callConnectedTime = -1;
|
||||
private boolean answerWithVideoAvailable = false;
|
||||
private boolean canEnterPipMode = false;
|
||||
private List<CallParticipant> previousParticipantsList = Collections.emptyList();
|
||||
private boolean callStarting = false;
|
||||
private boolean switchOnFirstScreenShare = true;
|
||||
private boolean showScreenShareTip = true;
|
||||
|
||||
private final WebRtcCallRepository repository = new WebRtcCallRepository(ApplicationDependencies.getApplication());
|
||||
|
||||
@@ -261,6 +262,11 @@ public class WebRtcCallViewModel extends ViewModel {
|
||||
canDisplayTooltipIfNeeded = false;
|
||||
}
|
||||
|
||||
public void onDismissedSwitchCameraTooltip() {
|
||||
canDisplaySwitchCameraTooltipIfNeeded = false;
|
||||
SignalStore.tooltips().markCallingSwitchCameraTooltipSeen();
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void updateFromWebRtcViewModel(@NonNull WebRtcViewModel webRtcViewModel, boolean enableVideo) {
|
||||
canEnterPipMode = !webRtcViewModel.getState().isPreJoinOrNetworkUnavailable();
|
||||
@@ -342,6 +348,16 @@ public class WebRtcCallViewModel extends ViewModel {
|
||||
} else if (!webRtcViewModel.isCellularConnection()) {
|
||||
canDisplayPopupIfNeeded = true;
|
||||
}
|
||||
|
||||
if (SignalStore.tooltips().showCallingSwitchCameraTooltip() &&
|
||||
canDisplaySwitchCameraTooltipIfNeeded &&
|
||||
hasEnabledLocalVideo &&
|
||||
webRtcViewModel.getState() == WebRtcViewModel.State.CALL_CONNECTED &&
|
||||
!newState.getAllRemoteParticipants().isEmpty()
|
||||
) {
|
||||
canDisplaySwitchCameraTooltipIfNeeded = false;
|
||||
events.setValue(new Event.ShowSwitchCameraTooltip());
|
||||
}
|
||||
}
|
||||
|
||||
@MainThread
|
||||
@@ -537,6 +553,12 @@ public class WebRtcCallViewModel extends ViewModel {
|
||||
public static class ShowWifiToCellularPopup extends Event {
|
||||
}
|
||||
|
||||
public static class ShowSwitchCameraTooltip extends Event {
|
||||
}
|
||||
|
||||
public static class DismissSwitchCameraTooltip extends Event {
|
||||
}
|
||||
|
||||
public static class StartCall extends Event {
|
||||
private final boolean isVideoCall;
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ public final class WebRtcControls {
|
||||
}
|
||||
|
||||
public boolean displayOverflow() {
|
||||
return FeatureFlags.groupCallReactions() && isAtLeastOutgoing();
|
||||
return FeatureFlags.groupCallReactions() && isAtLeastOutgoing() && hasAtLeastOneRemote && isGroupCall();
|
||||
}
|
||||
|
||||
public boolean displayMuteAudio() {
|
||||
@@ -173,7 +173,7 @@ public final class WebRtcControls {
|
||||
}
|
||||
|
||||
public boolean displayCameraToggle() {
|
||||
return (isPreJoin() || isAtLeastOutgoing()) && isLocalVideoEnabled && isMoreThanOneCameraAvailable;
|
||||
return (isPreJoin() || (isAtLeastOutgoing() && !hasAtLeastOneRemote)) && isLocalVideoEnabled && isMoreThanOneCameraAvailable;
|
||||
}
|
||||
|
||||
public boolean displayRemoteVideoRecycler() {
|
||||
|
||||
@@ -15,7 +15,7 @@ public class TooltipValues extends SignalStoreValues {
|
||||
private static final String MULTI_FORWARD_DIALOG = "tooltip.multi.forward.dialog";
|
||||
private static final String BUBBLE_OPT_OUT = "tooltip.bubble.opt.out";
|
||||
private static final String PROFILE_SETTINGS_QR_CODE = "tooltip.profile_settings_qr_code";
|
||||
|
||||
private static final String CALLING_SWITCH_CAMERA = "tooltip.calling.switch_camera";
|
||||
|
||||
TooltipValues(@NonNull KeyValueStore store) {
|
||||
super(store);
|
||||
@@ -82,4 +82,12 @@ public class TooltipValues extends SignalStoreValues {
|
||||
public void markProfileSettingsQrCodeTooltipSeen() {
|
||||
putBoolean(PROFILE_SETTINGS_QR_CODE, false);
|
||||
}
|
||||
|
||||
public boolean showCallingSwitchCameraTooltip() {
|
||||
return getBoolean(CALLING_SWITCH_CAMERA, true);
|
||||
}
|
||||
|
||||
public void markCallingSwitchCameraTooltipSeen() {
|
||||
putBoolean(CALLING_SWITCH_CAMERA, false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user