From 40f86fa6390a243929c200e03aa1dc8b2d510a21 Mon Sep 17 00:00:00 2001 From: Vance <40771709+vancez@users.noreply.github.com> Date: Sun, 15 Feb 2026 14:52:27 +0800 Subject: [PATCH] fix(mobile): account for safe area padding in canvas size calculation (#14285) * fix(mobile): account for safe area padding in canvas size calculation * fix(mobile): differentiate safe area handling for portrait vs landscape * refact(ios): Simple refactor Signed-off-by: fufesou * fix(ios): canvas getSize, test -> Android Signed-off-by: fufesou * fix: comments Signed-off-by: fufesou --------- Signed-off-by: fufesou Co-authored-by: fufesou --- flutter/lib/models/model.dart | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 7a3f98377..ff298c380 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -2215,10 +2215,32 @@ class CanvasModel with ChangeNotifier { double w = size.width - leftToEdge - rightToEdge; double h = size.height - topToEdge - bottomToEdge; if (isMobile) { + // Account for horizontal safe area insets on both orientations. + w = w - mediaData.padding.left - mediaData.padding.right; + // Vertically, subtract the bottom keyboard inset (viewInsets.bottom) and any + // bottom overlay (e.g. key-help tools) so the canvas is not covered. h = h - mediaData.viewInsets.bottom - (parent.target?.cursorModel.keyHelpToolsRectToAdjustCanvas?.bottom ?? 0); + // Orientation-specific handling: + // - Portrait: additionally subtract top padding (e.g. status bar / notch) + // - Landscape: does not subtract mediaData.padding.top/bottom (home indicator auto-hides) + final isPortrait = size.height > size.width; + if (isPortrait) { + // In portrait mode, subtract the top safe-area padding (e.g. status bar / notch) + // so the remote image is not truncated, while keeping the bottom inset to avoid + // introducing unnecessary blank space around the canvas. + // + // iOS -> Android, portrait, adjust mode: + // h = h (no padding subtracted): top and bottom are truncated + // https://github.com/user-attachments/assets/30ed4559-c27e-432b-847f-8fec23c9f998 + // h = h - top - bottom: extra blank spaces appear + // https://github.com/user-attachments/assets/12a98817-3b4e-43aa-be0f-4b03cf364b7e + // h = h - top (current): works fine + // https://github.com/user-attachments/assets/95f047f2-7f47-4a36-8113-5023989a0c81 + h = h - mediaData.padding.top; + } } return Size(w < 0 ? 0 : w, h < 0 ? 0 : h); }