Skip to content

Size from the window, not the screen - #1635

Merged
GianniCarlo merged 1 commit into
developfrom
fix/duo-uiscreen-main
Oct 11, 2026
Merged

GianniCarlo merged 1 commit into
developfrom
fix/duo-uiscreen-main

Conversation

@GianniCarlo

Copy link
Copy Markdown
Collaborator

Problem

Four places size or place things from UIScreen.main, which is the whole display. The app's window can be smaller than that: in Split View on iPad, and on iPhone Duo, where the window also resizes when the phone opens or closes. Apple's iPhone Duo guidance is to stop using UIScreen.main (it's ambiguous on a two-display device and is headed for deprecation) and read the window, the scene or the view instead.

Changes

  • LoadingUtils: the blocking spinner centers on its window instead of the screen, with flexible margins so it stays centered when the window resizes. Blocking is unchanged (the window's interaction is turned off, as before).
  • ButtonFreeView: the trailing-edge exclusion for swipes uses the gesture area's measured width (onGeometryChange) instead of the screen's.
  • ConfettiView: the emitter lays itself out from its own bounds in layoutSubviews, with implicit animations off so it doesn't slide in from its old frame.
  • PlayerView: the swipe-to-dismiss threshold uses the view's displayScale instead of UIScreen.main.nativeScale. Same value on a standard iPhone at default zoom (132pt at 3x).

Left as is on purpose: the theme's brightness and light/dark reads (ThemeManager, SettingsThemesView) and the share extension, which don't affect layout.

Testing

  • Built for the simulator and installed on an iPhone 17.
  • On device: the player's swipe-to-dismiss and button-free mode feel the same, and the confetti covers the screen. The spinner's blocking code isn't touched.

Four spots placed or sized things from UIScreen.main, which is the whole
display. The app's window can be smaller than that: in Split View, and on
iPhone Duo, where it also resizes when the phone opens or closes. They now
read the window or the view instead:

- The UIKit loading spinner centers on its window and stays centered when
  the window resizes. Blocking (window interaction off) is unchanged.
- Button-free mode's trailing-edge exclusion uses the gesture area's width.
- The confetti emitter spans its own view and follows it when it resizes.
- The player's swipe-to-dismiss threshold uses the view's displayScale,
  the same value as before on a standard iPhone at the default zoom.

The other UIScreen.main reads (theme brightness and light/dark, the share
extension) don't affect layout and stay as they are.
@github-actions

Copy link
Copy Markdown

✅ Claude PR Review — PASS

This PR stops sizing four layout spots from UIScreen.main and uses the window or the view instead: the LoadingUtils spinner, the ButtonFreeView trailing-edge swipe exclusion, the ConfettiView emitter and the PlayerView swipe-to-dismiss threshold. I checked each change against its surrounding code and callers.

  • Spinner: loadAndBlock already passes the window, so nothing changes there. Without a window, the spinner now centers on parentView's own bounds, which is more correct than the old screen center in local coordinates. The flexible autoresizing margins keep it centered when the window resizes. Blocking and unblocking (isUserInteractionEnabled, tag lookup) are untouched.
  • Swipe exclusion: onGeometryChange sits on the same ZStack as the .local DragGesture, so the measured width uses the same coordinates as startLocation. The .infinity starting value safely means no trailing exclusion until the first measurement. The deployment target (26.0) is well above the API's minimum.
  • Confetti: EmitterView adds the emitter layer once in init, and layoutSubviews updates position and size inside a transaction with animations turned off. The layer's coordinates match what the old code used.
  • Dismiss threshold: displayScale gives the same value as nativeScale at default zoom and differs only slightly under Display Zoom.

The PR doesn't touch concurrency, the player or AVAudioSession lifecycle, CoreData/SwiftData, or auth/entitlement. All changes are main-thread UI code with no new closures that could hold on to objects.

Findings: no findings

Converged: nothing new this round, and no earlier finding is open.

Model claude-opus-5-5 · run log · 0 new · 0 carried over · 0 resolved · advisory (a human should still review). Findings are de-duplicated across pushes; an earlier finding closes only when the verification pass judges it against the current code — fixed, no longer applicable, accepted by a maintainer, or a duplicate of a finding reported on this push.

@GianniCarlo
GianniCarlo merged commit 5415a28 into develop Oct 11, 2026
3 checks passed
@GianniCarlo
GianniCarlo deleted the fix/duo-uiscreen-main branch October 11, 2026 20:26

This branch was successfully deployed

1 active deployment
reviewer — d4c78266 Deployed Oct 11, 2026 by GianniCarlo via review #248
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant