damus

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

CreateAccountView.swift (6520B)


      1 //
      2 //  CreateAccountView.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2022-05-20.
      6 //
      7 
      8 import SwiftUI
      9 import Combine
     10 
     11 struct CreateAccountView: View, KeyboardReadable {
     12     @StateObject var account: CreateAccountModel = CreateAccountModel()
     13     @StateObject var profileUploadObserver = ImageUploadingObserver()
     14     var nav: NavigationCoordinator
     15     @State var keyboardVisible: Bool = false
     16     let maxViewportHeightForAdaptiveContentSize: CGFloat = 975 // 956px height = iPhone 16 Pro Max
     17     
     18     func SignupForm<FormContent: View>(@ViewBuilder content: () -> FormContent) -> some View {
     19         return VStack(alignment: .leading, spacing: 10.0, content: content)
     20     }
     21     
     22     func regen_key() {
     23         let keypair = generate_new_keypair()
     24         self.account.pubkey = keypair.pubkey
     25         self.account.privkey = keypair.privkey
     26     }
     27     
     28     var body: some View {
     29         ZStack(alignment: .top) {
     30             VStack {
     31                 Spacer()
     32 
     33                 VStack(alignment: .center) {
     34                     let screenHeight = UIScreen.main.bounds.height
     35                     let style = EditPictureControl.Style(
     36                         size: keyboardVisible && screenHeight < maxViewportHeightForAdaptiveContentSize ? 25 : 75,
     37                         first_time_setup: true
     38                     )
     39 
     40                     EditPictureControl(
     41                         uploader: MediaUploader.nostrBuild,
     42                         context: .profile_picture,
     43                         keypair: account.keypair,
     44                         pubkey: account.pubkey,
     45                         style: style,
     46                         current_image_url: $account.profile_image,
     47                         upload_observer: profileUploadObserver,
     48                         callback: uploadedProfilePicture
     49                     )
     50                         .shadow(radius: 2)
     51                 }
     52                 
     53                 SignupForm {
     54                     FormLabel(NSLocalizedString("Name", comment: "Label to prompt name entry."), optional: false)
     55                         .foregroundColor(DamusColors.neutral6)
     56                     FormTextInput(NSLocalizedString("Satoshi Nakamoto", comment: "Name of Bitcoin creator(s)."), text: $account.name)
     57                         .textInputAutocapitalization(.words)
     58                     
     59                     FormLabel(NSLocalizedString("Bio", comment: "Label to prompt bio entry for user to describe themself."), optional: true)
     60                         .foregroundColor(DamusColors.neutral6)
     61                     FormTextInput(NSLocalizedString("Absolute legend.", comment: "Example Bio"), text: $account.about)
     62                 }
     63                 .padding(.top, 25)
     64                 
     65                 Button(action: {
     66                     nav.push(route: Route.SaveKeys(account: account))
     67                 }) {
     68                     HStack {
     69                         Text("Next", comment: "Button to continue with account creation.")
     70                             .fontWeight(.semibold)
     71                     }
     72                     .frame(minWidth: 300, maxWidth: .infinity, maxHeight: 12, alignment: .center)
     73                 }
     74                 .buttonStyle(GradientButtonStyle())
     75                 .disabled(profileUploadObserver.isLoading || account.name.isEmpty)
     76                 .opacity(profileUploadObserver.isLoading || account.name.isEmpty ? 0.5 : 1)
     77                 .padding(.top, 20)
     78                 
     79                 LoginPrompt()
     80                     .padding(.top)
     81                 
     82                 Spacer()
     83             }
     84             .padding()
     85         }
     86         .background(DamusBackground(maxHeight: UIScreen.main.bounds.size.height/2), alignment: .top)
     87         .dismissKeyboardOnTap()
     88         .onReceive(keyboardPublisher) { visible in
     89             withAnimation {
     90                 self.keyboardVisible = visible
     91             }
     92         }
     93         .navigationBarTitleDisplayMode(.inline)
     94         .navigationBarBackButtonHidden(true)
     95         .navigationBarItems(leading: BackNav())
     96     }
     97     
     98     func uploadedProfilePicture(image_url: URL?) {
     99         account.profile_image = image_url
    100     }
    101 }
    102 
    103 struct LoginPrompt: View {
    104     @Environment(\.dismiss) var dismiss
    105     var body: some View {
    106         HStack {
    107             Text("Already on Nostr?", comment: "Ask the user if they already have an account on Nostr")
    108                 .foregroundColor(DamusColors.neutral6)
    109 
    110             Button(NSLocalizedString("Login", comment: "Button to navigate to login view.")) {
    111                 self.dismiss()
    112             }
    113 
    114             Spacer()
    115         }
    116     }
    117 }
    118 
    119 struct BackNav: View {
    120     @Environment(\.dismiss) var dismiss
    121     var body: some View {
    122         Image("chevron-left")
    123             .foregroundColor(DamusColors.adaptableBlack)
    124             .onTapGesture {
    125                 self.dismiss()
    126         }
    127     }
    128 }
    129 
    130 extension View {
    131     func placeholder<Content: View>(
    132         when shouldShow: Bool,
    133         alignment: Alignment = .leading,
    134         @ViewBuilder placeholder: () -> Content) -> some View {
    135 
    136         ZStack(alignment: alignment) {
    137             placeholder().opacity(shouldShow ? 1 : 0)
    138             self
    139         }
    140     }
    141 }
    142 
    143 struct CreateAccountView_Previews: PreviewProvider {
    144     static var previews: some View {
    145         let model = CreateAccountModel(display_name: "", name: "jb55", about: "")
    146         return CreateAccountView(account: model, nav: .init())
    147     }
    148 }
    149 
    150 func FormTextInput(_ title: String, text: Binding<String>) -> some View {
    151     return TextField("", text: text)
    152         .placeholder(when: text.wrappedValue.isEmpty) {
    153             Text(title).foregroundColor(.gray.opacity(0.5))
    154         }
    155         .padding(15)
    156         .background {
    157             RoundedRectangle(cornerRadius: 12)
    158                 .stroke(.gray.opacity(0.5), lineWidth: 1)
    159                 .background {
    160                     RoundedRectangle(cornerRadius: 12)
    161                         .foregroundColor(.damusAdaptableWhite)
    162                 }
    163         }
    164         .font(.body.bold())
    165 }
    166 
    167 func FormLabel(_ title: String, optional: Bool = false) -> some View {
    168     return HStack {
    169         Text(title)
    170                 .bold()
    171         if optional {
    172             Text("optional", comment: "Label indicating that a form input is optional.")
    173                 .font(.callout)
    174                 .foregroundColor(DamusColors.mediumGrey)
    175         } else {
    176             Text("required", comment: "Label indicating that a form input is required.")
    177                 .font(.callout)
    178                 .foregroundColor(DamusColors.mediumGrey)
    179         }
    180     }
    181 }
    182