OTP/OTP/Views/AddQRView.swift

96 lines
2.9 KiB
Swift

//
// AddQRView.swift
// OTP
//
// Created by Shadowfacts on 8/22/21.
//
import SwiftUI
import CodeScanner
import OTPKit
struct AddQRView: View {
let dismiss: (DismissAction) -> Void
@State private var isPresentingScanFailedAlert = false
@State private var scanError: ScanError?
@State private var scannedKey: TOTPKey?
@State private var isShowingConfirmView = false
var body: some View {
NavigationView {
CodeScannerView(codeTypes: [.qr], scanMode: .once) { (result) in
switch result {
case .success(let code):
if let components = URLComponents(string: code),
let key = TOTPKey(urlComponents: components) {
self.scannedKey = key
isShowingConfirmView = true
} else {
isPresentingScanFailedAlert = true
scanError = .invalidCode(code)
}
case .failure(let error):
isPresentingScanFailedAlert = true
scanError = .scanner(error)
}
}
.edgesIgnoringSafeArea(.bottom)
.navigationBarTitle("Scan QR Code", displayMode: .inline)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button("Cancel") {
dismiss(.cancel)
}
}
}
.overlay {
NavigationLink(isActive: $isShowingConfirmView) {
EditKeyForm(editingKey: scannedKey, showCancelButton: false, dismiss: dismiss)
.navigationTitle("Add Key")
} label: {
// EmptyView because this is only used to trigger programatic navigation
EmptyView()
}
}
}
.alert("Unable to get OTP key from QR code", isPresented: $isPresentingScanFailedAlert) {
Button("Cancel", role: .cancel) {
dismiss(.cancel)
}
Button("Try Again") {
isPresentingScanFailedAlert = false
}
} message: {
if let error = scanError {
Text(error.localizedDescription)
}
}
}
}
extension AddQRView {
enum ScanError: LocalizedError {
case scanner(CodeScannerView.ScanError)
case invalidCode(String)
var errorDescription: String? {
switch self {
case .invalidCode(let code):
return "Invalid Code: '\(code)'"
case .scanner(.badInput):
return "Scanner: Bad Input"
case .scanner(.badOutput):
return "Scanner: Bad Output"
}
}
}
}
struct AddQRView_Previews: PreviewProvider {
static var previews: some View {
AddQRView() { (_) in }
}
}