commit 2920325639b4ae8bd4cf51a0835d2c06c581d10f
parent 0f453c39e6a9082705cac0e0e20f88f200e90d07
Author: William Casarin <jb55@jb55.com>
Date: Sat, 21 May 2022 19:44:04 -0700
initial CreateAccountView
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
17 files changed, 502 insertions(+), 89 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,3 @@
xcuserdata
-Preview\ Content
damus/TestingPrivate.swift
.DS_Store
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -14,6 +14,11 @@
4C0A3F95280F6C78000448DE /* ReplyQuoteView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0A3F94280F6C78000448DE /* ReplyQuoteView.swift */; };
4C0A3F97280F8E02000448DE /* ThreadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C0A3F96280F8E02000448DE /* ThreadView.swift */; };
4C285C8228385570008A31F1 /* CarouselView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8128385570008A31F1 /* CarouselView.swift */; };
+ 4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8328385690008A31F1 /* CreateAccountView.swift */; };
+ 4C285C86283892E7008A31F1 /* CreateAccountModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C85283892E7008A31F1 /* CreateAccountModel.swift */; };
+ 4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */; };
+ 4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8B28398BC6008A31F1 /* Keys.swift */; };
+ 4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */; };
4C363A8428233689006E126D /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8328233689006E126D /* Parser.swift */; };
4C363A8628234FDE006E126D /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8528234FDE006E126D /* ImageCache.swift */; };
4C363A8828236948006E126D /* BlocksView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C363A8728236948006E126D /* BlocksView.swift */; };
@@ -105,6 +110,11 @@
4C0A3F94280F6C78000448DE /* ReplyQuoteView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyQuoteView.swift; sourceTree = "<group>"; };
4C0A3F96280F8E02000448DE /* ThreadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadView.swift; sourceTree = "<group>"; };
4C285C8128385570008A31F1 /* CarouselView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselView.swift; sourceTree = "<group>"; };
+ 4C285C8328385690008A31F1 /* CreateAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountView.swift; sourceTree = "<group>"; };
+ 4C285C85283892E7008A31F1 /* CreateAccountModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateAccountModel.swift; sourceTree = "<group>"; };
+ 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfilePictureSelector.swift; sourceTree = "<group>"; };
+ 4C285C8B28398BC6008A31F1 /* Keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Keys.swift; sourceTree = "<group>"; };
+ 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveKeysView.swift; sourceTree = "<group>"; };
4C363A8328233689006E126D /* Parser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = "<group>"; };
4C363A8528234FDE006E126D /* ImageCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = "<group>"; };
4C363A8728236948006E126D /* BlocksView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlocksView.swift; sourceTree = "<group>"; };
@@ -219,6 +229,7 @@
4C363A9B282838B9006E126D /* EventRef.swift */,
4C363AA328296DEE006E126D /* SearchModel.swift */,
4C3AC79A28306D7B00E1F516 /* Contacts.swift */,
+ 4C285C85283892E7008A31F1 /* CreateAccountModel.swift */,
);
path = Models;
sourceTree = "<group>";
@@ -252,6 +263,9 @@
4C3AC7A42836987600E1F516 /* MainTabView.swift */,
4C3AC7A628369BA200E1F516 /* SearchHomeView.swift */,
4C285C8128385570008A31F1 /* CarouselView.swift */,
+ 4C285C8328385690008A31F1 /* CreateAccountView.swift */,
+ 4C285C892838B985008A31F1 /* ProfilePictureSelector.swift */,
+ 4C285C8D28399BFD008A31F1 /* SaveKeysView.swift */,
);
path = Views;
sourceTree = "<group>";
@@ -284,6 +298,7 @@
4C363A8528234FDE006E126D /* ImageCache.swift */,
4C363AA728297703006E126D /* InsertSort.swift */,
4C477C9D282C3A4800033AA3 /* TipCounter.swift */,
+ 4C285C8B28398BC6008A31F1 /* Keys.swift */,
);
path = Util;
sourceTree = "<group>";
@@ -502,7 +517,9 @@
4C3AC79D2833036D00E1F516 /* FollowingView.swift in Sources */,
4C363A8A28236B57006E126D /* MentionView.swift in Sources */,
4CE4F8CD281352B30009DFBB /* Notifications.swift in Sources */,
+ 4C285C8428385690008A31F1 /* CreateAccountView.swift in Sources */,
4C363AA828297703006E126D /* InsertSort.swift in Sources */,
+ 4C285C86283892E7008A31F1 /* CreateAccountModel.swift in Sources */,
4C363A8C28236B92006E126D /* PubkeyView.swift in Sources */,
4C363A8628234FDE006E126D /* ImageCache.swift in Sources */,
4C75EFB728049D990006080F /* RelayPool.swift in Sources */,
@@ -510,6 +527,7 @@
4CEE2AF5280B29E600AB5EEF /* TimeAgo.swift in Sources */,
4C75EFAD28049CFB0006080F /* PostButton.swift in Sources */,
4C363AA228296A7E006E126D /* SearchView.swift in Sources */,
+ 4C285C8A2838B985008A31F1 /* ProfilePictureSelector.swift in Sources */,
4C75EFB92804A2740006080F /* EventView.swift in Sources */,
4C7FF7D52823313F009601DB /* Mentions.swift in Sources */,
4C363A9828283441006E126D /* TestingPrivate.swift in Sources */,
@@ -518,6 +536,7 @@
4C477C9E282C3A4800033AA3 /* TipCounter.swift in Sources */,
4C0A3F91280F6528000448DE /* ChatView.swift in Sources */,
4C75EFA627FF87A20006080F /* Nostr.swift in Sources */,
+ 4C285C8E28399BFE008A31F1 /* SaveKeysView.swift in Sources */,
4C75EFB328049D640006080F /* NostrEvent.swift in Sources */,
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */,
4C363A8428233689006E126D /* Parser.swift in Sources */,
@@ -533,6 +552,7 @@
4C3BEFD22819DB9B00B3DE84 /* ProfileModel.swift in Sources */,
4C0A3F93280F66F5000448DE /* ReplyMap.swift in Sources */,
4C3AC7A12835A81400E1F516 /* SetupView.swift in Sources */,
+ 4C285C8C28398BC7008A31F1 /* Keys.swift in Sources */,
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
4C363A94282704FA006E126D /* Post.swift in Sources */,
4C363A8828236948006E126D /* BlocksView.swift in Sources */,
diff --git a/damus/ContentView.swift b/damus/ContentView.swift
@@ -31,6 +31,8 @@ enum ThreadState {
}
struct ContentView: View {
+ let pubkey: String
+ let privkey: String
@State var status: String = "Not connected"
@State var active_sheet: Sheets? = nil
@State var loading: Bool = true
@@ -56,8 +58,6 @@ struct ContentView: View {
let timer = Timer.publish(every: 60, on: .main, in: .common).autoconnect()
let sub_id = UUID().description
- let pubkey = MY_PUBKEY
- let privkey = MY_PRIVKEY
var LoadingContainer: some View {
VStack {
@@ -708,28 +708,3 @@ func update_filters_with_since(last_of_kind: [Int: NostrEvent], filters: [NostrF
}
}
-struct Keypair {
- let pubkey: String
- let privkey: String
-}
-
-func save_keypair(pubkey: String, privkey: String) {
- UserDefaults.standard.set(pubkey, forKey: "pubkey")
- UserDefaults.standard.set(privkey, forKey: "privkey")
-}
-
-func get_saved_keypair() -> Keypair? {
- get_saved_pubkey().flatMap { pubkey in
- get_saved_privkey().map { privkey in
- return Keypair(pubkey: pubkey, privkey: privkey)
- }
- }
-}
-
-func get_saved_pubkey() -> String? {
- return UserDefaults.standard.string(forKey: "pubkey")
-}
-
-func get_saved_privkey() -> String? {
- return UserDefaults.standard.string(forKey: "privkey")
-}
diff --git a/damus/Models/CreateAccountModel.swift b/damus/Models/CreateAccountModel.swift
@@ -0,0 +1,40 @@
+//
+// CreateAccountModel.swift
+// damus
+//
+// Created by William Casarin on 2022-05-20.
+//
+
+import Foundation
+
+
+class CreateAccountModel: ObservableObject {
+ @Published var real_name: String = ""
+ @Published var nick_name: String = ""
+ @Published var about: String = ""
+ @Published var pubkey: String = ""
+ @Published var privkey: String = ""
+
+ var rendered_name: String {
+ if real_name.isEmpty {
+ return nick_name
+ }
+ return real_name
+ }
+
+ init() {
+ let keypair = generate_new_keypair()
+ self.pubkey = keypair.pubkey
+ self.privkey = keypair.privkey
+ }
+
+ init(real: String, nick: String, about: String) {
+ let keypair = generate_new_keypair()
+ self.pubkey = keypair.pubkey
+ self.privkey = keypair.privkey
+
+ self.real_name = real
+ self.nick_name = nick
+ self.about = about
+ }
+}
diff --git a/damus/Util/ImageCache.swift b/damus/Util/ImageCache.swift
@@ -54,7 +54,7 @@ class ImageCache {
func insert(_ image: UIImage?, for url: URL) {
guard let image = image else { return remove(for: url) }
- let decodedImage = image.decodedImage(Int(PFP_SIZE!))
+ let decodedImage = image.decodedImage(Int(PFP_SIZE))
lock.lock(); defer { lock.unlock() }
cache.setObject(decodedImage, forKey: url as AnyObject)
}
diff --git a/damus/Util/Keys.swift b/damus/Util/Keys.swift
@@ -0,0 +1,43 @@
+//
+// Keys.swift
+// damus
+//
+// Created by William Casarin on 2022-05-21.
+//
+
+import Foundation
+import secp256k1
+
+struct Keypair {
+ let pubkey: String
+ let privkey: String
+}
+
+func generate_new_keypair() -> Keypair {
+ let key = try! secp256k1.Signing.PrivateKey()
+ let privkey = hex_encode(key.rawRepresentation)
+ let pubkey = hex_encode(Data(key.publicKey.xonlyKeyBytes))
+ print("generating privkey:\(privkey) pubkey:\(pubkey)")
+ return Keypair(pubkey: pubkey, privkey: privkey)
+}
+
+func save_keypair(pubkey: String, privkey: String) {
+ UserDefaults.standard.set(pubkey, forKey: "pubkey")
+ UserDefaults.standard.set(privkey, forKey: "privkey")
+}
+
+func get_saved_keypair() -> Keypair? {
+ get_saved_pubkey().flatMap { pubkey in
+ get_saved_privkey().map { privkey in
+ return Keypair(pubkey: pubkey, privkey: privkey)
+ }
+ }
+}
+
+func get_saved_pubkey() -> String? {
+ return UserDefaults.standard.string(forKey: "pubkey")
+}
+
+func get_saved_privkey() -> String? {
+ return UserDefaults.standard.string(forKey: "privkey")
+}
diff --git a/damus/Views/CreateAccountView.swift b/damus/Views/CreateAccountView.swift
@@ -0,0 +1,142 @@
+//
+// CreateAccountView.swift
+// damus
+//
+// Created by William Casarin on 2022-05-20.
+//
+
+import SwiftUI
+
+struct CreateAccountView: View {
+ @StateObject var account: CreateAccountModel = CreateAccountModel()
+ @State var is_light: Bool = false
+ @State var is_done: Bool = false
+
+ func FormTextInput(_ title: String, text: Binding<String>) -> some View {
+ return TextField("", text: text)
+ .placeholder(when: text.wrappedValue.isEmpty) {
+ Text(title).foregroundColor(.white.opacity(0.4))
+ }
+ .padding()
+ .background {
+ RoundedRectangle(cornerRadius: 4.0).opacity(0.2)
+ }
+ .foregroundColor(.white)
+ .font(.body.bold())
+ }
+
+ func FormLabel(_ title: String, optional: Bool = false) -> some View {
+ return HStack {
+ Text(title)
+ .bold()
+ .foregroundColor(.white)
+ if optional {
+ Text("optional")
+ .font(.callout)
+ .foregroundColor(.white.opacity(0.5))
+ }
+ }
+ }
+
+ func SignupForm<FormContent: View>(@ViewBuilder content: () -> FormContent) -> some View {
+ return VStack(alignment: .leading, spacing: 10.0, content: content)
+ }
+
+ func regen_key() {
+ let keypair = generate_new_keypair()
+ self.account.pubkey = keypair.pubkey
+ self.account.privkey = keypair.privkey
+ }
+
+ var body: some View {
+ ZStack(alignment: .top) {
+ DamusGradient()
+
+ VStack {
+ Text("Create Account")
+ .font(.title.bold())
+ .foregroundColor(.white)
+
+ ProfilePictureSelector(pubkey: account.pubkey)
+
+ HStack(alignment: .top) {
+ VStack {
+ Text(" ")
+ .foregroundColor(.white)
+ }
+ VStack {
+ SignupForm {
+ FormLabel("Username")
+ HStack(spacing: 0.0) {
+ Text("@")
+ .foregroundColor(.white)
+ .padding(.leading, -25.0)
+
+ FormTextInput("satoshi", text: $account.nick_name)
+ .textInputAutocapitalization(.never)
+
+ }
+
+ FormLabel("Display Name", optional: true)
+ FormTextInput("Satoshi Nakamoto", text: $account.real_name)
+ .textInputAutocapitalization(.words)
+
+ FormLabel("About", optional: true)
+ FormTextInput("Creator(s) of Bitcoin. Absolute legend.", text: $account.about)
+
+ FormLabel("Account ID")
+ .onTapGesture {
+ regen_key()
+ }
+
+ KeyInput($account.pubkey)
+ .onTapGesture {
+ regen_key()
+ }
+ }
+ }
+ }
+
+ NavigationLink(destination: SaveKeysView(account: account), isActive: $is_done) {
+ EmptyView()
+ }
+ DamusWhiteButton("Create") {
+ self.is_done = true
+ }
+ .padding()
+ }
+ .padding(.leading, 14.0)
+ .padding(.trailing, 20.0)
+
+ }
+ .navigationBarTitleDisplayMode(.inline)
+ }
+}
+
+extension View {
+ func placeholder<Content: View>(
+ when shouldShow: Bool,
+ alignment: Alignment = .leading,
+ @ViewBuilder placeholder: () -> Content) -> some View {
+
+ ZStack(alignment: alignment) {
+ placeholder().opacity(shouldShow ? 1 : 0)
+ self
+ }
+ }
+}
+
+struct CreateAccountView_Previews: PreviewProvider {
+ static var previews: some View {
+ let model = CreateAccountModel(real: "", nick: "jb55", about: "")
+ return CreateAccountView(account: model)
+ }
+}
+
+func KeyInput(_ text: Binding<String>) -> some View {
+ return Text("\(text.wrappedValue)")
+ .textSelection(.enabled)
+ .font(.callout.monospaced())
+ .foregroundColor(.white)
+}
+
diff --git a/damus/Views/EventView.swift b/damus/Views/EventView.swift
@@ -72,7 +72,7 @@ struct EventView: View {
let pv = ProfileView(damus_state: damus, profile: pmodel)
NavigationLink(destination: pv) {
- ProfilePicView(pubkey: event.pubkey, size: PFP_SIZE!, highlight: highlight, image_cache: damus.image_cache, profiles: damus.profiles)
+ ProfilePicView(pubkey: event.pubkey, size: PFP_SIZE, highlight: highlight, image_cache: damus.image_cache, profiles: damus.profiles)
}
Spacer()
diff --git a/damus/Views/FollowingView.swift b/damus/Views/FollowingView.swift
@@ -17,7 +17,7 @@ struct FollowUserView: View {
let pv = ProfileView(damus_state: damus_state, profile: pmodel)
NavigationLink(destination: pv) {
- ProfilePicView(pubkey: pubkey, size: PFP_SIZE!, highlight: .none, image_cache: damus_state.image_cache, profiles: damus_state.profiles)
+ ProfilePicView(pubkey: pubkey, size: PFP_SIZE, highlight: .none, image_cache: damus_state.image_cache, profiles: damus_state.profiles)
}
VStack(alignment: .leading) {
diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift
@@ -56,9 +56,6 @@ struct PostView: View {
HStack(alignment: .top) {
ZStack(alignment: .leading) {
- TextEditor(text: $post)
- .focused($focus)
-
if self.post == "" {
VStack {
Text("What's happening?")
@@ -67,6 +64,9 @@ struct PostView: View {
Spacer()
}
}
+
+ TextEditor(text: $post)
+ .focused($focus)
}
diff --git a/damus/Views/ProfilePicView.swift b/damus/Views/ProfilePicView.swift
@@ -7,8 +7,7 @@
import SwiftUI
-let PFP_SIZE: CGFloat? = 52.0
-let CORNER_RADIUS: CGFloat = 32
+let PFP_SIZE: CGFloat = 52.0
func id_to_color(_ id: String) -> Color {
return hex_to_rgb(id)
@@ -47,9 +46,9 @@ struct ProfilePicView: View {
}
var Placeholder: some View {
- PlaceholderColor.opacity(0.5)
+ PlaceholderColor
.frame(width: size, height: size)
- .cornerRadius(CORNER_RADIUS)
+ .clipShape(Circle())
.overlay(Circle().stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
.padding(2)
}
@@ -100,14 +99,27 @@ struct ProfilePicView: View {
}
}
-/*
+func make_preview_profiles(_ pubkey: String) -> Profiles {
+ let profiles = Profiles()
+ let picture = "http://cdn.jb55.com/img/red-me.jpg"
+ let profile = Profile(name: "Will", about: "It's me", picture: picture)
+ let ts_profile = TimestampedProfile(profile: profile, timestamp: 0)
+ profiles.add(id: pubkey, profile: ts_profile)
+ return profiles
+}
+
struct ProfilePicView_Previews: PreviewProvider {
+ static let pubkey = "ca48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846"
+
static var previews: some View {
- ProfilePicView(picture: "http://cdn.jb55.com/img/red-me.jpg", size: 64, highlight: .none)
+ ProfilePicView(
+ pubkey: pubkey,
+ size: 100,
+ highlight: .none,
+ image_cache: ImageCache(),
+ profiles: make_preview_profiles(pubkey))
}
}
- */
-
func hex_to_rgb(_ hex: String) -> Color {
guard hex.count >= 6 else {
diff --git a/damus/Views/ProfilePictureSelector.swift b/damus/Views/ProfilePictureSelector.swift
@@ -0,0 +1,30 @@
+//
+// ProfilePictureSelector.swift
+// damus
+//
+// Created by William Casarin on 2022-05-20.
+//
+
+import SwiftUI
+
+struct ProfilePictureSelector: View {
+ let pubkey: String
+
+ var body: some View {
+ let highlight: Highlight = .custom(Color.white, 2.0)
+ ZStack {
+ ProfilePicView(pubkey: pubkey, size: 80.0, highlight: highlight, image_cache: ImageCache(), profiles: Profiles())
+
+ Image(systemName: "camera")
+ .font(.title)
+ .foregroundColor(.white)
+ }
+ }
+}
+
+struct ProfilePictureSelector_Previews: PreviewProvider {
+ static var previews: some View {
+ let test_pubkey = "ff48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846"
+ ProfilePictureSelector(pubkey: test_pubkey)
+ }
+}
diff --git a/damus/Views/ProfileView.swift b/damus/Views/ProfileView.swift
@@ -72,7 +72,7 @@ struct ProfileView: View {
VStack(alignment: .leading) {
let data = damus_state.profiles.lookup(id: profile.pubkey)
HStack(alignment: .top) {
- ProfilePicView(pubkey: profile.pubkey, size: PFP_SIZE!, highlight: .custom(Color.black, 2), image_cache: damus_state.image_cache, profiles: damus_state.profiles)
+ ProfilePicView(pubkey: profile.pubkey, size: PFP_SIZE, highlight: .custom(Color.black, 2), image_cache: damus_state.image_cache, profiles: damus_state.profiles)
Spacer()
diff --git a/damus/Views/SaveKeysView.swift b/damus/Views/SaveKeysView.swift
@@ -0,0 +1,113 @@
+//
+// SaveKeysView.swift
+// damus
+//
+// Created by William Casarin on 2022-05-21.
+//
+
+import SwiftUI
+
+struct SaveKeysView: View {
+ let account: CreateAccountModel
+ @State var is_done: Bool = false
+ @State var pub_copied: Bool = false
+ @State var priv_copied: Bool = false
+
+ var body: some View {
+ ZStack(alignment: .top) {
+ DamusGradient()
+
+ VStack(alignment: .center) {
+ Text("Welcome, \(account.rendered_name)!")
+ .font(.title.bold())
+ .foregroundColor(.white)
+ .padding(.bottom, 10)
+
+ Text("Before we get started, you'll need to save your account info, otherwise you won't be able to login in the future if you ever uninstall Damus.")
+ .foregroundColor(.white)
+ .padding(.bottom, 10)
+
+ Text("Public Key")
+ .font(.title2.bold())
+ .foregroundColor(.white)
+ .padding(.bottom, 10)
+
+ Text("This is your account ID, you can give this to your friends so that they can follow you")
+ .foregroundColor(.white)
+ .padding(.bottom, 10)
+
+ SaveKeyView(text: account.pubkey, is_copied: $pub_copied)
+ .padding(.bottom, 10)
+
+ Text("Private Key")
+ .font(.title2.bold())
+ .foregroundColor(.white)
+ .padding(.bottom, 10)
+
+ Text("This is your secret account key. You need this to access your account. Don't share this with anyone! Save it in a password manager and keep it safe!")
+ .foregroundColor(.white)
+ .padding(.bottom, 10)
+
+ SaveKeyView(text: account.privkey, is_copied: $priv_copied)
+ .padding(.bottom, 10)
+
+ if pub_copied && priv_copied {
+ DamusWhiteButton("Let's go!") {
+ save_keypair(pubkey: account.pubkey, privkey: account.privkey)
+ notify(.login, ())
+ }
+ }
+ }
+ .padding(20)
+ }
+ }
+}
+
+struct SaveKeyView: View {
+ let text: String
+ @Binding var is_copied: Bool
+
+ func copy_text() {
+ UIPasteboard.general.string = text
+ is_copied = true
+ }
+
+ var body: some View {
+ HStack {
+ Button(action: copy_text) {
+ Label("", systemImage: is_copied ? "checkmark.circle.fill" : "doc.on.doc")
+ .foregroundColor(is_copied ? .green : .white)
+ .background {
+ if is_copied {
+ Circle()
+ .foregroundColor(.white)
+ .frame(width: 25, height: 25, alignment: .center)
+ .padding(.leading, -8)
+ .padding(.top, 1)
+ } else {
+ EmptyView()
+ }
+ }
+ }
+
+ Text(text)
+ .padding(5)
+ .background {
+ RoundedRectangle(cornerRadius: 4.0).opacity(0.2)
+ }
+ .textSelection(.enabled)
+ .font(.callout.monospaced())
+ .foregroundColor(.white)
+ .onTapGesture {
+ copy_text()
+ }
+ }
+ }
+}
+
+struct SaveKeysView_Previews: PreviewProvider {
+ static var previews: some View {
+ let model = CreateAccountModel(real: "William", nick: "jb55", about: "I'm me")
+ SaveKeysView(account: model)
+ }
+}
diff --git a/damus/Views/SetupView.swift b/damus/Views/SetupView.swift
@@ -20,50 +20,80 @@ let damus_grad_c2 = hex_col(r: 0x7f, g: 0x35, b: 0xab)
let damus_grad_c3 = hex_col(r: 0xff, g: 0x0b, b: 0xd6)
let damus_grad = [damus_grad_c1, damus_grad_c2, damus_grad_c3]
+enum SetupState {
+ case home
+ case create_account
+ case login
+}
+
+struct DamusGradient: View {
+ var body: some View {
+ LinearGradient(colors: damus_grad, startPoint: .bottomLeading, endPoint: .topTrailing)
+ .edgesIgnoringSafeArea([.top,.bottom])
+ }
+}
+
struct SetupView: View {
+ @State var state: SetupState? = .home
+
var body: some View {
- ZStack {
- LinearGradient(colors: damus_grad, startPoint: .bottomLeading, endPoint: .topTrailing)
- .edgesIgnoringSafeArea([.top,.bottom])
-
- VStack(alignment: .center) {
- Image("logo-nobg")
- .resizable()
- .frame(width: 128.0, height: 128.0, alignment: .center)
- .padding([.top], 20.0)
- Text("Damus")
- .font(Font.custom("Nunito", size: 50.0))
- .kerning(-2)
- .foregroundColor(.white)
-
- CarouselView()
+ NavigationView {
+ ZStack {
+ DamusGradient()
- Spacer()
-
- Button("Create Account") {
- print("Create Account")
- }
- .font(.body.bold())
- .foregroundColor(.white)
- .frame(width: 300, height: 50)
- .background(
- RoundedRectangle(cornerRadius: 4.0)
- .stroke(Color.white, lineWidth: 2.0)
- .background(Color.white.opacity(0.15))
- )
-
- Button("Login") {
- notify(.login, ())
+ VStack(alignment: .center) {
+ NavigationLink(destination: CreateAccountView(), tag: .create_account, selection: $state ) {
+ EmptyView()
+ }
+
+ Image("logo-nobg")
+ .resizable()
+ .frame(width: 128.0, height: 128.0, alignment: .center)
+ .padding([.top], 20.0)
+ Text("Damus")
+ .font(Font.custom("Nunito", size: 50.0))
+ .kerning(-2)
+ .foregroundColor(.white)
+
+ CarouselView()
+
+ Spacer()
+
+ DamusWhiteButton("Create Account") {
+ self.state = .create_account
+ }
+
+ Button("Login") {
+ notify(.login, ())
+ }
+ .padding([.top, .bottom], 20)
+ .foregroundColor(.white)
+
+ Spacer()
}
- .foregroundColor(.white)
- .padding([.top], 20)
-
- Spacer()
}
+ .padding(.top, -80)
}
+ .navigationBarTitleDisplayMode(.inline)
+ .navigationViewStyle(StackNavigationViewStyle())
}
}
+func DamusWhiteButton(_ title: String, action: @escaping () -> ()) -> some View {
+ return Button(action: action) {
+ Text(title)
+ .frame(width: 300, height: 50)
+ .font(.body.bold())
+ .contentShape(Rectangle())
+ .foregroundColor(.white)
+ .background(
+ RoundedRectangle(cornerRadius: 4.0)
+ .stroke(Color.white, lineWidth: 2.0)
+ .background(Color.white.opacity(0.15))
+ )
+ }
+
+}
struct SetupView_Previews: PreviewProvider {
static var previews: some View {
@@ -75,3 +105,4 @@ struct SetupView_Previews: PreviewProvider {
}
}
}
+
diff --git a/damus/damusApp.swift b/damus/damusApp.swift
@@ -21,21 +21,27 @@ struct damusApp: App {
struct MainView: View {
@State var needs_setup = true;
+ @State var keypair: Keypair? = nil;
var body: some View {
- if needs_setup {
- SetupView()
- .onReceive(handle_notify(.login)) { notif in
- needs_setup = false
- }
- } else {
- ContentView()
+ Group {
+ if let kp = keypair, !needs_setup {
+ ContentView(pubkey: kp.pubkey, privkey: kp.privkey)
+ } else {
+ SetupView()
+ .onReceive(handle_notify(.login)) { notif in
+ needs_setup = false
+ keypair = get_saved_keypair()
+ }
+ }
+ }
+ .onAppear {
+ keypair = get_saved_keypair()
}
}
}
-func needs_setup() -> Bool {
- let _ = get_saved_privkey()
- return true
+func needs_setup() -> Keypair? {
+ return get_saved_keypair()
}
diff --git a/damusTests/LikeTests.swift b/damusTests/LikeTests.swift
@@ -19,10 +19,12 @@ class LikeTests: XCTestCase {
}
func testLikeHasNotification() throws {
+ let privkey = "0fc2092231f958f8d57d66f5e238bb45b6a2571f44c0ce024bbc6f3a9c8a15fe"
+ let pubkey = "30c6d1dc7f7c156794fa15055e651b758a61b99f50fcf759de59386050bf6ae2"
let liked = NostrEvent(content: "awesome #[0] post", pubkey: "orig_pk", tags: [["p", "cindy"], ["e", "bob"]])
liked.calculate_id()
let id = liked.id
- let like_ev = make_like_event(pubkey: "pubkey", liked: liked)!
+ let like_ev = make_like_event(pubkey: pubkey, privkey: privkey, liked: liked)
XCTAssertTrue(like_ev.references(id: "orig_pk", key: "p"))
XCTAssertTrue(like_ev.references(id: "cindy", key: "p"))