From bee40668373e448226324f9654adc46e43bdb147 Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Wed, 16 Oct 2024 18:12:18 -0400 Subject: [PATCH 1/8] #1594: Create Account screen and new feature flag --- Nos.xcodeproj/project.pbxproj | 4 + Nos/Assets/Localization/Localizable.xcstrings | 88 ++++++++++++++++- Nos/Service/FeatureFlags.swift | 6 ++ Nos/Views/Onboarding/CreateAccountView.swift | 98 +++++++++++++++++++ .../OnboardingAgeVerificationView.swift | 26 +++-- .../OnboardingNotOldEnoughView.swift | 4 +- .../Onboarding/OnboardingStartView.swift | 4 +- Nos/Views/Onboarding/OnboardingView.swift | 22 +++-- Nos/Views/Settings/SettingsView.swift | 15 +++ NosTests/Service/MockFeatureFlags.swift | 1 + 10 files changed, 244 insertions(+), 24 deletions(-) create mode 100644 Nos/Views/Onboarding/CreateAccountView.swift diff --git a/Nos.xcodeproj/project.pbxproj b/Nos.xcodeproj/project.pbxproj index 3ae447dd8..4141371ae 100644 --- a/Nos.xcodeproj/project.pbxproj +++ b/Nos.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ 0393893D2CA49CE000698978 /* fonts-animated.gif in Resources */ = {isa = PBXBuildFile; fileRef = 0393893C2CA49CE000698978 /* fonts-animated.gif */; }; 039C961F2C480F4100A8EB39 /* unsupported_kinds.json in Resources */ = {isa = PBXBuildFile; fileRef = 039C961E2C480F4100A8EB39 /* unsupported_kinds.json */; }; 039C96292C48321E00A8EB39 /* long_form_data.json in Resources */ = {isa = PBXBuildFile; fileRef = 039C96282C48321E00A8EB39 /* long_form_data.json */; }; + 039F09592CC051FF00FEEC81 /* CreateAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 039F09582CC051EE00FEEC81 /* CreateAccountView.swift */; }; 03A3AA3B2C5028FF008FE153 /* PublicKeyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A3AA3A2C5028FF008FE153 /* PublicKeyTests.swift */; }; 03B4E6A22C125CA1006E5F59 /* nostr_build_nip96_upload_response.json in Resources */ = {isa = PBXBuildFile; fileRef = 03B4E6A12C125CA1006E5F59 /* nostr_build_nip96_upload_response.json */; }; 03B4E6AC2C125D13006E5F59 /* FileStorageUploadResponseJSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03B4E6AB2C125D13006E5F59 /* FileStorageUploadResponseJSONTests.swift */; }; @@ -637,6 +638,7 @@ 0393893C2CA49CE000698978 /* fonts-animated.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = "fonts-animated.gif"; sourceTree = ""; }; 039C961E2C480F4100A8EB39 /* unsupported_kinds.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = unsupported_kinds.json; sourceTree = ""; }; 039C96282C48321E00A8EB39 /* long_form_data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = long_form_data.json; sourceTree = ""; }; + 039F09582CC051EE00FEEC81 /* CreateAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountView.swift; sourceTree = ""; }; 03A3AA3A2C5028FF008FE153 /* PublicKeyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicKeyTests.swift; sourceTree = ""; }; 03AB2F7D2BF6609500B73DB1 /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = ""; }; 03B4E6A12C125CA1006E5F59 /* nostr_build_nip96_upload_response.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = nostr_build_nip96_upload_response.json; sourceTree = ""; }; @@ -1447,6 +1449,7 @@ isa = PBXGroup; children = ( 030FECAA2CB5E0B900820014 /* BuildYourNetworkView.swift */, + 039F09582CC051EE00FEEC81 /* CreateAccountView.swift */, 3F30020629C237AB003D4F8B /* OnboardingAgeVerificationView.swift */, 3F30020C29C382EB003D4F8B /* OnboardingLoginView.swift */, 3F30020829C23895003D4F8B /* OnboardingNotOldEnoughView.swift */, @@ -2285,6 +2288,7 @@ 5BFF66B62A58A8A000AA79DD /* MutesView.swift in Sources */, C913DA0A2AEAF52B003BDD6D /* NoteWarningController.swift in Sources */, 3F30020929C23895003D4F8B /* OnboardingNotOldEnoughView.swift in Sources */, + 039F09592CC051FF00FEEC81 /* CreateAccountView.swift in Sources */, 042406F32C907A15008F2A21 /* NosToggle.swift in Sources */, 03B4E6AE2C125D61006E5F59 /* FileStorageUploadResponseJSON.swift in Sources */, 5B79F6112B98AD0A002DA9BE /* ExcellentChoiceSheet.swift in Sources */, diff --git a/Nos/Assets/Localization/Localizable.xcstrings b/Nos/Assets/Localization/Localizable.xcstrings index 6e6b52ef6..517dbef8b 100644 --- a/Nos/Assets/Localization/Localizable.xcstrings +++ b/Nos/Assets/Localization/Localizable.xcstrings @@ -4030,6 +4030,90 @@ } } }, + "createAccountButton" : { + "comment" : "The title of the button to create an account", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Create Account" + } + } + } + }, + "createAccountDescription" : { + "comment" : "The description on the create account screen", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "We've simplified management of your account credentials. Nos uses public-private key encryption to verify your identity." + } + } + } + }, + "createAccountDisplayName" : { + "comment" : "The label on the create account screen for display name", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display Name" + } + } + } + }, + "createAccountHeadline" : { + "comment" : "The headline (title) on the create account screen", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Say goodbye to usernames and passwords!" + } + } + } + }, + "createAccountPrivateKey" : { + "comment" : "The label on the create account screen for private key", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Private Key" + } + } + } + }, + "createAccountPublicKey" : { + "comment" : "The label on the create account screen for public key", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Public Key" + } + } + } + }, + "createAccountUsername" : { + "comment" : "The label on the create account screen for username", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Username" + } + } + } + }, "dayAbbreviated" : { "extractionState" : "manual", "localizations" : { @@ -13785,7 +13869,7 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Your **@username** is your identity in the Nos community.\u2028\nChoose a name that reflects you or your organization. Make it memorable and distinct!" + "value" : "Your **@username** is your identity in the Nos community.
\nChoose a name that reflects you or your organization. Make it memorable and distinct!" } }, "es" : { @@ -18951,7 +19035,7 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Well done, you've successfully claimed your **@username**!\u2028\nYou can share this name with other people in the Nostr and Fediverse communities to make it easy to find you." + "value" : "Well done, you've successfully claimed your **@username**!
\nYou can share this name with other people in the Nostr and Fediverse communities to make it easy to find you." } }, "es" : { diff --git a/Nos/Service/FeatureFlags.swift b/Nos/Service/FeatureFlags.swift index 3a1b70dca..2040f4880 100644 --- a/Nos/Service/FeatureFlags.swift +++ b/Nos/Service/FeatureFlags.swift @@ -7,6 +7,11 @@ enum FeatureFlag { /// Whether the new moderation flow should be enabled or not. /// - Note: See [#1489](https://github.com/planetary-social/nos/issues/1489) for details on the new moderation flow. case newModerationFlow + + /// Whether the new onboarding flow should be enabled or not. + /// - Note: See [Figma](https://www.figma.com/design/6MeujQUXzC1AuviHEHCs0J/Nos---In-Progress?node-id=9221-8504) + /// for the new flow. + case newOnboardingFlow } /// The set of feature flags used by the app. @@ -31,6 +36,7 @@ protocol FeatureFlags { /// Feature flags and their values. private var featureFlags: [FeatureFlag: Bool] = [ .newModerationFlow: false, + .newOnboardingFlow: false ] /// Returns true if the feature is enabled. diff --git a/Nos/Views/Onboarding/CreateAccountView.swift b/Nos/Views/Onboarding/CreateAccountView.swift new file mode 100644 index 000000000..77d587815 --- /dev/null +++ b/Nos/Views/Onboarding/CreateAccountView.swift @@ -0,0 +1,98 @@ +import Dependencies +import SwiftUI + +/// The Create Account view in the onboarding. +struct CreateAccountView: View { + @Environment(OnboardingState.self) private var state + + @Dependency(\.crashReporting) private var crashReporting + @Dependency(\.currentUser) private var currentUser + + var body: some View { + VStack(alignment: .leading, spacing: 20) { + Text("👋") + .font(.system(size: 60)) + Text("createAccountHeadline") + .font(.clarityBold(.title)) + .foregroundStyle(Color.primaryTxt) + Text("createAccountDescription") + .foregroundStyle(Color.secondaryTxt) + Spacer() + NumberedStepsView() + .padding(.horizontal, 10) + Spacer() + BigActionButton(title: "createAccountButton") { + do { + try await currentUser.createAccount() + } catch { + crashReporting.report(error) + } + state.step = .buildYourNetwork + } + } + .padding(40) + .background(Color.appBg) + .navigationBarHidden(true) + } +} + +/// The four numbered steps with their corresponding text. +fileprivate struct NumberedStepsView: View { + var body: some View { + VStack(alignment: .leading, spacing: 50) { + NumberedStepView(index: 1, label: "createAccountPrivateKey") + NumberedStepView(index: 2, label: "createAccountPublicKey") + NumberedStepView(index: 3, label: "createAccountDisplayName") + NumberedStepView(index: 4, label: "createAccountUsername") + } + .background( + ConnectingLine() + .offset(x: 5) + .stroke(Color.profileDividerShadow, lineWidth: 4), + alignment: .leading + ) + } +} + +/// A view containing an index with a circle background and some text. +fileprivate struct NumberedStepView: View { + let index: Int + let label: LocalizedStringKey + + var body: some View { + HStack(alignment: .center, spacing: 20) { + Text(index, format: .number) + .font(.clarityBold(.headline)) + .foregroundStyle(Color.primaryTxt) + .background( + Circle() + .fill(Color.profileDividerShadow) + .frame(width: 30, height: 30) + ) + + Text(label) + .font(.headline) + .fontWeight(.bold) + .foregroundStyle(Color.primaryTxt) + } + } +} + +/// Custom shape for the vertical connecting line +fileprivate struct ConnectingLine: Shape { + func path(in rect: CGRect) -> Path { + var path = Path() + let startPoint = CGPoint(x: rect.minX, y: 0) + let endPoint = CGPoint(x: rect.minX, y: rect.maxY) + + path.move(to: startPoint) + path.addLine(to: endPoint) + + return path + } +} + +#Preview { + CreateAccountView() + .environment(OnboardingState()) +} diff --git a/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift b/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift index 22e0b2238..a4a5d04fa 100644 --- a/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift +++ b/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift @@ -3,10 +3,11 @@ import SwiftUI /// The Age Verification view in the onboarding. struct OnboardingAgeVerificationView: View { - @EnvironmentObject var state: OnboardingState + @Environment(OnboardingState.self) private var state @Dependency(\.crashReporting) private var crashReporting @Dependency(\.currentUser) private var currentUser + @Dependency(\.featureFlags) private var featureFlags var body: some View { VStack { @@ -31,15 +32,12 @@ struct OnboardingAgeVerificationView: View { if state.flow == .loginToExistingAccount { state.step = .login } else { - // temporary; this will eventually move to the Create Account screen - do { - try await currentUser.createAccount() - } catch { - crashReporting.report(error) + if featureFlags.isEnabled(.newOnboardingFlow) { + state.step = .createAccount + } else { + await createAccount() + state.step = .buildYourNetwork } - // end temporary account creation - - state.step = .buildYourNetwork } } } @@ -49,4 +47,14 @@ struct OnboardingAgeVerificationView: View { .background(Color.appBg) .navigationBarHidden(true) } + + /// Create an account, logging any error to the crash reporting service. + /// - Note: This is a temporary solution for this screen and will eventually move to the Create Account screen. + func createAccount() async { + do { + try await currentUser.createAccount() + } catch { + crashReporting.report(error) + } + } } diff --git a/Nos/Views/Onboarding/OnboardingNotOldEnoughView.swift b/Nos/Views/Onboarding/OnboardingNotOldEnoughView.swift index af1c2f82d..0567e6d21 100644 --- a/Nos/Views/Onboarding/OnboardingNotOldEnoughView.swift +++ b/Nos/Views/Onboarding/OnboardingNotOldEnoughView.swift @@ -1,8 +1,8 @@ import SwiftUI struct OnboardingNotOldEnoughView: View { - @EnvironmentObject var state: OnboardingState - + @Environment(OnboardingState.self) private var state + var body: some View { VStack { Text(.localizable.notOldEnoughTitle) diff --git a/Nos/Views/Onboarding/OnboardingStartView.swift b/Nos/Views/Onboarding/OnboardingStartView.swift index 0601fe661..3003bf345 100644 --- a/Nos/Views/Onboarding/OnboardingStartView.swift +++ b/Nos/Views/Onboarding/OnboardingStartView.swift @@ -3,7 +3,7 @@ import SwiftUI /// The beginning of the Onboarding views which contains buttons to start creating a new account or log in. struct OnboardingStartView: View { - @EnvironmentObject var state: OnboardingState + @Environment(OnboardingState.self) private var state @Dependency(\.analytics) private var analytics @@ -54,6 +54,6 @@ struct OnboardingStartView: View { #Preview { OnboardingStartView() - .environmentObject(OnboardingState()) + .environment(OnboardingState()) .inject(previewData: PreviewData()) } diff --git a/Nos/Views/Onboarding/OnboardingView.swift b/Nos/Views/Onboarding/OnboardingView.swift index 3acc0d48b..f38069b35 100644 --- a/Nos/Views/Onboarding/OnboardingView.swift +++ b/Nos/Views/Onboarding/OnboardingView.swift @@ -1,13 +1,13 @@ import SwiftUI -class OnboardingState: ObservableObject { - @Published var flow: OnboardingFlow = .createAccount - @Published var step: OnboardingStep = .onboardingStart { +@Observable class OnboardingState { + var flow: OnboardingFlow = .createAccount + var step: OnboardingStep = .onboardingStart { didSet { path.append(step) } } - @Published var path = NavigationPath() + var path = NavigationPath() } enum OnboardingFlow { @@ -19,13 +19,14 @@ enum OnboardingStep { case onboardingStart case ageVerification case notOldEnough + case createAccount case buildYourNetwork case login } /// The view that initializes the onboarding navigation stack and shows the first view. struct OnboardingView: View { - @StateObject var state = OnboardingState() + @State var state = OnboardingState() /// Completion to be called when all onboarding steps are complete let completion: @MainActor () -> Void @@ -33,18 +34,21 @@ struct OnboardingView: View { var body: some View { NavigationStack(path: $state.path) { OnboardingStartView() - .environmentObject(state) + .environment(state) .navigationDestination(for: OnboardingStep.self) { step in switch step { case .onboardingStart: OnboardingStartView() - .environmentObject(state) + .environment(state) case .ageVerification: OnboardingAgeVerificationView() - .environmentObject(state) + .environment(state) case .notOldEnough: OnboardingNotOldEnoughView() - .environmentObject(state) + .environment(state) + case .createAccount: + CreateAccountView() + .environment(state) case .login: OnboardingLoginView(completion: completion) case .buildYourNetwork: diff --git a/Nos/Views/Settings/SettingsView.swift b/Nos/Views/Settings/SettingsView.swift index 3456c4c9d..cd8a26c81 100644 --- a/Nos/Views/Settings/SettingsView.swift +++ b/Nos/Views/Settings/SettingsView.swift @@ -284,6 +284,19 @@ extension SettingsView { private var newModerationFlowToggle: some View { NosToggle(isOn: isNewModerationFlowEnabled, labelText: .localizable.enableNewModerationFlow) } + + /// Whether the new onboarding flow is enabled. + private var isNewOnboardingFlowEnabled: Binding { + Binding( + get: { featureFlags.isEnabled(.newOnboardingFlow) }, + set: { featureFlags.setFeature(.newOnboardingFlow, enabled: $0) } + ) + } + + /// A toggle for the new moderation flow that allows the user to turn the feature on or off. + private var newOnboardingFlowToggle: some View { + NosToggle(isOn: isNewOnboardingFlowEnabled, labelText: "New Onboarding Flow") + } } #endif @@ -293,6 +306,7 @@ extension SettingsView { @MainActor private var stagingControls: some View { Group { newModerationFlowToggle + newOnboardingFlowToggle } } } @@ -304,6 +318,7 @@ extension SettingsView { @MainActor private var debugControls: some View { Group { newModerationFlowToggle + newOnboardingFlowToggle Text(.localizable.sampleDataInstructions) .foregroundColor(.primaryTxt) Button(String(localized: .localizable.loadSampleData)) { diff --git a/NosTests/Service/MockFeatureFlags.swift b/NosTests/Service/MockFeatureFlags.swift index 7d2eb5969..d64fc6a2e 100644 --- a/NosTests/Service/MockFeatureFlags.swift +++ b/NosTests/Service/MockFeatureFlags.swift @@ -3,6 +3,7 @@ class MockFeatureFlags: FeatureFlags { /// Mock feature flags and their values. private var featureFlags: [FeatureFlag: Bool] = [ .newModerationFlow: false, + .newOnboardingFlow: true ] func isEnabled(_ feature: FeatureFlag) -> Bool { From 3cb365b7942bc52797564e8ac84098c270f8509c Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Thu, 17 Oct 2024 09:17:02 -0400 Subject: [PATCH 2/8] update CHANGELOG; remove unused feature flag strings --- CHANGELOG.md | 1 + Nos/Assets/Localization/Localizable.xcstrings | 83 ------------------- 2 files changed, 1 insertion(+), 83 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 367ccddda..6ebc32f1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed integration with Universal Name Space [#1636](https://github.com/planetary-social/nos/issues/1636) ### Internal Changes +- Added the Create Account onboarding screen. Currently behind the “New Onboarding Flow” feature flag. [#1594](https://github.com/planetary-social/nos/issues/1594) ## [0.2.2] - 2024-10-11Z diff --git a/Nos/Assets/Localization/Localizable.xcstrings b/Nos/Assets/Localization/Localizable.xcstrings index 517dbef8b..080c89d01 100644 --- a/Nos/Assets/Localization/Localizable.xcstrings +++ b/Nos/Assets/Localization/Localizable.xcstrings @@ -5534,89 +5534,6 @@ } } }, - "enableAccountDeletion" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Enable account deletion" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Activar eliminación de cuenta" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "계정 삭제 활성화" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用账户删除" - } - } - } - }, - "enableNewMediaDisplay" : { - "comment" : "Setting for new media feature flag", - "extractionState" : "manual", - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Neue Mediendarstellung aktivieren" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Enable new media display" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Activar nuevo visor de medios" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Activer l'affichage des nouveaux médias" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새로운 미디어 디스플레이 사용" - } - }, - "sw" : { - "stringUnit" : { - "state" : "translated", - "value" : "Washa onyesho jipya la midia" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用新的媒体显示" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "啓用新的媒體顯示" - } - } - } - }, "enableNewModerationFlow" : { "extractionState" : "manual", "localizations" : { From 4ad98654ef0756bc719b02afec804a311d1cd69c Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Thu, 17 Oct 2024 11:55:35 -0400 Subject: [PATCH 3/8] handle larger font sizes in Create Account --- .../Contents.json | 20 ++++++++ Nos/Views/Onboarding/CreateAccountView.swift | 48 +++++++++++-------- 2 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 Nos/Assets/Colors.xcassets/numbered-step-background.colorset/Contents.json diff --git a/Nos/Assets/Colors.xcassets/numbered-step-background.colorset/Contents.json b/Nos/Assets/Colors.xcassets/numbered-step-background.colorset/Contents.json new file mode 100644 index 000000000..bb7f36785 --- /dev/null +++ b/Nos/Assets/Colors.xcassets/numbered-step-background.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x5B", + "green" : "0x25", + "red" : "0x37" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Nos/Views/Onboarding/CreateAccountView.swift b/Nos/Views/Onboarding/CreateAccountView.swift index 77d587815..51ca7a438 100644 --- a/Nos/Views/Onboarding/CreateAccountView.swift +++ b/Nos/Views/Onboarding/CreateAccountView.swift @@ -9,28 +9,35 @@ struct CreateAccountView: View { @Dependency(\.currentUser) private var currentUser var body: some View { - VStack(alignment: .leading, spacing: 20) { - Text("👋") - .font(.system(size: 60)) - Text("createAccountHeadline") - .font(.clarityBold(.title)) - .foregroundStyle(Color.primaryTxt) - Text("createAccountDescription") - .foregroundStyle(Color.secondaryTxt) - Spacer() - NumberedStepsView() - .padding(.horizontal, 10) - Spacer() - BigActionButton(title: "createAccountButton") { - do { - try await currentUser.createAccount() - } catch { - crashReporting.report(error) + GeometryReader { geometry in + ScrollView { + VStack(alignment: .leading, spacing: 20) { + Text("👋") + .font(.system(size: 60)) + Text("createAccountHeadline") + .font(.title) + .bold() + .foregroundStyle(Color.primaryTxt) + Text("createAccountDescription") + .font(.body) + .foregroundStyle(Color.secondaryTxt) + Spacer() + NumberedStepsView() + .padding(.horizontal, 10) + Spacer() + BigActionButton(title: "createAccountButton") { + do { + try await currentUser.createAccount() + } catch { + crashReporting.report(error) + } + state.step = .buildYourNetwork + } } - state.step = .buildYourNetwork + .padding(40) + .frame(minHeight: geometry.size.height) } } - .padding(40) .background(Color.appBg) .navigationBarHidden(true) } @@ -47,7 +54,7 @@ fileprivate struct NumberedStepsView: View { } .background( ConnectingLine() - .offset(x: 5) + .offset(x: 8) .stroke(Color.profileDividerShadow, lineWidth: 4), alignment: .leading ) @@ -64,6 +71,7 @@ fileprivate struct NumberedStepView: View { Text(index, format: .number) .font(.clarityBold(.headline)) .foregroundStyle(Color.primaryTxt) + .frame(width: 16) .background( Circle() .fill(Color.profileDividerShadow) From 1ede020a69a010b96e2f03e37d433119ec49b20a Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Thu, 17 Oct 2024 12:33:48 -0400 Subject: [PATCH 4/8] use new color constant --- Nos/Views/Onboarding/CreateAccountView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Nos/Views/Onboarding/CreateAccountView.swift b/Nos/Views/Onboarding/CreateAccountView.swift index 51ca7a438..1adc7e4fc 100644 --- a/Nos/Views/Onboarding/CreateAccountView.swift +++ b/Nos/Views/Onboarding/CreateAccountView.swift @@ -55,7 +55,7 @@ fileprivate struct NumberedStepsView: View { .background( ConnectingLine() .offset(x: 8) - .stroke(Color.profileDividerShadow, lineWidth: 4), + .stroke(Color.numberedStepBackground, lineWidth: 4), alignment: .leading ) } @@ -74,7 +74,7 @@ fileprivate struct NumberedStepView: View { .frame(width: 16) .background( Circle() - .fill(Color.profileDividerShadow) + .fill(Color.numberedStepBackground) .frame(width: 30, height: 30) ) From 7b6bb807373ae76e0ec0e6b344bf3b3e9ad695d2 Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Thu, 17 Oct 2024 12:47:53 -0400 Subject: [PATCH 5/8] rename localization keys --- Nos/Assets/Localization/Localizable.xcstrings | 98 +++++++++---------- Nos/Views/Onboarding/CreateAccountView.swift | 8 +- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/Nos/Assets/Localization/Localizable.xcstrings b/Nos/Assets/Localization/Localizable.xcstrings index 080c89d01..76ad2d7ee 100644 --- a/Nos/Assets/Localization/Localizable.xcstrings +++ b/Nos/Assets/Localization/Localizable.xcstrings @@ -4054,20 +4054,8 @@ } } }, - "createAccountDisplayName" : { - "comment" : "The label on the create account screen for display name", - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Display Name" - } - } - } - }, "createAccountHeadline" : { - "comment" : "The headline (title) on the create account screen", + "comment" : "headline for the create account screen", "extractionState" : "manual", "localizations" : { "en" : { @@ -4078,42 +4066,6 @@ } } }, - "createAccountPrivateKey" : { - "comment" : "The label on the create account screen for private key", - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Private Key" - } - } - } - }, - "createAccountPublicKey" : { - "comment" : "The label on the create account screen for public key", - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Public Key" - } - } - } - }, - "createAccountUsername" : { - "comment" : "The label on the create account screen for username", - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Username" - } - } - } - }, "dayAbbreviated" : { "extractionState" : "manual", "localizations" : { @@ -5237,6 +5189,18 @@ } } }, + "displayNameHeadline" : { + "comment" : "headline for the display name screen in onboarding", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Display Name" + } + } + } + }, "done" : { "extractionState" : "manual", "localizations" : { @@ -14094,6 +14058,18 @@ } } }, + "privateKeyHeadline" : { + "comment" : "headline for the private key screen in onboarding", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Private Key" + } + } + } + }, "privateKeyPlaceholder" : { "extractionState" : "manual", "localizations" : { @@ -14533,6 +14509,18 @@ } } }, + "publicKeyHeadline" : { + "comment" : "headline for the public key screen in onboarding", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Public Key" + } + } + } + }, "quote" : { "extractionState" : "manual", "localizations" : { @@ -18993,6 +18981,18 @@ } } }, + "usernameHeadline" : { + "comment" : "headline for the username screen in onboarding", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Username" + } + } + } + }, "usernameWarningMessage" : { "extractionState" : "manual", "localizations" : { diff --git a/Nos/Views/Onboarding/CreateAccountView.swift b/Nos/Views/Onboarding/CreateAccountView.swift index 1adc7e4fc..c804380b4 100644 --- a/Nos/Views/Onboarding/CreateAccountView.swift +++ b/Nos/Views/Onboarding/CreateAccountView.swift @@ -47,10 +47,10 @@ struct CreateAccountView: View { fileprivate struct NumberedStepsView: View { var body: some View { VStack(alignment: .leading, spacing: 50) { - NumberedStepView(index: 1, label: "createAccountPrivateKey") - NumberedStepView(index: 2, label: "createAccountPublicKey") - NumberedStepView(index: 3, label: "createAccountDisplayName") - NumberedStepView(index: 4, label: "createAccountUsername") + NumberedStepView(index: 1, label: "privateKeyHeadline") + NumberedStepView(index: 2, label: "publicKeyHeadline") + NumberedStepView(index: 3, label: "displayNameHeadline") + NumberedStepView(index: 4, label: "usernameHeadline") } .background( ConnectingLine() From f99a1a5d6a604065225fef3289dea95a9a40e12b Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Thu, 17 Oct 2024 13:31:29 -0400 Subject: [PATCH 6/8] fix title font on Create Account --- Nos/Views/Onboarding/CreateAccountView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nos/Views/Onboarding/CreateAccountView.swift b/Nos/Views/Onboarding/CreateAccountView.swift index c804380b4..136c252db 100644 --- a/Nos/Views/Onboarding/CreateAccountView.swift +++ b/Nos/Views/Onboarding/CreateAccountView.swift @@ -15,7 +15,7 @@ struct CreateAccountView: View { Text("👋") .font(.system(size: 60)) Text("createAccountHeadline") - .font(.title) + .font(.clarityBold(.title)) .bold() .foregroundStyle(Color.primaryTxt) Text("createAccountDescription") From ed8160fdbc83569eec35c75c82ba05cd05bddb73 Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Thu, 17 Oct 2024 13:33:59 -0400 Subject: [PATCH 7/8] remove extraneous bold --- Nos/Views/Onboarding/CreateAccountView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Nos/Views/Onboarding/CreateAccountView.swift b/Nos/Views/Onboarding/CreateAccountView.swift index 136c252db..56a7190de 100644 --- a/Nos/Views/Onboarding/CreateAccountView.swift +++ b/Nos/Views/Onboarding/CreateAccountView.swift @@ -16,7 +16,6 @@ struct CreateAccountView: View { .font(.system(size: 60)) Text("createAccountHeadline") .font(.clarityBold(.title)) - .bold() .foregroundStyle(Color.primaryTxt) Text("createAccountDescription") .font(.body) From 033cb0e614175c363ae31aa9d32723a96011226a Mon Sep 17 00:00:00 2001 From: Josh Brown Date: Thu, 17 Oct 2024 16:09:17 -0400 Subject: [PATCH 8/8] add readability padding, remove spacer, use ViewThatFits --- Nos/Views/Onboarding/CreateAccountView.swift | 66 +++++++++++-------- .../OnboardingAgeVerificationView.swift | 2 +- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/Nos/Views/Onboarding/CreateAccountView.swift b/Nos/Views/Onboarding/CreateAccountView.swift index 56a7190de..07262355c 100644 --- a/Nos/Views/Onboarding/CreateAccountView.swift +++ b/Nos/Views/Onboarding/CreateAccountView.swift @@ -4,42 +4,51 @@ import SwiftUI /// The Create Account view in the onboarding. struct CreateAccountView: View { @Environment(OnboardingState.self) private var state - + @Environment(CurrentUser.self) var currentUser + @Dependency(\.crashReporting) private var crashReporting - @Dependency(\.currentUser) private var currentUser var body: some View { - GeometryReader { geometry in - ScrollView { - VStack(alignment: .leading, spacing: 20) { - Text("👋") - .font(.system(size: 60)) - Text("createAccountHeadline") - .font(.clarityBold(.title)) - .foregroundStyle(Color.primaryTxt) - Text("createAccountDescription") - .font(.body) - .foregroundStyle(Color.secondaryTxt) - Spacer() - NumberedStepsView() - .padding(.horizontal, 10) - Spacer() - BigActionButton(title: "createAccountButton") { - do { - try await currentUser.createAccount() - } catch { - crashReporting.report(error) - } - state.step = .buildYourNetwork - } + ZStack { + Color.appBg + .ignoresSafeArea() + ViewThatFits(in: .vertical) { + createAccountStack + + ScrollView { + createAccountStack } - .padding(40) - .frame(minHeight: geometry.size.height) } } - .background(Color.appBg) .navigationBarHidden(true) } + + var createAccountStack: some View { + VStack(alignment: .leading, spacing: 20) { + Text("👋") + .font(.system(size: 60)) + Text("createAccountHeadline") + .font(.clarityBold(.title)) + .foregroundStyle(Color.primaryTxt) + Text("createAccountDescription") + .font(.body) + .foregroundStyle(Color.secondaryTxt) + .padding(.bottom, 10) + NumberedStepsView() + .padding(.horizontal, 10) + Spacer() + BigActionButton(title: "createAccountButton") { + do { + try await currentUser.createAccount() + } catch { + crashReporting.report(error) + } + state.step = .buildYourNetwork + } + } + .padding(40) + .readabilityPadding() + } } /// The four numbered steps with their corresponding text. @@ -102,4 +111,5 @@ fileprivate struct ConnectingLine: Shape { #Preview { CreateAccountView() .environment(OnboardingState()) + .inject(previewData: PreviewData()) } diff --git a/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift b/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift index a4a5d04fa..52231925b 100644 --- a/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift +++ b/Nos/Views/Onboarding/OnboardingAgeVerificationView.swift @@ -4,9 +4,9 @@ import SwiftUI /// The Age Verification view in the onboarding. struct OnboardingAgeVerificationView: View { @Environment(OnboardingState.self) private var state + @Environment(CurrentUser.self) var currentUser @Dependency(\.crashReporting) private var crashReporting - @Dependency(\.currentUser) private var currentUser @Dependency(\.featureFlags) private var featureFlags var body: some View {