Skip to content

Commit 821a94b

Browse files
isaacclaude
andcommitted
iPhone Duo: story camera and editor clear the home indicator
On the folded screen (466x678) the 9:16 preview is 150pt taller than the screen, so the camera and editor take their compact bottom layout, whose offsets were tuned for home-button phones (the only other phones whose preview overflows). Measured from the screen edge they put the camera's mode selector, gallery and flip buttons, and the editor's bar, on the home indicator (layout.intrinsicInsets.bottom, 20pt; the Duo's safeInsets.bottom is 0). - Camera: the bottom inset is at least the home indicator's (phones only). Every other phone has more room than that below the preview, so only the Duo changes. The collage reorder hint stays below the preview, as before. - Editor: the bar sits 62pt above the indicator instead of the edge. The drawing screen's bar keeps matching it (rows above move up with it), and the sticker frame helper, shared with the cut-out screen, keeps its bottom limit in step. Beside the unfolded status island the bar still mirrors the top row, which already clears the indicator. Checked on the Duo simulator, folded portrait: camera bottom row and shutter 20pt higher, editor and drawing bars end at about 649pt, above the indicator at about 669pt. Sticker editor not checked on screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 721b0e7 commit 821a94b

5 files changed

Lines changed: 41 additions & 10 deletions

File tree

‎docs/iphone-duo-layout.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ These are the user's decisions; a screen that follows them is correct, one that
112112
- `UIScreen.main` used for layout while unfolded.
113113
- `widthClass == .regular` treated as iPad.
114114
- A 9:16 preview taller than the screen (UP, FP) leaving negative space below it for the bottom controls.
115+
- A bottom row lifted by a constant tuned for home-button phones, until the Duo the only phones whose 9:16 preview is
116+
taller than the screen: measured from the screen edge, it lands on the home indicator. The indicator is
117+
`layout.intrinsicInsets.bottom` (20pt); the Duo's `safeInsets.bottom` is 0. The story camera keeps its controls above
118+
it; the editor's bar, the drawing screen's and the sticker frame sit 62pt above it on the folded screen. Beside the
119+
unfolded island the bar mirrors the top row, which already clears it.
115120
- Something parked just past the content's edge, off-screen on a phone, shows in the strip beside a band: the story
116121
viewer's resting cube neighbours sat 40pt into FP's strip. Clip to the band (the stories turn the clip off while
117122
opening and closing, which can start or end at an avatar in the strip).

‎submodules/DrawingUI/Sources/DrawingScreen.swift‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,11 @@ private final class DrawingScreenComponent: CombinedComponent {
11791179
let mirroredControlsBottomInset = -(environment.statusBarHeight + 31.0 + 30.0)
11801180
bottomPanelLift = max(0.0, controlsBottomInset - mirroredControlsBottomInset)
11811181
controlsBottomInset -= bottomPanelLift
1182+
} else {
1183+
// Elsewhere (folded) the editor's bar is 62pt above the home indicator; so is this one, and the rows
1184+
// above it move up with it.
1185+
bottomPanelLift = environment.safeInsets.bottom
1186+
controlsBottomInset -= bottomPanelLift
11821187
}
11831188
}
11841189
let previewBottomInset = max(0.0, unclampedPreviewBottomInset)

‎submodules/TelegramUI/Components/CameraScreen/Sources/CameraScreen.swift‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,8 +2139,10 @@ private final class CameraScreenComponent: CombinedComponent {
21392139
availableSize: CGSize(width: availableSize.width - 32.0, height: availableSize.height),
21402140
transition: context.transition
21412141
)
2142+
// Below the viewfinder, not above the bottom inset, which can be the home indicator's (iPhone Duo): a viewfinder
2143+
// taller than the screen leaves no room for the hint, and it stays off screen as on home-button phones.
21422144
context.add(collageReorderHint
2143-
.position(CGPoint(x: availableSize.width / 2.0, y: availableSize.height - environment.safeInsets.bottom + 16.0 + collageReorderHint.size.height / 2.0))
2145+
.position(CGPoint(x: availableSize.width / 2.0, y: environment.safeInsets.top + previewHeight + 16.0 + collageReorderHint.size.height / 2.0))
21442146
.appear(.default(alpha: true))
21452147
.disappear(.default(alpha: true))
21462148
)
@@ -3747,7 +3749,13 @@ public class CameraScreenImpl: ViewController, CameraScreen {
37473749
}
37483750
// Clamped like the story editor's: a 9:16 viewfinder much taller than the screen (iPhone Duo's unfolded
37493751
// screen in portrait, 238pt over) would otherwise put the bottom controls below the screen.
3750-
let bottomInset = max(0.0, layout.size.height - previewSize.height - topInset)
3752+
var bottomInset = max(0.0, layout.size.height - previewSize.height - topInset)
3753+
if !isTablet {
3754+
// The bottom controls stay above the home indicator. Below a 9:16 viewfinder that fits there is always more
3755+
// room than the indicator takes; one taller than the screen leaves none, which until iPhone Duo only
3756+
// happened on home-button phones (its folded screen, 150pt over, put the mode selector on the indicator).
3757+
bottomInset = max(bottomInset, layout.intrinsicInsets.bottom)
3758+
}
37513759

37523760
let panelWidth: CGFloat
37533761
let previewFrame: CGRect

‎submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaCutoutScreen.swift‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,25 @@ private final class MediaCutoutScreenComponent: Component {
2424

2525
let context: AccountContext
2626
let mediaEditor: MediaEditor
27+
let homeIndicatorInset: CGFloat
2728

2829
init(
2930
context: AccountContext,
30-
mediaEditor: MediaEditor
31+
mediaEditor: MediaEditor,
32+
homeIndicatorInset: CGFloat
3133
) {
3234
self.context = context
3335
self.mediaEditor = mediaEditor
36+
self.homeIndicatorInset = homeIndicatorInset
3437
}
3538

3639
static func ==(lhs: MediaCutoutScreenComponent, rhs: MediaCutoutScreenComponent) -> Bool {
3740
if lhs.context !== rhs.context {
3841
return false
3942
}
43+
if lhs.homeIndicatorInset != rhs.homeIndicatorInset {
44+
return false
45+
}
4046
return true
4147
}
4248

@@ -430,7 +436,7 @@ private final class MediaCutoutScreenComponent: Component {
430436
// whole screen (iPhone Duo) that is not the visible area: it starts at the top, 44pt higher on a screen
431437
// under 680pt, as in the editor's sticker mode.
432438
var overlayFrame = previewContainerFrame
433-
if !isTablet, let stickerPreviewFrame = mediaEditorStickerPreviewFrame(screenSize: availableSize, safeInsets: environment.safeInsets, reservedCorners: environment.reservedCorners, statusBarHeight: environment.statusBarHeight, hasStatusIsland: environment.navigationBarTrailingButtonsInset > 0.0) {
439+
if !isTablet, let stickerPreviewFrame = mediaEditorStickerPreviewFrame(screenSize: availableSize, safeInsets: environment.safeInsets, reservedCorners: environment.reservedCorners, statusBarHeight: environment.statusBarHeight, hasStatusIsland: environment.navigationBarTrailingButtonsInset > 0.0, homeIndicatorInset: component.homeIndicatorInset) {
434440
// iPhone Duo: the editor's narrowed sticker preview.
435441
overlayFrame = stickerPreviewFrame
436442
} else if previewSize.height > availableSize.height + 30.0 {
@@ -608,7 +614,8 @@ final class MediaCutoutScreen: ViewController {
608614
component: AnyComponent(
609615
MediaCutoutScreenComponent(
610616
context: self.context,
611-
mediaEditor: controller.mediaEditor
617+
mediaEditor: controller.mediaEditor,
618+
homeIndicatorInset: layout.intrinsicInsets.bottom
612619
)
613620
),
614621
environment: {

‎submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,17 @@ import MediaAssetsContext
6464
/// preview is narrowed and placed with the frame in that space. The sticker is the canvas-centred square either way, so
6565
/// only the preview's scale changes. Returns the preview's frame on iPhone Duo (reserved corners), nil elsewhere, where
6666
/// the usual placement is kept.
67-
func mediaEditorStickerPreviewFrame(screenSize: CGSize, safeInsets: UIEdgeInsets, reservedCorners: ContainerViewLayoutCorners, statusBarHeight: CGFloat, hasStatusIsland: Bool) -> CGRect? {
67+
func mediaEditorStickerPreviewFrame(screenSize: CGSize, safeInsets: UIEdgeInsets, reservedCorners: ContainerViewLayoutCorners, statusBarHeight: CGFloat, hasStatusIsland: Bool, homeIndicatorInset: CGFloat) -> CGRect? {
6868
if reservedCorners == .none {
6969
return nil
7070
}
7171
let frameFraction: CGFloat = 0.97
7272
let spaceAboveFrame: CGFloat = 35.0 + 40.0
7373
let spaceBelowFrame: CGFloat = 35.0 + 40.0 + 16.0 + 40.0
7474
// The bottom bar's buttons start 8pt above where the editor's controls inset puts them (see the component's
75-
// `controlsBottomInset`: mirrored on the status island's clock line beside the island, 62pt up otherwise).
76-
let controlsBottomInset: CGFloat = hasStatusIsland ? -(statusBarHeight + 31.0 + 30.0) : -62.0
75+
// `controlsBottomInset`: mirrored on the status island's clock line beside the island, 62pt above the home
76+
// indicator otherwise).
77+
let controlsBottomInset: CGFloat = hasStatusIsland ? -(statusBarHeight + 31.0 + 30.0) : -62.0 - homeIndicatorInset
7778
let bottomLimit = screenSize.height + 8.0 + controlsBottomInset - 8.0
7879
let topLimit = statusBarHeight + 8.0
7980
let available = bottomLimit - topLimit
@@ -867,6 +868,11 @@ final class MediaEditorScreenComponent: Component {
867868
// Beside a status island the bottom bar mirrors the top row (see topRowY): its 44pt buttons
868869
// centred compact status height + 31 above the bottom edge, as the drawing screen's are.
869870
controlsBottomInset = min(controlsBottomInset, -(environment.statusBarHeight + 31.0 + 30.0))
871+
} else {
872+
// Elsewhere 62pt above the home indicator. The 62pt was set for home-button phones, the only phones
873+
// with a preview taller than the screen until iPhone Duo, whose folded screen it left with the
874+
// buttons on the indicator.
875+
controlsBottomInset -= component.bottomSafeInset
870876
}
871877
// Beside a status island the bottom buttons keep the top rows' 16pt side inset; so do they on the folded
872878
// screen, whose outer corners (59pt) would clip a button 9pt from the edge (iPhone Duo).
@@ -886,7 +892,7 @@ final class MediaEditorScreenComponent: Component {
886892
// The sticker frame's buttons centre on the frame, which beside a side strip is the band's centre, not the screen's
887893
// (iPhone Duo folded: an erase and restore pair centred on the screen reached 16pt into the strip).
888894
var stickerButtonsCenterX: CGFloat = availableSize.width / 2.0
889-
if !isTablet, case .stickerEditor = controller.mode, let stickerPreviewFrame = mediaEditorStickerPreviewFrame(screenSize: availableSize, safeInsets: environment.safeInsets, reservedCorners: environment.reservedCorners, statusBarHeight: environment.statusBarHeight, hasStatusIsland: environment.navigationBarTrailingButtonsInset > 0.0) {
895+
if !isTablet, case .stickerEditor = controller.mode, let stickerPreviewFrame = mediaEditorStickerPreviewFrame(screenSize: availableSize, safeInsets: environment.safeInsets, reservedCorners: environment.reservedCorners, statusBarHeight: environment.statusBarHeight, hasStatusIsland: environment.navigationBarTrailingButtonsInset > 0.0, homeIndicatorInset: component.bottomSafeInset) {
890896
// iPhone Duo: see `mediaEditorStickerPreviewFrame` (the node places the preview the same way).
891897
previewSize = stickerPreviewFrame.size
892898
previewFrame = stickerPreviewFrame
@@ -6122,7 +6128,7 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
61226128
// `mediaEditorStickerPreviewFrame`; the component places them the same way). The insets above stay those of
61236129
// the full-width preview, so the bottom bar keeps its place.
61246130
var stickerPreviewOrigin: CGPoint?
6125-
if !isTablet, case .stickerEditor = controller.mode, let stickerPreviewFrame = mediaEditorStickerPreviewFrame(screenSize: layout.size, safeInsets: layout.safeInsets, reservedCorners: layout.reservedCorners, statusBarHeight: layout.navigationBarStatusBarHeight ?? 0.0, hasStatusIsland: layout.navigationBarTrailingButtonsInset > 0.0) {
6131+
if !isTablet, case .stickerEditor = controller.mode, let stickerPreviewFrame = mediaEditorStickerPreviewFrame(screenSize: layout.size, safeInsets: layout.safeInsets, reservedCorners: layout.reservedCorners, statusBarHeight: layout.navigationBarStatusBarHeight ?? 0.0, hasStatusIsland: layout.navigationBarTrailingButtonsInset > 0.0, homeIndicatorInset: layout.intrinsicInsets.bottom) {
61266132
previewSize = stickerPreviewFrame.size
61276133
stickerPreviewOrigin = stickerPreviewFrame.origin
61286134
}

0 commit comments

Comments
 (0)