Skip to content

Commit

Permalink
Merge pull request #1660 from planetary-social/onboarding-public-key
Browse files Browse the repository at this point in the history
#1596: Public Key screen in onboarding
  • Loading branch information
joshuatbrown authored Oct 18, 2024
2 parents d4ff40f + 84aab65 commit 244247d
Show file tree
Hide file tree
Showing 10 changed files with 191 additions and 47 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Increase build settings timeout in fastlane. [#1662](https://github.com/planetary-social/nos/pull/1662)
- Removed new moderation feature flag. [#1646](https://github.com/planetary-social/nos/issues/1646)
- Added the Private Key onboarding screen. Currently behind the “New Onboarding Flow” feature flag. [#1595](https://github.com/planetary-social/nos/issues/1595)
- Added the Public Key onboarding screen. Currently behind the “New Onboarding Flow” feature flag. [#1596](https://github.com/planetary-social/nos/issues/1596)

## [0.2.2] - 2024-10-11Z

Expand Down
22 changes: 21 additions & 1 deletion Nos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
0304D0B22C9B731F001D16C7 /* MockOpenGraphService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0304D0B12C9B731F001D16C7 /* MockOpenGraphService.swift */; };
0304D0B32C9B731F001D16C7 /* MockOpenGraphService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0304D0B12C9B731F001D16C7 /* MockOpenGraphService.swift */; };
030AE4292BE3D63C004DEE02 /* FeaturedAuthor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030AE4282BE3D63C004DEE02 /* FeaturedAuthor.swift */; };
030E56CA2CC1BC6200A4A51E /* PublicKeyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030E56C92CC1BC6200A4A51E /* PublicKeyView.swift */; };
030E56E42CC1BF2900A4A51E /* CopyButtonState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030E56E32CC1BF2900A4A51E /* CopyButtonState.swift */; };
030E56F32CC2836D00A4A51E /* CopyKeyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030E56F22CC2836D00A4A51E /* CopyKeyView.swift */; };
030FECAB2CB5E0B900820014 /* BuildYourNetworkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 030FECAA2CB5E0B900820014 /* BuildYourNetworkView.swift */; };
0314CF742C9C7DD00001A53B /* youTube_fortnight_short.html in Resources */ = {isa = PBXBuildFile; fileRef = 0314CF732C9C7DD00001A53B /* youTube_fortnight_short.html */; };
0314D5AC2C7D31060002E7F4 /* MediaService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0314D5AB2C7D31060002E7F4 /* MediaService.swift */; };
Expand Down Expand Up @@ -589,6 +592,9 @@
0304D0A62C9B4BF2001D16C7 /* OpenGraphMetatdata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGraphMetatdata.swift; sourceTree = "<group>"; };
0304D0B12C9B731F001D16C7 /* MockOpenGraphService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockOpenGraphService.swift; sourceTree = "<group>"; };
030AE4282BE3D63C004DEE02 /* FeaturedAuthor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeaturedAuthor.swift; sourceTree = "<group>"; };
030E56C92CC1BC6200A4A51E /* PublicKeyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicKeyView.swift; sourceTree = "<group>"; };
030E56E32CC1BF2900A4A51E /* CopyButtonState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyButtonState.swift; sourceTree = "<group>"; };
030E56F22CC2836D00A4A51E /* CopyKeyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopyKeyView.swift; sourceTree = "<group>"; };
030FECAA2CB5E0B900820014 /* BuildYourNetworkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildYourNetworkView.swift; sourceTree = "<group>"; };
0314CF732C9C7DD00001A53B /* youTube_fortnight_short.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = youTube_fortnight_short.html; sourceTree = "<group>"; };
0314D5AB2C7D31060002E7F4 /* MediaService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaService.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1054,6 +1060,15 @@
path = CoreData;
sourceTree = "<group>";
};
030E56E52CC2835A00A4A51E /* Components */ = {
isa = PBXGroup;
children = (
030E56F22CC2836D00A4A51E /* CopyKeyView.swift */,
03C5DBC42CC19044009A9E0E /* LargeNumberView.swift */,
);
path = Components;
sourceTree = "<group>";
};
0315B5ED2C7E44FD0020E707 /* Media */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1463,13 +1478,14 @@
children = (
030FECAA2CB5E0B900820014 /* BuildYourNetworkView.swift */,
039F09582CC051EE00FEEC81 /* CreateAccountView.swift */,
03C5DBC42CC19044009A9E0E /* LargeNumberView.swift */,
3F30020629C237AB003D4F8B /* OnboardingAgeVerificationView.swift */,
3F30020C29C382EB003D4F8B /* OnboardingLoginView.swift */,
3F30020829C23895003D4F8B /* OnboardingNotOldEnoughView.swift */,
3F30020429C1FDD9003D4F8B /* OnboardingStartView.swift */,
3FB5E650299D28A200386527 /* OnboardingView.swift */,
038EF09C2CC16D640031F7F2 /* PrivateKeyView.swift */,
030E56C92CC1BC6200A4A51E /* PublicKeyView.swift */,
030E56E52CC2835A00A4A51E /* Components */,
);
path = Onboarding;
sourceTree = "<group>";
Expand Down Expand Up @@ -1542,6 +1558,7 @@
C92F01502AC4D67B00972489 /* Form */,
03C8B4902C6D061900A07CCD /* Media */,
03618B1E2C825F0900BCBC55 /* Wizard */,
030E56E32CC1BF2900A4A51E /* CopyButtonState.swift */,
);
path = Components;
sourceTree = "<group>";
Expand Down Expand Up @@ -2322,6 +2339,7 @@
502B6C3D2C9462A400446316 /* PushNotificationRegistrar.swift in Sources */,
5B6EB48E29EDBE0E006E750C /* NoteParser.swift in Sources */,
C9F84C23298DC7B900C6714D /* SettingsView.swift in Sources */,
030E56E42CC1BF2900A4A51E /* CopyButtonState.swift in Sources */,
03E711812C936DD1000B6F96 /* OpenGraphParser.swift in Sources */,
03C8B4962C6D065900A07CCD /* ImageViewer.swift in Sources */,
5B79F6092B98AC33002DA9BE /* ClaimYourUniqueIdentitySheet.swift in Sources */,
Expand Down Expand Up @@ -2352,6 +2370,7 @@
C9DFA972299BF9E8006929C1 /* CompactNoteView.swift in Sources */,
C9AC31AD2A55E0BD00A94E5A /* NotificationViewModel.swift in Sources */,
0326347A2C10C57A00E489B5 /* FileStorageAPIClient.swift in Sources */,
030E56CA2CC1BC6200A4A51E /* PublicKeyView.swift in Sources */,
C9EE3E632A053910008A7491 /* ExpirationTimeOption.swift in Sources */,
03C7E7A22CB9CD150054624C /* PointDownEmojiTipViewStyle.swift in Sources */,
C9A0DAE029C697A100466635 /* AboutView.swift in Sources */,
Expand Down Expand Up @@ -2490,6 +2509,7 @@
5B834F692A83FC7F000C1432 /* ProfileSocialStatsView.swift in Sources */,
045EDD052CAC025700B67964 /* ScrollViewProxy+Animate.swift in Sources */,
CD09A74629A50F750063464F /* SideMenuContent.swift in Sources */,
030E56F32CC2836D00A4A51E /* CopyKeyView.swift in Sources */,
C9DFA971299BF8CD006929C1 /* NoteView.swift in Sources */,
037071272C90C5FA00BEAEC4 /* OpenGraphService.swift in Sources */,
C974652E2A3B86600031226F /* NoteCardHeader.swift in Sources */,
Expand Down
36 changes: 36 additions & 0 deletions Nos/Assets/Localization/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -3769,6 +3769,18 @@
}
}
},
"copyPublicKey" : {
"comment" : "title for the button that copies the public key",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Copy public key"
}
}
}
},
"copyQRLink" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -14539,6 +14551,18 @@
}
}
},
"publicKeyDescription" : {
"comment" : "a description for the public key screen explaining what a public key is",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "This is your public identifier that does not change. Public keys can be shared."
}
}
}
},
"publicKeyHeadline" : {
"comment" : "headline for the public key screen in onboarding",
"extractionState" : "manual",
Expand All @@ -14551,6 +14575,18 @@
}
}
},
"publicKeyNpubParenthetical" : {
"comment" : "the word \"npub\" in parentheses in English. \"npub\" should not be translated, but the parentheses may",
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "(npub)"
}
}
}
},
"quote" : {
"extractionState" : "manual",
"localizations" : {
Expand Down
5 changes: 5 additions & 0 deletions Nos/Views/Components/CopyButtonState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// The state of a copy button.
enum CopyButtonState {
case copy
case copied
}
63 changes: 63 additions & 0 deletions Nos/Views/Onboarding/Components/CopyKeyView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import SwiftUI

/// A bordered view that shows a key and a button to copy it. When the user taps the copy button,
/// its title changes to "Copied!".
struct CopyKeyView: View {
let buttonTitle: LocalizedStringKey

@Binding var keyString: String
@Binding var copyButtonState: CopyButtonState

init(_ buttonTitle: LocalizedStringKey, keyString: Binding<String>, copyButtonState: Binding<CopyButtonState>) {
self.buttonTitle = buttonTitle
_keyString = keyString
_copyButtonState = copyButtonState
}

var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text(keyString)
HStack {
if copyButtonState == .copy {
Image.copyIcon
.frame(width: 20, height: 20)
} else {
Image(systemName: "checkmark")
.frame(width: 20, height: 20)
}
Button {
UIPasteboard.general.string = keyString
copyButtonState = .copied
Task { @MainActor in
try await Task.sleep(for: .seconds(10))
copyButtonState = .copy
}
} label: {
Text(copyButtonState == .copy ? buttonTitle : "copied")
}
Spacer()
}
.foregroundStyle(Color.actionTertiary)
}
.padding()
.withStyledBorder()
}
}

#Preview {
@State var privateKey = KeyFixture.nsec
@State var privateCopyButtonState = CopyButtonState.copy

@State var publicKey = KeyFixture.npub
@State var publicCopyButtonState = CopyButtonState.copied

return VStack(spacing: 40) {
CopyKeyView("copyPrivateKey", keyString: $privateKey, copyButtonState: $privateCopyButtonState)
CopyKeyView("copyPublicKey", keyString: $publicKey, copyButtonState: $publicCopyButtonState)
}
}

enum KeyType {
case `public`
case `private`
}
File renamed without changes.
4 changes: 4 additions & 0 deletions Nos/Views/Onboarding/OnboardingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum OnboardingStep {
case notOldEnough
case createAccount
case privateKey
case publicKey
case buildYourNetwork
case login
}
Expand Down Expand Up @@ -53,6 +54,9 @@ struct OnboardingView: View {
case .privateKey:
PrivateKeyView()
.environment(state)
case .publicKey:
PublicKeyView()
.environment(state)
case .login:
OnboardingLoginView(completion: completion)
case .buildYourNetwork:
Expand Down
43 changes: 2 additions & 41 deletions Nos/Views/Onboarding/PrivateKeyView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,17 @@ struct PrivateKeyView: View {
.foregroundStyle(Color.secondaryTxt)
}
PrivateKeyDescription()
BorderedPrivateKey(privateKeyString: $privateKeyString, copyButtonState: $copyButtonState)
CopyKeyView("copyPrivateKey", keyString: $privateKeyString, copyButtonState: $copyButtonState)
Spacer()
BigActionButton("next") {
state.step = .buildYourNetwork
state.step = .publicKey
}
}
.padding(40)
.readabilityPadding()
}
}

fileprivate enum CopyButtonState {
case copy
case copied
}

fileprivate struct PrivateKeyDescription: View {
var body: some View {
let attributedString = AttributedString(localized: "privateKeyDescription")
Expand All @@ -73,40 +68,6 @@ fileprivate struct PrivateKeyDescription: View {
}
}

fileprivate struct BorderedPrivateKey: View {
@Binding var privateKeyString: String
@Binding var copyButtonState: CopyButtonState

var body: some View {
VStack(alignment: .leading, spacing: 16) {
Text(privateKeyString)
HStack {
if copyButtonState == .copy {
Image.copyIcon
.frame(width: 20, height: 20)
} else {
Image(systemName: "checkmark")
.frame(width: 20, height: 20)
}
Button {
UIPasteboard.general.string = privateKeyString
copyButtonState = .copied
Task { @MainActor in
try await Task.sleep(for: .seconds(10))
copyButtonState = .copy
}
} label: {
Text(copyButtonState == .copy ? "copyPrivateKey" : "copied")
}
Spacer()
}
.foregroundStyle(Color.actionTertiary)
}
.padding()
.withStyledBorder()
}
}

#Preview {
PrivateKeyView()
.environment(OnboardingState())
Expand Down
59 changes: 59 additions & 0 deletions Nos/Views/Onboarding/PublicKeyView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import Dependencies
import SwiftUI

/// The Public Key view in the onboarding.
struct PublicKeyView: View {
@Environment(OnboardingState.self) private var state
@Environment(CurrentUser.self) var currentUser

@State private var publicKeyString = ""
@State private var copyButtonState: CopyButtonState = .copy

var body: some View {
ZStack {
Color.appBg
.ignoresSafeArea()
ViewThatFits(in: .vertical) {
publicKeyStack

ScrollView {
publicKeyStack
}
}
.onAppear {
publicKeyString = currentUser.keyPair?.npub ?? ""
}
}
.navigationBarHidden(true)
}

var publicKeyStack: some View {
VStack(alignment: .leading, spacing: 20) {
LargeNumberView(2)
HStack(alignment: .firstTextBaseline) {
Text("publicKeyHeadline")
.font(.clarityBold(.title))
.foregroundStyle(Color.primaryTxt)
Text("publicKeyNpubParenthetical")
.font(.clarityRegular(.title2))
.foregroundStyle(Color.secondaryTxt)
}
Text("publicKeyDescription")
.font(.body)
.foregroundStyle(Color.secondaryTxt)
CopyKeyView("copyPublicKey", keyString: $publicKeyString, copyButtonState: $copyButtonState)
Spacer()
BigActionButton("next") {
state.step = .buildYourNetwork
}
}
.padding(40)
.readabilityPadding()
}
}

#Preview {
PublicKeyView()
.environment(OnboardingState())
.inject(previewData: PreviewData())
}
5 changes: 0 additions & 5 deletions Nos/Views/Settings/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ struct SettingsView: View {
case deleteAccount
}

fileprivate enum CopyButtonState {
case copy
case copied
}

var body: some View {
Form {
Section {
Expand Down

0 comments on commit 244247d

Please sign in to comment.