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