oficina / meet Public

iPhone: grid fixture, tile backdrop, landscape bar test, upright snapshots

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev c64c1d075b886bb9eb2c24e7151e46e9c095a66e parent f71445d
4 files changed, +29 −8
  • native/ios/Sources/CallsPhone.swift +6 −2
  • native/ios/Sources/PhoneCallFixture.swift +2 −1
  • native/ios/Sources/PhoneFullScreenCall.swift +5 −4
  • native/ios/UITests/CallsPhoneUITests.swift +16 −1
diff --git a/native/ios/Sources/CallsPhone.swift b/native/ios/Sources/CallsPhone.swift
index d1a42e9..0a8521c 100644
--- a/native/ios/Sources/CallsPhone.swift
+++ b/native/ios/Sources/CallsPhone.swift
@@ -128,12 +128,13 @@ struct PhoneCall: View {
init(
call: Call, leave: @escaping () -> Void, style: CallLayoutStyle? = nil,
- controlsShown: Bool? = nil, showingMore: Bool = false
+ controlsShown: Bool? = nil, showingMore: Bool = false, grid: Bool = false
) {
self.call = call
self.leave = leave
self.style = style
_showingMore = State(initialValue: showingMore)
+ _grid = State(initialValue: grid)
_chrome = StateObject(wrappedValue: ControlsVisibilityModel(input: .touch, pinned: controlsShown))
}
@@ -389,9 +390,12 @@ struct PhoneVideoTile: View {
var cornerRadius: CGFloat = 18
var compact = false
var labelInsets = EdgeInsets()
+ /// Behind a picture that is not there: a shade lighter than the stage
+ /// for a tile among others, so it reads as a tile.
+ var backdrop = Color.black
var body: some View {
ZStack {
- Color.black
+ backdrop
if let track, !cameraOff, placeholder == nil {
PhoneVideo(track: track, fit: screen).scaleEffect(x: mirrored ? -1 : 1, y: 1)
} else {
diff --git a/native/ios/Sources/PhoneCallFixture.swift b/native/ios/Sources/PhoneCallFixture.swift
index a128b46..1bcffdc 100644
--- a/native/ios/Sources/PhoneCallFixture.swift
+++ b/native/ios/Sources/PhoneCallFixture.swift
@@ -24,7 +24,8 @@
PhoneCall(
call: call, leave: {},
style: defaults.bool(forKey: "CallsFixtureClassic") ? .classic : .fullWindow,
- controlsShown: pinned, showingMore: defaults.bool(forKey: "CallsFixtureMore"))
+ controlsShown: pinned, showingMore: defaults.bool(forKey: "CallsFixtureMore"),
+ grid: fixture == .grid)
}
.tint(CallsAppearance.accent)
.preferredColorScheme(defaults.bool(forKey: "CallsFixtureDark") ? .dark : .light)
diff --git a/native/ios/Sources/PhoneFullScreenCall.swift b/native/ios/Sources/PhoneFullScreenCall.swift
index f215e40..d904ca1 100644
--- a/native/ios/Sources/PhoneFullScreenCall.swift
+++ b/native/ios/Sources/PhoneFullScreenCall.swift
@@ -14,6 +14,7 @@ extension PhoneCall {
/// The round buttons' size, and the bar's height with its margin.
static let button: CGFloat = 56
static let barHeight: CGFloat = 56 + 16
+ static let tileBackdrop = Color(white: 0.13)
var fullScreen: some View {
GeometryReader { geometry in
@@ -137,21 +138,21 @@ extension PhoneCall {
ForEach(call.screens, id: \.self) { peer in
PhoneVideoTile(
track: call.remoteScreens[peer], label: screenCaption(call.name(of: peer)),
- screen: true, cornerRadius: 8, compact: true
+ screen: true, cornerRadius: 8, compact: true, backdrop: Self.tileBackdrop
)
.frame(width: tile.width, height: tile.height)
}
PhoneVideoTile(
track: call.localTrack, label: "You", muted: call.muted, mirrored: true,
cameraOff: call.cameraOff, placeholder: call.selfPlaceholder, cornerRadius: 8,
- compact: true
+ compact: true, backdrop: Self.tileBackdrop
)
.frame(width: tile.width, height: tile.height)
ForEach(peers) { peer in
PhoneVideoTile(
track: call.remoteTracks[peer.peer], label: peer.name,
muted: call.isMuted(peer.peer), cameraOff: call.isCameraOff(peer.peer),
- cornerRadius: 8, compact: true
+ cornerRadius: 8, compact: true, backdrop: Self.tileBackdrop
)
.frame(width: tile.width, height: tile.height)
}
@@ -178,7 +179,7 @@ extension PhoneCall {
return PhoneVideoTile(
track: call.localTrack, label: "You", muted: call.muted, mirrored: true,
cameraOff: call.cameraOff, placeholder: call.selfPlaceholder, cornerRadius: 14,
- compact: true
+ compact: true, backdrop: Self.tileBackdrop
)
.frame(width: pip.width, height: pip.height)
.overlay(RoundedRectangle(cornerRadius: 14).strokeBorder(.white.opacity(0.2)))
diff --git a/native/ios/UITests/CallsPhoneUITests.swift b/native/ios/UITests/CallsPhoneUITests.swift
index 536da5e..8fde901 100644
--- a/native/ios/UITests/CallsPhoneUITests.swift
+++ b/native/ios/UITests/CallsPhoneUITests.swift
@@ -142,8 +142,11 @@ final class CallsPhoneUITests: XCTestCase {
?? "/tmp/immersive-call")
}
+ /// The screen as the device draws it: upright for portrait, and turned
+ /// a quarter for landscape (straightened afterwards with `sips -r 270`;
+ /// the app's own screenshot crops landscape wrongly on iOS 26).
@MainActor private func snapshot(_ app: XCUIApplication, _ name: String) throws {
- let shot = app.screenshot()
+ let shot = XCUIScreen.main.screenshot()
let attachment = XCTAttachment(screenshot: shot)
attachment.name = name
attachment.lifetime = .keepAlways
@@ -239,4 +242,16 @@ final class CallsPhoneUITests: XCTestCase {
try snapshot(classic, "classic-portrait-\(scheme)")
}
}
+
+ /// Landscape keeps both bar buttons on screen, clear of the Dynamic
+ /// Island's side.
+ @MainActor func testLandscapeKeepsTheBarOnScreen() throws {
+ XCUIDevice.shared.orientation = .landscapeLeft
+ defer { XCUIDevice.shared.orientation = .portrait }
+ let app = launchCall("focus", ["-CallsFixtureControls", "shown"])
+ XCTAssertTrue(app.buttons["leave"].waitForExistence(timeout: 15))
+ XCTAssertTrue(app.buttons["leave"].isHittable)
+ XCTAssertTrue(app.buttons["moreControls"].isHittable)
+ XCTAssertLessThan(app.buttons["moreControls"].frame.midX, app.buttons["leave"].frame.midX)
+ }
}