damus

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

SaveKeysView.swift (8739B)


      1 //
      2 //  SaveKeysView.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2022-05-21.
      6 //
      7 
      8 import SwiftUI
      9 import Security
     10 
     11 struct SaveKeysView: View {
     12     let account: CreateAccountModel
     13     let pool: RelayPool = RelayPool(ndb: Ndb()!)
     14     @State var loading: Bool = false
     15     @State var error: String? = nil
     16     
     17     @State private var credential_handler = CredentialHandler()
     18 
     19     @FocusState var pubkey_focused: Bool
     20     @FocusState var privkey_focused: Bool
     21     
     22     let first_contact_event: NdbNote?
     23     
     24     init(account: CreateAccountModel) {
     25         self.account = account
     26         self.first_contact_event = make_first_contact_event(keypair: account.keypair)
     27     }
     28     
     29     var body: some View {
     30         ZStack(alignment: .top) {
     31             VStack(alignment: .center) {
     32 
     33                 Spacer()
     34                 
     35                 Image("logo-nobg")
     36                     .resizable()
     37                     .shadow(color: DamusColors.purple, radius: 2)
     38                     .frame(width: 56, height: 56, alignment: .center)
     39                     .padding(.top, 20.0)
     40                 
     41                 if account.rendered_name.isEmpty {
     42                     Text("Welcome!", comment: "Text to welcome user.")
     43                         .font(.title)
     44                         .fontWeight(.heavy)
     45                         .foregroundStyle(DamusLogoGradient.gradient)
     46                 } else {
     47                     Text("Welcome, \(account.rendered_name)!", comment: "Text to welcome user.")
     48                         .font(.title)
     49                         .fontWeight(.heavy)
     50                         .foregroundStyle(DamusLogoGradient.gradient)
     51                 }
     52                 
     53                 Text("Save your login info?", comment: "Ask user if they want to save their account information.")
     54                     .font(.title)
     55                     .fontWeight(.heavy)
     56                     .foregroundColor(DamusColors.neutral6)
     57                     .padding(.top, 5)
     58                 
     59                 Text("We'll save your account key, so you won't need to enter it manually next time you log in.", comment: "Reminder to user that they should save their account information.")
     60                     .font(.system(size: 14))
     61                     .foregroundColor(DamusColors.neutral6)
     62                     .padding(.top, 2)
     63                     .padding(.bottom, 100)
     64                     .multilineTextAlignment(.center)
     65                 
     66                 Spacer()
     67                 
     68                 if loading {
     69                     ProgressView()
     70                         .progressViewStyle(.circular)
     71                 } else if let err = error {
     72                     Text("Error: \(err)", comment: "Error message indicating why saving keys failed.")
     73                         .foregroundColor(.red)
     74                     
     75                     Button(action: {
     76                         complete_account_creation(account)
     77                     }) {
     78                         HStack {
     79                             Text("Retry", comment:  "Button to retry completing account creation after an error occurred.")
     80                                 .fontWeight(.semibold)
     81                         }
     82                         .frame(minWidth: 300, maxWidth: .infinity, maxHeight: 12, alignment: .center)
     83                     }
     84                     .buttonStyle(GradientButtonStyle())
     85                     .padding(.top, 20)
     86                 } else {
     87                     
     88                     Button(action: {
     89                         save_key(account)
     90                         complete_account_creation(account)
     91                     }) {
     92                         HStack {
     93                             Text("Save", comment:  "Button to save key, complete account creation, and start using the app.")
     94                                 .fontWeight(.semibold)
     95                         }
     96                         .frame(minWidth: 300, maxWidth: .infinity, maxHeight: 12, alignment: .center)
     97                     }
     98                     .buttonStyle(GradientButtonStyle())
     99                     .padding(.top, 20)
    100                     
    101                     Button(action: {
    102                         complete_account_creation(account)
    103                     }) {
    104                         HStack {
    105                             Text("Not now", comment:  "Button to not save key, complete account creation, and start using the app.")
    106                                 .fontWeight(.semibold)
    107                         }
    108                         .frame(minWidth: 300, maxWidth: .infinity, maxHeight: 12, alignment: .center)
    109                     }
    110                     .buttonStyle(NeutralButtonStyle(padding: EdgeInsets(top: 15, leading: 15, bottom: 15, trailing: 15), cornerRadius: 12))
    111                     .padding(.top, 20)
    112                 }
    113             }
    114             .padding(20)
    115         }
    116         .background(DamusBackground(maxHeight: UIScreen.main.bounds.size.height/2), alignment: .top)
    117         .navigationBarBackButtonHidden(true)
    118         .navigationBarItems(leading: BackNav())
    119 
    120     }
    121     
    122     func save_key(_ account: CreateAccountModel) {
    123         credential_handler.save_credential(pubkey: account.pubkey, privkey: account.privkey)
    124     }
    125     
    126     func complete_account_creation(_ account: CreateAccountModel) {
    127         guard let first_contact_event else {
    128             error = NSLocalizedString("Could not create your initial contact list event. This is a software bug, please contact Damus support via support@damus.io or through our Nostr account for help.", comment: "Error message to the user indicating that the initial contact list failed to be created.")
    129             return
    130         }
    131         // Save contact list to storage right away so that we don't need to depend on the network to complete this important step
    132         self.save_to_storage(first_contact_event: first_contact_event, for: account)
    133         
    134         let bootstrap_relays = load_bootstrap_relays(pubkey: account.pubkey)
    135         for relay in bootstrap_relays {
    136             add_rw_relay(self.pool, relay)
    137         }
    138 
    139         self.pool.register_handler(sub_id: "signup", handler: handle_event)
    140 
    141         self.loading = true
    142         
    143         self.pool.connect()
    144     }
    145     
    146     func save_to_storage(first_contact_event: NdbNote, for account: CreateAccountModel) {
    147         // Send to NostrDB so that we have a local copy in storage
    148         self.pool.send_raw_to_local_ndb(.typical(.event(first_contact_event)))
    149         
    150         // Save the ID to user settings so that we can easily find it later.
    151         let settings = UserSettingsStore.globally_load_for(pubkey: account.pubkey)
    152         settings.latest_contact_event_id_hex = first_contact_event.id.hex()
    153     }
    154 
    155     func handle_event(relay: RelayURL, ev: NostrConnectionEvent) {
    156         switch ev {
    157         case .ws_event(let wsev):
    158             switch wsev {
    159             case .connected:
    160                 let metadata = create_account_to_metadata(account)
    161                 
    162                 if let keypair = account.keypair.to_full(),
    163                    let metadata_ev = make_metadata_event(keypair: keypair, metadata: metadata) {
    164                     self.pool.send(.event(metadata_ev))
    165                 }
    166                 
    167                 if let first_contact_event {
    168                     self.pool.send(.event(first_contact_event))
    169                 }
    170                 
    171                 do {
    172                     try save_keypair(pubkey: account.pubkey, privkey: account.privkey)
    173                     notify(.login(account.keypair))
    174                 } catch {
    175                     self.error = "Failed to save keys"
    176                 }
    177                 
    178             case .error(let err):
    179                 self.loading = false
    180                 self.error = String(describing: err)
    181             default:
    182                 break
    183             }
    184         case .nostr_event(let resp):
    185             switch resp {
    186             case .notice(let msg):
    187                 // TODO handle message
    188                 self.loading = false
    189                 self.error = msg
    190                 print(msg)
    191             case .event:
    192                 print("event in signup?")
    193             case .eose:
    194                 break
    195             case .ok:
    196                 break
    197             case .auth:
    198                 break
    199             }
    200         }
    201     }
    202 }
    203 
    204 struct SaveKeysView_Previews: PreviewProvider {
    205     static var previews: some View {
    206         let model = CreateAccountModel(display_name: "William", name: "jb55", about: "I'm me")
    207         SaveKeysView(account: model)
    208     }
    209 }
    210 
    211 func create_account_to_metadata(_ model: CreateAccountModel) -> Profile {
    212     return Profile(name: model.name, display_name: model.display_name, about: model.about, picture: model.profile_image?.absoluteString, banner: nil, website: nil, lud06: nil, lud16: nil, nip05: nil, damus_donation: nil)
    213 }