Browse Source

initial CreateAccountView

Signed-off-by: William Casarin <jb55@jb55.com>
profiles-everywhere
William Casarin 2 years ago
parent
commit
2920325639
  1. 1
      .gitignore
  2. 20
      damus.xcodeproj/project.pbxproj
  3. 29
      damus/ContentView.swift
  4. 40
      damus/Models/CreateAccountModel.swift
  5. 2
      damus/Util/ImageCache.swift
  6. 43
      damus/Util/Keys.swift
  7. 142
      damus/Views/CreateAccountView.swift
  8. 2
      damus/Views/EventView.swift
  9. 2
      damus/Views/FollowingView.swift
  10. 6
      damus/Views/PostView.swift
  11. 28
      damus/Views/ProfilePicView.swift
  12. 30
      damus/Views/ProfilePictureSelector.swift
  13. 2
      damus/Views/ProfileView.swift
  14. 113
      damus/Views/SaveKeysView.swift
  15. 101
      damus/Views/SetupView.swift
  16. 26
      damus/damusApp.swift
  17. 4
      damusTests/LikeTests.swift

1
.gitignore

@ -1,4 +1,3 @@
xcuserdata
Preview\ Content
damus/TestingPrivate.swift
.DS_Store

20
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 */,

29
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")
}

40
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
}
}

2
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)
}

43
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")
}

142
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)
}

2
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()

2
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) {

6
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)
}

28
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 {

30
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)
}
}

2
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()

113
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)
}
}

101
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 {
}
}
}

26
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()
}

4
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"))

Loading…
Cancel
Save