qrscan: use explicit types when scanning

This commit is contained in:
William Casarin
2023-06-07 07:56:00 +02:00
parent a0caf9ce07
commit 8f237b47eb

View File

@@ -8,6 +8,38 @@
import SwiftUI import SwiftUI
import CoreImage.CIFilterBuiltins import CoreImage.CIFilterBuiltins
struct ProfileScanResult: Equatable {
let pubkey: String
init(hex: String) {
self.pubkey = hex
}
init?(string: String) {
var str = string
guard str.count != 0 else {
return nil
}
if str.hasPrefix("nostr:") {
str.removeFirst("nostr:".count)
}
if let _ = hex_decode(str), str.count == 64 {
self = .init(hex: str)
return
}
if str.starts(with: "npub"), let b32 = try? bech32_decode(str) {
let hex = hex_encode(b32.data)
self = .init(hex: hex)
return
}
return nil
}
}
struct QRCodeView: View { struct QRCodeView: View {
let damus_state: DamusState let damus_state: DamusState
@State var pubkey: String @State var pubkey: String
@@ -16,12 +48,11 @@ struct QRCodeView: View {
@State private var selectedTab = 0 @State private var selectedTab = 0
@State var scanResult: Search? = nil @State var scanResult: ProfileScanResult? = nil
@State var showProfileView: Bool = false @State var showProfileView: Bool = false
@State var profile: Profile? = nil @State var profile: Profile? = nil
@State var error: String? = nil
@State private var scannedCode = ""
@State private var outerTrimEnd: CGFloat = 0 @State private var outerTrimEnd: CGFloat = 0
var animationDuration: Double = 0.5 var animationDuration: Double = 0.5
@@ -152,29 +183,6 @@ struct QRCodeView: View {
} }
} }
func search_changed(_ new: String) {
var str = new
guard str.count != 0 else {
return
}
if str.hasPrefix("nostr:") {
str.removeFirst("nostr:".count)
}
if let _ = hex_decode(str), str.count == 64 {
self.scanResult = .hex(str)
return
}
if str.starts(with: "npub") {
if let _ = try? bech32_decode(str) {
self.scanResult = .profile(str)
return
}
}
}
func QRCameraView() -> some View { func QRCameraView() -> some View {
return VStack(alignment: .center) { return VStack(alignment: .center) {
Text("Scan a user's pubkey") Text("Scan a user's pubkey")
@@ -185,16 +193,10 @@ struct QRCodeView: View {
CodeScannerView(codeTypes: [.qr], scanMode: .continuous, simulatedData: "npub1k92qsr95jcumkpu6dffurkvwwycwa2euvx4fthv78ru7gqqz0nrs2ngfwd", shouldVibrateOnSuccess: false) { result in CodeScannerView(codeTypes: [.qr], scanMode: .continuous, simulatedData: "npub1k92qsr95jcumkpu6dffurkvwwycwa2euvx4fthv78ru7gqqz0nrs2ngfwd", shouldVibrateOnSuccess: false) { result in
switch result { switch result {
case .success(let result): case .success(let success):
search_changed(result.string) handleProfileScan(success.string)
switch scanResult { case .failure(let failure):
case .profile(let prof): self.error = failure.localizedDescription
handleProfileScan(prof)
default:
print("Not a profile")
}
case .failure(let error):
print(error.localizedDescription)
} }
} }
.scaledToFit() .scaledToFit()
@@ -207,17 +209,11 @@ struct QRCodeView: View {
Spacer() Spacer()
if showProfileView { if let scanResult {
let decoded = try? bech32_decode(scannedCode) let dst = ProfileView(damus_state: damus_state, pubkey: scanResult.pubkey)
let hex = hex_encode(decoded!.data) NavigationLink(destination: dst, isActive: $showProfileView) {
EmptyView()
NavigationLink( }
destination: ProfileView(damus_state: damus_state, pubkey: hex),
isActive: $showProfileView,
label: {
EmptyView()
}
)
} }
Spacer() Spacer()
@@ -236,33 +232,50 @@ struct QRCodeView: View {
} }
} }
func profile(for code: String) -> Profile? { func handleProfileScan(_ scanned_str: String) {
guard let decoded = try? bech32_decode(code) else { guard let result = ProfileScanResult(string: scanned_str) else {
return nil self.error = "Invalid profile QR"
return
} }
let hex = hex_encode(decoded.data)
return damus_state.profiles.lookup(id: hex)
}
func handleProfileScan(_ prof: String) { self.error = nil
guard scannedCode != prof else {
guard result != self.scanResult else {
return return
} }
generator.impactOccurred() generator.impactOccurred()
cameraAnimate { cameraAnimate {
scannedCode = prof scanResult = result
if profile(for: scannedCode) != nil { find_event(state: damus_state, query: .profile(pubkey: result.pubkey)) { res in
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) { guard let res else {
showProfileView = true error = "Profile not found"
return
} }
} else {
print("Profile not found") switch res {
case .invalid_profile:
error = "Profile was found but was corrupt."
case .profile:
show_profile_after_delay()
case .event:
print("invalid search result")
}
} }
} }
} }
func show_profile_after_delay() {
DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
showProfileView = true
}
}
func cameraAnimate(completion: @escaping () -> Void) { func cameraAnimate(completion: @escaping () -> Void) {
outerTrimEnd = 0.0 outerTrimEnd = 0.0
withAnimation(.easeInOut(duration: animationDuration)) { withAnimation(.easeInOut(duration: animationDuration)) {
@@ -296,3 +309,4 @@ struct QRCodeView_Previews: PreviewProvider {
QRCodeView(damus_state: test_damus_state(), pubkey: test_event.pubkey) QRCodeView(damus_state: test_damus_state(), pubkey: test_event.pubkey)
} }
} }