View Issue Details
| ID | Project | Category | View Status | Date Submitted | Last Update |
|---|---|---|---|---|---|
| 0011954 | Taler | wallet (iOS App) | public | 2026-11-05 15:12 | 2026-11-05 15:12 |
| Reporter | bot-cg [agent] | Assigned To | Resolution deadline | ||
| Implementer | Reviewer | ||||
| Release signed by | Deployed by | ||||
| Verifier | Communicator | CM_7 | |||
| Data protection authority notification required | No | ||||
| CSIRT notification required | No | ||||
| Estimated effort (hours) | Actual effort (hours) | 0 | |||
| Fast-track | No | ||||
| Work package | none | ||||
| Priority | normal | Severity | minor | Reproducibility | always |
| Status | new | Resolution | open | ||
| Summary | 0011954: OIM never appears when the app is launched already in landscape: the orientation at appear is not reported | ||||
| Description | Start the wallet while already holding the phone in landscape and the OIM presentation never appears. It only shows up after rotating to portrait and back to landscape. Cause ----- `MainView.swift:328` activates OIM from `.onRotate`: .onRotate { newOrientation in controller.setOIMmode(for: newOrientation, isSheetActive) ... } and `TalerCommon/ViewModifier/View+DeviceRotation.swift` only reacts to a change: content .onAppear() // SwiftUI bug: view modifiers do not work with // onReceive() unless you first add onAppear() .onReceive(... UIDevice.orientationDidChangeNotification ...) { _ in action(UIDevice.current.orientation) } That bare `.onAppear()` is a workaround for an unrelated SwiftUI problem and takes no action of its own, so the orientation a view *appears* in is never reported — only later changes are. `Controller.setOIMmode` therefore never runs at launch, `oimModeActive` stays false, and `BalancesListView`/`TransactionsListView` do not add their OIM overlay. Measured -------- An app launched directly into landscapeRight, with a non-empty balances list on screen (`screenSize [874, 402]`, navTitle "Balances"), left every file under `TalerWallet1/Views/OIM/` at 0.0% line coverage — 4,289 instrumented lines, about a tenth of the app, none of it entered. The same build enters OIM normally when the device is rotated after launch. Suggested fix (patch attached) ------------------------------ Report the orientation on appear as well: .onAppear { action(UIDevice.current.orientation) } `MainView` is the only caller of `onRotate`, so nothing else changes behaviour. This also removes the need for the bare `.onAppear()`, since the new one serves the same purpose. Why it matters beyond the missing presentation: this is also what makes the OIM code unreachable for UI automation that launches the app in a fixed orientation, which is how a test harness normally starts it. How to reproduce ---------------- 1. Fresh build of the GNU_Taler scheme (OIM is in its compilation conditions) on an iPhone simulator. 2. Give the wallet a balance so the balances list is non-empty. 3. Put the simulator in landscape *before* launching the app, e.g. `xcrun simctl ui <device> appearance` is not needed -- set the device orientation and then launch. 4. The balances list appears without the OIM overlay. Rotate to portrait and back to landscapeRight: the overlay appears. Filed by an agent (bot-cg) on behalf of Christian Grothoff, from an automated UI exploration campaign. Left unassigned deliberately. | ||||
| Tags | No tags attached. | ||||
| Attached Files | report-orientation-on-appear.diff (1,309 bytes)
diff --git a/TalerCommon/ViewModifier/View+DeviceRotation.swift b/TalerCommon/ViewModifier/View+DeviceRotation.swift
index c059c2a1..d011856b 100644
--- a/TalerCommon/ViewModifier/View+DeviceRotation.swift
+++ b/TalerCommon/ViewModifier/View+DeviceRotation.swift
@@ -32,7 +32,16 @@ struct DeviceRotationViewModifier: ViewModifier {
func body(content: Content) -> some View {
content
- .onAppear() // SwiftUI bug: view modifiers do not work with onReceive() unless you first add onAppear()
+ // SwiftUI bug: view modifiers do not work with onReceive()
+ // unless you first add onAppear().
+ //
+ // Report the orientation the view appears in, too, not only
+ // later changes. Without this a view that is already in
+ // landscape when it appears never hears about it: the app
+ // launched in landscapeRight leaves `oimModeActive` false, so
+ // the OIM presentation is missing until the user rotates away
+ // and back again.
+ .onAppear { action(UIDevice.current.orientation) }
.onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in
action(UIDevice.current.orientation)
}
| ||||