Suspend the orientation lock while the Duo hinge is open

The in-app orientation lock pinned the player to the orientation it
opened in even where programmatic rotation is refused, so rotating the
half-open device did nothing. OrientationManager now ignores lock
requests and drops the current lock while canRotateProgrammatically is
false. The YATTEE_FORCE_TABLETOP override only applies on the interior
display size and flags the same state, matching a real .partiallyOpen
hinge instead of forcing the layout on the folded exterior display.
This commit is contained in:
Arkadiusz Fal
2026-10-01 22:35:47 +02:00
parent 83895a1fd9
commit 40267573a9
2 changed files with 29 additions and 4 deletions

View File

@@ -16,11 +16,24 @@ struct HingeLayoutObserver: ViewModifier {
/// Debug override: launch with `YATTEE_FORCE_TABLETOP=1` to force the
/// tabletop layout on simulators without a hinge control.
private static let forceTabletop = ProcessInfo.processInfo.environment["YATTEE_FORCE_TABLETOP"] == "1"
static let forceTabletop = ProcessInfo.processInfo.environment["YATTEE_FORCE_TABLETOP"] == "1"
func body(content: Content) -> some View {
if Self.forceTabletop {
content.onAppear { isTabletop = true }
// The override stands in for a half-open hinge, which only exists
// on the interior display: folded (exterior, 466×678) keeps the
// regular layout, like the real `.closed` state would.
content.onGeometryChange(for: Bool.self) { proxy in
min(proxy.size.width, proxy.size.height) >= ExpandedPlayerSheet.minHeightForCornerLayout
} action: { isInterior in
// Mirror the real hinge state: no programmatic rotation (and no
// orientation lock) while the hinge is open.
OrientationManager.shared.canRotateProgrammatically = !isInterior
guard isInterior != isTabletop else { return }
withAnimation(.easeInOut(duration: 0.3)) {
isTabletop = isInterior
}
}
} else if #available(iOS 27.1, *) {
content.onHingeChange { _, context in
// `hinge` is nil on devices without a hinge and when the view