damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

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 }