Merge pull request 'fix: back button bounces user back into selected business' (#31) from schwifty/fix-back-button-bounce into main

This commit is contained in:
koda 2026-03-22 22:32:12 +00:00
commit a6ba88803c
4 changed files with 40 additions and 15 deletions

View file

@ -14,6 +14,9 @@ final class AppState: ObservableObject {
@Published var token: String? @Published var token: String?
@Published var userId: String? @Published var userId: String?
/// When true, skip auto-navigation in BusinessListView (user explicitly went back)
var skipAutoNav = false
init() { init() {
// Restore saved session // Restore saved session
if let saved = SecureStorage.loadSession() { if let saved = SecureStorage.loadSession() {
@ -36,6 +39,8 @@ final class AppState: ObservableObject {
} }
func backToBusinessList() { func backToBusinessList() {
AppPrefs.lastBusinessId = nil
skipAutoNav = true
currentScreen = .businessList currentScreen = .businessList
} }

View file

@ -22,6 +22,8 @@
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>NSCameraUsageDescription</key>
<string>Payfrit Beacon needs camera access to scan QR codes on beacon labels for provisioning.</string>
<key>NSBluetoothAlwaysUsageDescription</key> <key>NSBluetoothAlwaysUsageDescription</key>
<string>Payfrit Beacon needs Bluetooth to detect and configure nearby beacons.</string> <string>Payfrit Beacon needs Bluetooth to detect and configure nearby beacons.</string>
<key>NSBluetoothPeripheralUsageDescription</key> <key>NSBluetoothPeripheralUsageDescription</key>

View file

@ -94,18 +94,22 @@ struct BusinessListView: View {
let list = try await APIClient.shared.listBusinesses(token: token) let list = try await APIClient.shared.listBusinesses(token: token)
businesses = list businesses = list
// Auto-navigate if only one business (like Android) // Skip auto-navigation if user explicitly tapped Back
if list.count == 1, let only = list.first { if !appState.skipAutoNav {
appState.selectBusiness(only) // Auto-navigate if only one business (like Android)
return if list.count == 1, let only = list.first {
} appState.selectBusiness(only)
return
}
// Auto-navigate to last used business // Auto-navigate to last used business
if let lastId = AppPrefs.lastBusinessId, if let lastId = AppPrefs.lastBusinessId,
let last = list.first(where: { $0.id == lastId }) { let last = list.first(where: { $0.id == lastId }) {
appState.selectBusiness(last) appState.selectBusiness(last)
return return
}
} }
appState.skipAutoNav = false
} catch let e as APIError where e.errorDescription == APIError.unauthorized.errorDescription { } catch let e as APIError where e.errorDescription == APIError.unauthorized.errorDescription {
appState.logout() appState.logout()
} catch { } catch {

View file

@ -241,17 +241,31 @@ final class CameraPreviewUIView: UIView {
func setFlash(_ on: Bool) { func setFlash(_ on: Bool) {
guard let device = AVCaptureDevice.default(for: .video), guard let device = AVCaptureDevice.default(for: .video),
device.hasTorch else { return } device.hasTorch else { return }
try? device.lockForConfiguration() do {
device.torchMode = on ? .on : .off try device.lockForConfiguration()
device.unlockForConfiguration() device.torchMode = on ? .on : .off
device.unlockForConfiguration()
} catch {
NSLog("[QRScanner] Failed to set torch: \(error.localizedDescription)")
}
} }
private func setupCamera() { private func setupCamera() {
let session = AVCaptureSession() let session = AVCaptureSession()
session.sessionPreset = .high session.sessionPreset = .high
guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back), guard let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
let input = try? AVCaptureDeviceInput(device: device) else { return } NSLog("[QRScanner] ERROR: No back camera available")
return
}
let input: AVCaptureDeviceInput
do {
input = try AVCaptureDeviceInput(device: device)
} catch {
NSLog("[QRScanner] ERROR: Failed to create camera input: \(error.localizedDescription)")
return
}
if session.canAddInput(input) { if session.canAddInput(input) {
session.addInput(input) session.addInput(input)