damusApp.swift (5644B)
1 // 2 // damusApp.swift 3 // damus 4 // 5 // Created by William Casarin on 2022-04-01. 6 // 7 8 import SwiftUI 9 import StoreKit 10 11 @main 12 struct damusApp: App { 13 @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate 14 var body: some Scene { 15 WindowGroup { 16 MainView(appDelegate: appDelegate) 17 } 18 } 19 } 20 21 struct MainView: View { 22 @State var needs_setup = false; 23 @State var keypair: Keypair? = nil; 24 @StateObject private var orientationTracker = OrientationTracker() 25 var appDelegate: AppDelegate 26 27 var body: some View { 28 Group { 29 if let kp = keypair, !needs_setup { 30 ContentView(keypair: kp, appDelegate: appDelegate) 31 .environmentObject(orientationTracker) 32 } else { 33 SetupView() 34 .onReceive(handle_notify(.login)) { notif in 35 needs_setup = false 36 keypair = get_saved_keypair() 37 if keypair == nil, let tempkeypair = notif.to_full()?.to_keypair() { 38 keypair = tempkeypair 39 } 40 } 41 } 42 } 43 .dynamicTypeSize(.xSmall ... .xxxLarge) 44 .onReceive(handle_notify(.logout)) { () in 45 try? clear_keypair() 46 keypair = nil 47 // We need to disconnect and reconnect to all relays when the user signs out 48 // This is to conform to NIP-42 and ensure we aren't persisting old connections 49 notify(.disconnect_relays) 50 } 51 .onReceive(NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)) { _ in 52 orientationTracker.setDeviceMajorAxis() 53 } 54 .onAppear { 55 orientationTracker.setDeviceMajorAxis() 56 keypair = get_saved_keypair() 57 appDelegate.keypair = keypair 58 } 59 } 60 } 61 62 class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { 63 var keypair: Keypair? = nil 64 var settings: UserSettingsStore? = nil 65 66 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 67 UNUserNotificationCenter.current().delegate = self 68 69 SKPaymentQueue.default().add(StoreObserver.standard) 70 return true 71 } 72 73 func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { 74 // Return if this feature is disabled 75 guard let settings = self.settings else { return } 76 if !settings.enable_experimental_push_notifications { 77 return 78 } 79 80 // Send the device token and pubkey to the server 81 let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() 82 83 print("Received device token: \(token)") 84 85 guard let pubkey = keypair?.pubkey else { 86 return 87 } 88 89 // Send those as JSON to the server 90 let json: [String: Any] = ["deviceToken": token, "pubkey": pubkey.hex()] 91 92 // create post request 93 let url = settings.send_device_token_to_localhost ? Constants.DEVICE_TOKEN_RECEIVER_TEST_URL : Constants.DEVICE_TOKEN_RECEIVER_PRODUCTION_URL 94 var request = URLRequest(url: url) 95 request.httpMethod = "POST" 96 97 // insert json data to the request 98 request.httpBody = try? JSONSerialization.data(withJSONObject: json, options: []) 99 request.setValue("application/json", forHTTPHeaderField: "Content-Type") 100 101 let task = URLSession.shared.dataTask(with: request) { data, response, error in 102 guard let data = data, error == nil else { 103 print(error?.localizedDescription ?? "No data") 104 return 105 } 106 107 if let response = response as? HTTPURLResponse, !(200...299).contains(response.statusCode) { 108 print("Unexpected status code: \(response.statusCode)") 109 return 110 } 111 112 let responseJSON = try? JSONSerialization.jsonObject(with: data, options: []) 113 if let responseJSON = responseJSON as? [String: Any] { 114 print(responseJSON) 115 } 116 } 117 118 task.resume() 119 } 120 121 // Handle the notification in the foreground state 122 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { 123 // Display the notification in the foreground 124 completionHandler([.banner, .list, .sound, .badge]) 125 } 126 127 func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { 128 let userInfo = response.notification.request.content.userInfo 129 guard let notification = LossyLocalNotification.from_user_info(user_info: userInfo) else { 130 return 131 } 132 notify(.local_notification(notification)) 133 completionHandler() 134 } 135 } 136 137 class OrientationTracker: ObservableObject { 138 var deviceMajorAxis: CGFloat = 0 139 func setDeviceMajorAxis() { 140 let bounds = UIScreen.main.bounds 141 let height = max(bounds.height, bounds.width) /// device's longest dimension 142 let width = min(bounds.height, bounds.width) /// device's shortest dimension 143 let orientation = UIDevice.current.orientation 144 deviceMajorAxis = (orientation == .portrait || orientation == .unknown) ? height : width 145 } 146 }