mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-04 13:02:39 +08:00
[fix] correct mobile viewport safe areas and zoom reset
This commit is contained in:
@@ -34,7 +34,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen
|
|||||||
private View settingsUpdateDot, aboutUpdateDot, settingsUpdateButton, aboutUpdateRow;
|
private View settingsUpdateDot, aboutUpdateDot, settingsUpdateButton, aboutUpdateRow;
|
||||||
private TextView aboutUpdateLabel;
|
private TextView aboutUpdateLabel;
|
||||||
private boolean navigatingBack;
|
private boolean navigatingBack;
|
||||||
private FrameLayout canvas;
|
private FrameLayout canvas, safeArea;
|
||||||
private LinearLayout root;
|
private LinearLayout root;
|
||||||
private EditText remote;
|
private EditText remote;
|
||||||
private TextView status, signalBadge, identitySummary;
|
private TextView status, signalBadge, identitySummary;
|
||||||
@@ -133,10 +133,11 @@ public final class MainActivity extends Activity implements NativeSession.Listen
|
|||||||
settingsUpdateDot=null;aboutUpdateDot=null;settingsUpdateButton=null;aboutUpdateRow=null;aboutUpdateLabel=null;
|
settingsUpdateDot=null;aboutUpdateDot=null;settingsUpdateButton=null;aboutUpdateRow=null;aboutUpdateLabel=null;
|
||||||
previewSwitch=null;clearPreviewsButton=null;previewCleanupError=null;previewCards.clear();recentGrid=null;
|
previewSwitch=null;clearPreviewsButton=null;previewCleanupError=null;previewCards.clear();recentGrid=null;
|
||||||
canvas=new FrameLayout(this);canvas.setBackgroundColor(dark?Color.BLACK:BACKGROUND);
|
canvas=new FrameLayout(this);canvas.setBackgroundColor(dark?Color.BLACK:BACKGROUND);
|
||||||
FrameLayout safeArea=new FrameLayout(this);canvas.addView(safeArea,new FrameLayout.LayoutParams(-1,-1));
|
safeArea=new FrameLayout(this);canvas.addView(safeArea,new FrameLayout.LayoutParams(-1,-1));
|
||||||
root=ui.pageColumn(dark?0:nextPage.equals("home")?1200:720);
|
root=ui.pageColumn(dark?0:nextPage.equals("home")?1200:720);
|
||||||
safeArea.addView(root,new FrameLayout.LayoutParams(-1,-1,Gravity.TOP|Gravity.CENTER_HORIZONTAL));
|
safeArea.addView(root,new FrameLayout.LayoutParams(-1,-1,Gravity.TOP|Gravity.CENTER_HORIZONTAL));
|
||||||
safeArea.setOnApplyWindowInsetsListener((view,insets)->{
|
safeArea.setOnApplyWindowInsetsListener((view,insets)->{
|
||||||
|
if(dark&&(pictureInPictureUi||isInPictureInPictureMode())){view.setPadding(0,0,0,0);return insets;}
|
||||||
if(dark&&android.os.Build.VERSION.SDK_INT>=30){
|
if(dark&&android.os.Build.VERSION.SDK_INT>=30){
|
||||||
android.graphics.Insets bars=insets.getInsets(WindowInsets.Type.systemBars()|WindowInsets.Type.displayCutout());
|
android.graphics.Insets bars=insets.getInsets(WindowInsets.Type.systemBars()|WindowInsets.Type.displayCutout());
|
||||||
view.setPadding(bars.left,bars.top,bars.right,bars.bottom);
|
view.setPadding(bars.left,bars.top,bars.right,bars.bottom);
|
||||||
@@ -328,7 +329,10 @@ public final class MainActivity extends Activity implements NativeSession.Listen
|
|||||||
dialog.setContentView(card);dialog.setCanceledOnTouchOutside(false);dialog.setOnCancelListener(d->end(""));Window w=dialog.getWindow();if(w!=null){w.setBackgroundDrawableResource(android.R.color.transparent);w.setDimAmount(.08f);}dialog.show();if(w!=null)w.setLayout(dp(292),-2);
|
dialog.setContentView(card);dialog.setCanceledOnTouchOutside(false);dialog.setOnCancelListener(d->end(""));Window w=dialog.getWindow();if(w!=null){w.setBackgroundDrawableResource(android.R.color.transparent);w.setDimAmount(.08f);}dialog.show();if(w!=null)w.setLayout(dp(292),-2);
|
||||||
}
|
}
|
||||||
private void sessionScreen(boolean autoLandscape){
|
private void sessionScreen(boolean autoLandscape){
|
||||||
installRoot("session",true);remoteOrientation.begin(autoLandscape,!isTablet()&&!isInMultiWindowMode());video=new RemoteVideoView(this,session);video.setRelative(preferences.getBoolean("relativeMouse",true));canvas.addView(video,0,new FrameLayout.LayoutParams(-1,-1));
|
installRoot("session",true);remoteOrientation.begin(autoLandscape,!isTablet()&&!isInMultiWindowMode());video=new RemoteVideoView(this,session);video.setRelative(preferences.getBoolean("relativeMouse",true));
|
||||||
|
// Video, cursor and touch input must share the area inside system bars
|
||||||
|
// and display cutouts; fitting to the outer canvas hides image edges.
|
||||||
|
safeArea.addView(video,0,new FrameLayout.LayoutParams(-1,-1));
|
||||||
controls=new SessionControls(this,ui,new SessionControls.Actions(){
|
controls=new SessionControls(this,ui,new SessionControls.Actions(){
|
||||||
public void disconnect(){confirmDisconnect();}public void display(){selectDisplay();}public void clipboard(){MainActivity.this.clipboard();}
|
public void disconnect(){confirmDisconnect();}public void display(){selectDisplay();}public void clipboard(){MainActivity.this.clipboard();}
|
||||||
public void sendFile(){chooseFile();}public void saveFile(){saveReceivedFile();}public void secureAttention(){MainActivity.this.secureAttention();}
|
public void sendFile(){chooseFile();}public void saveFile(){saveReceivedFile();}public void secureAttention(){MainActivity.this.secureAttention();}
|
||||||
@@ -803,6 +807,7 @@ public final class MainActivity extends Activity implements NativeSession.Listen
|
|||||||
if(value){releaseKeys();hideKeyboard();pageHost.finish();if(disconnectDialog!=null)disconnectDialog.dismiss();if(remoteUpdateDialog!=null)remoteUpdateDialog.dismiss();}
|
if(value){releaseKeys();hideKeyboard();pageHost.finish();if(disconnectDialog!=null)disconnectDialog.dismiss();if(remoteUpdateDialog!=null)remoteUpdateDialog.dismiss();}
|
||||||
if(controls!=null)controls.setPictureInPicture(value);
|
if(controls!=null)controls.setPictureInPicture(value);
|
||||||
if(video!=null)video.setPictureInPicture(value);
|
if(video!=null)video.setPictureInPicture(value);
|
||||||
|
if(safeArea!=null)safeArea.requestApplyInsets();
|
||||||
}
|
}
|
||||||
@Override protected void onUserLeaveHint(){
|
@Override protected void onUserLeaveHint(){
|
||||||
super.onUserLeaveHint();
|
super.onUserLeaveHint();
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ final class RemoteViewport {
|
|||||||
void zoomBy(float factor, float focusX, float focusY) {
|
void zoomBy(float factor, float focusX, float focusY) {
|
||||||
if (baseWidth == 0 || baseHeight == 0 || !Float.isFinite(factor) || factor <= 0) return;
|
if (baseWidth == 0 || baseHeight == 0 || !Float.isFinite(factor) || factor <= 0) return;
|
||||||
float nextScale = clamp(scale * factor, 1, MAXIMUM_SCALE);
|
float nextScale = clamp(scale * factor, 1, MAXIMUM_SCALE);
|
||||||
|
// Returning to fit must clear cursor-edge panning too, including a
|
||||||
|
// pinch that starts at 1x with an already shifted image.
|
||||||
|
if (nextScale == 1) { reset(); return; }
|
||||||
float ratio = nextScale / scale;
|
float ratio = nextScale / scale;
|
||||||
float focusFromCenterX = focusX - (baseLeft + baseWidth / 2f);
|
float focusFromCenterX = focusX - (baseLeft + baseWidth / 2f);
|
||||||
float focusFromCenterY = focusY - (baseTop + baseHeight / 2f);
|
float focusFromCenterY = focusY - (baseTop + baseHeight / 2f);
|
||||||
@@ -75,10 +78,9 @@ final class RemoteViewport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void finishGesture() {
|
void finishGesture() {
|
||||||
if (!isZoomed()) {
|
// Ordinary pointer gestures at 1x retain edge panning. Only a zoom
|
||||||
scale = 1;
|
// snapping back to its minimum restores the complete centered image.
|
||||||
constrainOffset();
|
if (scale > 1 && !isZoomed()) reset();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() { scale = 1; offsetX = offsetY = 0; edgePanned = false; }
|
void reset() { scale = 1; offsetX = offsetY = 0; edgePanned = false; }
|
||||||
|
|||||||
@@ -384,6 +384,15 @@ final class RemoteTouchSurface: UIView, UIGestureRecognizerDelegate {
|
|||||||
let newScale = min(max(oldScale * recognizer.scale, 1),
|
let newScale = min(max(oldScale * recognizer.scale, 1),
|
||||||
maximumViewportScale)
|
maximumViewportScale)
|
||||||
recognizer.scale = 1
|
recognizer.scale = 1
|
||||||
|
if newScale == 1 {
|
||||||
|
// Pinching back to fit also ends any cursor-edge pan, even
|
||||||
|
// when the gesture starts at 1x with an off-center image.
|
||||||
|
viewportScale = 1
|
||||||
|
viewportOffset = .zero
|
||||||
|
edgePanned = false
|
||||||
|
publishViewport()
|
||||||
|
return
|
||||||
|
}
|
||||||
guard abs(newScale - oldScale) > 0.0001 else { return }
|
guard abs(newScale - oldScale) > 0.0001 else { return }
|
||||||
|
|
||||||
let center = CGPoint(x: bounds.midX, y: bounds.midY)
|
let center = CGPoint(x: bounds.midX, y: bounds.midY)
|
||||||
@@ -402,7 +411,8 @@ final class RemoteTouchSurface: UIView, UIGestureRecognizerDelegate {
|
|||||||
pinchActive = false
|
pinchActive = false
|
||||||
if viewportScale <= 1.001 {
|
if viewportScale <= 1.001 {
|
||||||
viewportScale = 1
|
viewportScale = 1
|
||||||
viewportOffset = constrainedViewportOffset(viewportOffset, scale: 1)
|
viewportOffset = .zero
|
||||||
|
edgePanned = false
|
||||||
publishViewport()
|
publishViewport()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -140,8 +140,11 @@ struct RemoteSessionView: View {
|
|||||||
|
|
||||||
}
|
}
|
||||||
.frame(width: proxy.size.width, height: proxy.size.height)
|
.frame(width: proxy.size.width, height: proxy.size.height)
|
||||||
|
.clipped()
|
||||||
}
|
}
|
||||||
.ignoresSafeArea()
|
// Fit video and input to the same unobscured area. Only the black
|
||||||
|
// background extends beneath the home indicator and display cutout.
|
||||||
|
.ignoresSafeArea(.keyboard)
|
||||||
.transaction { transaction in
|
.transaction { transaction in
|
||||||
transaction.animation = nil
|
transaction.animation = nil
|
||||||
transaction.disablesAnimations = true
|
transaction.disablesAnimations = true
|
||||||
|
|||||||
Reference in New Issue
Block a user