damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 534969e616ab8bbe2b8cec1295ab28ec94b7bc48
parent 75a9b4df7fdc59ddfa419bb9f6c6b389dceaf59f
Author: Daniel D’Aquino <daniel@daquino.me>
Date:   Sun, 14 Jan 2024 21:55:04 +0000

purple: add support for LN checkout flow

This commit adds support for the LN checkout flow, and the Purple
landing page:

1. It adds a "learn more" button on the Damus Purple view, where the
   user can learn more
2. It adds new `damus:purple` urls to enable the LN checkout flow

Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 24++++++++++++++++++------
Mdamus/ContentView.swift | 11+++++++++++
Mdamus/Models/Purple/DamusPurple.swift | 25+++++++++++++++++++++++++
Adamus/Models/Purple/DamusPurpleURL.swift | 43+++++++++++++++++++++++++++++++++++++++++++
Mdamus/Util/Constants.swift | 2++
Adamus/Views/Purple/DamusPurpleURLSheetView.swift | 34++++++++++++++++++++++++++++++++++
Adamus/Views/Purple/DamusPurpleVerifyNpubView.swift | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdamus/Views/Purple/DamusPurpleView.swift | 75++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
8 files changed, 243 insertions(+), 35 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -445,9 +445,6 @@ D72A2D072AD9C1FB002AFF62 /* MockProfiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A2D062AD9C1FB002AFF62 /* MockProfiles.swift */; }; D7315A2A2ACDF3B70036E30A /* DamusCacheManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7315A292ACDF3B70036E30A /* DamusCacheManager.swift */; }; D7315A2C2ACDF4DA0036E30A /* DamusCacheManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7315A2B2ACDF4DA0036E30A /* DamusCacheManagerTests.swift */; }; - D74F430A2B23F0BE00425B75 /* DamusPurple.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74F43092B23F0BE00425B75 /* DamusPurple.swift */; }; - D74F430C2B23FB9B00425B75 /* StoreObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74F430B2B23FB9B00425B75 /* StoreObserver.swift */; }; - D76556D62B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */; }; D74AAFC22B153395006CF0F4 /* HeadlessDamusState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AAFC12B153395006CF0F4 /* HeadlessDamusState.swift */; }; D74AAFC32B153395006CF0F4 /* HeadlessDamusState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AAFC12B153395006CF0F4 /* HeadlessDamusState.swift */; }; D74AAFC52B1538DF006CF0F4 /* NotificationExtensionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AAFC42B1538DE006CF0F4 /* NotificationExtensionState.swift */; }; @@ -463,6 +460,9 @@ D74AAFD22B155E78006CF0F4 /* WalletConnect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C7D09612A098D0E00943473 /* WalletConnect.swift */; }; D74AAFD42B155ECB006CF0F4 /* Zaps+.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AAFD32B155ECB006CF0F4 /* Zaps+.swift */; }; D74AAFD62B155F0C006CF0F4 /* WalletConnect+.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74AAFD52B155F0C006CF0F4 /* WalletConnect+.swift */; }; + D74F430A2B23F0BE00425B75 /* DamusPurple.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74F43092B23F0BE00425B75 /* DamusPurple.swift */; }; + D74F430C2B23FB9B00425B75 /* StoreObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74F430B2B23FB9B00425B75 /* StoreObserver.swift */; }; + D76556D62B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */; }; D76874F32AE3632B00FB0F68 /* ProfileZapLinkView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76874F22AE3632B00FB0F68 /* ProfileZapLinkView.swift */; }; D77BFA0B2AE3051200621634 /* ProfileActionSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77BFA0A2AE3051200621634 /* ProfileActionSheetView.swift */; }; D783A63F2AD4E53D00658DDA /* SuggestedHashtagsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D783A63E2AD4E53D00658DDA /* SuggestedHashtagsView.swift */; }; @@ -491,6 +491,9 @@ D79C4C1B2AFEB061003A41B4 /* DamusNotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D79C4C142AFEB061003A41B4 /* DamusNotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; D7A343EE2AD0D77C00CED48B /* InlineSnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = D7A343ED2AD0D77C00CED48B /* InlineSnapshotTesting */; }; D7A343F02AD0D77C00CED48B /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = D7A343EF2AD0D77C00CED48B /* SnapshotTesting */; }; + D7ADD3DE2B53854300F104C4 /* DamusPurpleURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7ADD3DD2B53854300F104C4 /* DamusPurpleURL.swift */; }; + D7ADD3E02B538D4200F104C4 /* DamusPurpleURLSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7ADD3DF2B538D4200F104C4 /* DamusPurpleURLSheetView.swift */; }; + D7ADD3E22B538E3500F104C4 /* DamusPurpleVerifyNpubView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7ADD3E12B538E3500F104C4 /* DamusPurpleVerifyNpubView.swift */; }; D7C6787E2B2D34CC00BCEAFB /* NIP98AuthenticatedRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C6787D2B2D34CC00BCEAFB /* NIP98AuthenticatedRequest.swift */; }; D7CB5D3B2B112FBB00AD4105 /* NotificationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A3B162B02DCE5008BD568 /* NotificationFormatter.swift */; }; D7CB5D3C2B1130C600AD4105 /* LocalNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDA128B29EB19C40006FA5A /* LocalNotification.swift */; }; @@ -1333,15 +1336,15 @@ D72A2D062AD9C1FB002AFF62 /* MockProfiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProfiles.swift; sourceTree = "<group>"; }; D7315A292ACDF3B70036E30A /* DamusCacheManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusCacheManager.swift; sourceTree = "<group>"; }; D7315A2B2ACDF4DA0036E30A /* DamusCacheManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusCacheManagerTests.swift; sourceTree = "<group>"; }; - D74F43092B23F0BE00425B75 /* DamusPurple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurple.swift; sourceTree = "<group>"; }; - D74F430B2B23FB9B00425B75 /* StoreObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreObserver.swift; sourceTree = "<group>"; }; - D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleWelcomeView.swift; sourceTree = "<group>"; }; D74AAFC12B153395006CF0F4 /* HeadlessDamusState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlessDamusState.swift; sourceTree = "<group>"; }; D74AAFC42B1538DE006CF0F4 /* NotificationExtensionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationExtensionState.swift; sourceTree = "<group>"; }; D74AAFCB2B155D07006CF0F4 /* MakeZapRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeZapRequest.swift; sourceTree = "<group>"; }; D74AAFCE2B155D8C006CF0F4 /* ZapDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZapDataModel.swift; sourceTree = "<group>"; }; D74AAFD32B155ECB006CF0F4 /* Zaps+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Zaps+.swift"; sourceTree = "<group>"; }; D74AAFD52B155F0C006CF0F4 /* WalletConnect+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WalletConnect+.swift"; sourceTree = "<group>"; }; + D74F43092B23F0BE00425B75 /* DamusPurple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurple.swift; sourceTree = "<group>"; }; + D74F430B2B23FB9B00425B75 /* StoreObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreObserver.swift; sourceTree = "<group>"; }; + D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleWelcomeView.swift; sourceTree = "<group>"; }; D76874F22AE3632B00FB0F68 /* ProfileZapLinkView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileZapLinkView.swift; sourceTree = "<group>"; }; D77BFA0A2AE3051200621634 /* ProfileActionSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileActionSheetView.swift; sourceTree = "<group>"; }; D783A63E2AD4E53D00658DDA /* SuggestedHashtagsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestedHashtagsView.swift; sourceTree = "<group>"; }; @@ -1355,6 +1358,9 @@ D79C4C162AFEB061003A41B4 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; }; D79C4C182AFEB061003A41B4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; D79C4C1C2AFEB061003A41B4 /* DamusNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DamusNotificationService.entitlements; sourceTree = "<group>"; }; + D7ADD3DD2B53854300F104C4 /* DamusPurpleURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleURL.swift; sourceTree = "<group>"; }; + D7ADD3DF2B538D4200F104C4 /* DamusPurpleURLSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleURLSheetView.swift; sourceTree = "<group>"; }; + D7ADD3E12B538E3500F104C4 /* DamusPurpleVerifyNpubView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleVerifyNpubView.swift; sourceTree = "<group>"; }; D7C6787D2B2D34CC00BCEAFB /* NIP98AuthenticatedRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NIP98AuthenticatedRequest.swift; sourceTree = "<group>"; }; D7CB5D3D2B116DAD00AD4105 /* NotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsManager.swift; sourceTree = "<group>"; }; D7CB5D442B116FE800AD4105 /* Contacts+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Contacts+.swift"; sourceTree = "<group>"; }; @@ -2562,6 +2568,8 @@ children = ( 4CFF8F5829C9FD1E008DB934 /* DamusPurpleView.swift */, D76556D52B1E6C08001B0CCC /* DamusPurpleWelcomeView.swift */, + D7ADD3DF2B538D4200F104C4 /* DamusPurpleURLSheetView.swift */, + D7ADD3E12B538E3500F104C4 /* DamusPurpleVerifyNpubView.swift */, ); path = Purple; sourceTree = "<group>"; @@ -2622,6 +2630,7 @@ children = ( D74F43092B23F0BE00425B75 /* DamusPurple.swift */, D74F430B2B23FB9B00425B75 /* StoreObserver.swift */, + D7ADD3DD2B53854300F104C4 /* DamusPurpleURL.swift */, ); path = Purple; sourceTree = "<group>"; @@ -2912,6 +2921,7 @@ 4CEF958D2A9CE650000F901B /* verifier.c in Sources */, 4C32B9342A9AD01A00DC3548 /* NdbProfile.swift in Sources */, 4C32B9332A99845B00DC3548 /* Ndb.swift in Sources */, + D7ADD3E22B538E3500F104C4 /* DamusPurpleVerifyNpubView.swift in Sources */, 4C4793082A993E8900489948 /* refmap.c in Sources */, 4C4793072A993E6200489948 /* emitter.c in Sources */, 4C4793062A993E5300489948 /* json_parser.c in Sources */, @@ -3045,6 +3055,7 @@ D74F430C2B23FB9B00425B75 /* StoreObserver.swift in Sources */, 4C363A9A28283854006E126D /* Reply.swift in Sources */, BA693074295D649800ADDB87 /* UserSettingsStore.swift in Sources */, + D7ADD3E02B538D4200F104C4 /* DamusPurpleURLSheetView.swift in Sources */, 4CFF8F6729CC9E3A008DB934 /* ImageView.swift in Sources */, 4CA927632A290EB10098A105 /* EventTop.swift in Sources */, 4C90BD18283A9EE5008EE7EF /* LoginView.swift in Sources */, @@ -3327,6 +3338,7 @@ D7CB5D4E2B11728000AD4105 /* NewEventsBits.swift in Sources */, 4CC7AAFA297F64AC00430951 /* EventMenu.swift in Sources */, B57B4C622B312BD700A232C0 /* ReconnectRelaysNotify.swift in Sources */, + D7ADD3DE2B53854300F104C4 /* DamusPurpleURL.swift in Sources */, E4FA1C032A24BB7F00482697 /* SearchSettingsView.swift in Sources */, 4C75EFBB2804A34C0006080F /* ProofOfWork.swift in Sources */, 4C3AC7A52836987600E1F516 /* MainTabView.swift in Sources */, diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -28,6 +28,7 @@ enum Sheets: Identifiable { case filter case user_status case onboardingSuggestions + case purple(DamusPurpleURL) static func zap(target: ZapTarget, lnurl: String) -> Sheets { return .zap(ZapSheet(target: target, lnurl: lnurl)) @@ -48,6 +49,7 @@ enum Sheets: Identifiable { case .select_wallet: return "select-wallet" case .filter: return "filter" case .onboardingSuggestions: return "onboarding-suggestions" + case .purple(let purple_url): return "purple" + purple_url.url_string() } } } @@ -330,6 +332,8 @@ struct ContentView: View { .presentationDragIndicator(.visible) case .onboardingSuggestions: OnboardingSuggestionsView(model: SuggestedUsersViewModel(damus_state: damus_state!)) + case .purple(let purple_url): + DamusPurpleURLSheetView(damus_state: damus_state!, purple_url: purple_url) } } .onOpenURL { url in @@ -344,6 +348,7 @@ struct ContentView: View { case .event(let ev): self.open_event(ev: ev) case .wallet_connect(let nwc): self.open_wallet(nwc: nwc) case .script(let data): self.open_script(data) + case .purple(let purple_url): self.active_sheet = .purple(purple_url) } } } @@ -1043,9 +1048,15 @@ enum OpenResult { case event(NostrEvent) case wallet_connect(WalletConnectURL) case script([UInt8]) + case purple(DamusPurpleURL) } func on_open_url(state: DamusState, url: URL, result: @escaping (OpenResult?) -> Void) { + if let purple_url = DamusPurpleURL.from_url(url: url) { + result(.purple(purple_url)) + return + } + if let nwc = WalletConnectURL(str: url.absoluteString) { result(.wallet_connect(nwc)) return diff --git a/damus/Models/Purple/DamusPurple.swift b/damus/Models/Purple/DamusPurple.swift @@ -156,6 +156,30 @@ class DamusPurple: StoreObserverDelegate { throw PurpleError.translation_no_response } } + + func verify_npub_for_checkout(checkout_id: String) async throws { + var url = environment.get_base_url() + url.append(path: "/ln-checkout/\(checkout_id)/verify") + + let (data, response) = try await make_nip98_authenticated_request( + method: .put, + url: url, + payload: nil, + payload_type: nil, + auth_keypair: self.keypair + ) + + if let httpResponse = response as? HTTPURLResponse { + switch httpResponse.statusCode { + case 200: + Log.info("Verified npub for checkout id `%s` with Damus Purple server", for: .damus_purple, checkout_id) + default: + Log.error("Error in verifying npub with Damus Purple. HTTP status code: %d; Response: %s; Checkout id: ", for: .damus_purple, httpResponse.statusCode, String(data: data, encoding: .utf8) ?? "Unknown", checkout_id) + throw PurpleError.checkout_npub_verification_error + } + } + + } } // MARK: API types @@ -189,6 +213,7 @@ extension DamusPurple { enum PurpleError: Error { case translation_error(status_code: Int, response: Data) case translation_no_response + case checkout_npub_verification_error } struct TranslationResult: Codable { diff --git a/damus/Models/Purple/DamusPurpleURL.swift b/damus/Models/Purple/DamusPurpleURL.swift @@ -0,0 +1,43 @@ +// +// DamusPurpleURL.swift +// damus +// +// Created by Daniel Nogueira on 2024-01-13. +// + +import Foundation + +enum DamusPurpleURL { + case verify_npub(checkout_id: String) + case welcome(checkout_id: String) + case landing + + static func from_url(url: URL) -> DamusPurpleURL? { + guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return nil } + guard components.scheme == "damus" else { return nil } + switch components.path { + case "purple:verify": + guard let checkout_id: String = components.queryItems?.first(where: { $0.name == "id" })?.value else { return nil } + return .verify_npub(checkout_id: checkout_id) + case "purple:welcome": + guard let checkout_id: String = components.queryItems?.first(where: { $0.name == "id" })?.value else { return nil } + return .welcome(checkout_id: checkout_id) + case "purple:landing": + return .landing + default: + return nil + } + } + + func url_string() -> String { + switch self { + case .verify_npub(let id): + return "damus:purple:verify?id=\(id)" + case .welcome(let id): + return "damus:purple:welcome?id=\(id)" + case .landing: + return "damus:purple:landing" + } + } + +} diff --git a/damus/Util/Constants.swift b/damus/Util/Constants.swift @@ -16,4 +16,6 @@ class Constants { static let NOTIFICATION_EXTENSION_BUNDLE_IDENTIFIER: String = "com.jb55.damus2.DamusNotificationService" static let PURPLE_API_PRODUCTION_BASE_URL: URL = URL(string: "https://purple.damus.io")! static let PURPLE_API_TEST_BASE_URL: URL = URL(string: "http://127.0.0.1:8989")! + static let PURPLE_LANDING_PAGE_TEST_URL: URL = URL(string: "http://localhost:3000/purple")! + static let PURPLE_LANDING_PAGE_PRODUCTION_URL: URL = URL(string: "https://damus.io/purple")! } diff --git a/damus/Views/Purple/DamusPurpleURLSheetView.swift b/damus/Views/Purple/DamusPurpleURLSheetView.swift @@ -0,0 +1,34 @@ +// +// DamusPurpleURLSheetView.swift +// damus +// +// Created by Daniel D’Aquino on 2024-01-13. +// + +import Foundation + +import SwiftUI + +struct DamusPurpleURLSheetView: View { + @Environment(\.dismiss) var dismiss + let damus_state: DamusState + let purple_url: DamusPurpleURL + + var body: some View { + switch self.purple_url { + case .verify_npub(let checkout_id): + DamusPurpleVerifyNpubView(damus_state: damus_state, checkout_id: checkout_id) + case .welcome(_): + DamusPurpleWelcomeView() + case .landing: + DamusPurpleView(damus_state: damus_state) + } + } +} + +struct DamusPurpleURLSheetView_Previews: PreviewProvider { + static var previews: some View { + DamusPurpleURLSheetView(damus_state: test_damus_state, purple_url: .verify_npub(checkout_id: "123")) + } +} + diff --git a/damus/Views/Purple/DamusPurpleVerifyNpubView.swift b/damus/Views/Purple/DamusPurpleVerifyNpubView.swift @@ -0,0 +1,64 @@ +// +// DamusPurpleVerifyNpubView.swift +// damus +// +// Created by Daniel D’Aquino on 2024-01-13. +// + +import SwiftUI + +struct DamusPurpleVerifyNpubView: View { + let damus_state: DamusState + let checkout_id: String + @State var verified: Bool = false + + var body: some View { + ZStack { + Rectangle() + .background(Color.black) + + VStack { + DamusPurpleLogoView() + + VStack(alignment: .center, spacing: 30) { + Subtitle(NSLocalizedString("To continue your Purple subscription checkout, please verify your npub by clicking on the button below", comment: "Instruction on how to verify npub during Damus Purple checkout")) + .multilineTextAlignment(.center) + + if !verified { + Button(action: { + Task { + try await damus_state.purple.verify_npub_for_checkout(checkout_id: checkout_id) + verified = true + } + }, label: { + HStack { + Spacer() + Text(NSLocalizedString("Verify my npub", comment: "Button label to verify the user's npub for the purpose of Purple subscription checkout")) + Spacer() + } + }) + .padding(.horizontal, 30) + .buttonStyle(GradientButtonStyle()) + } + else { + Text(NSLocalizedString("Verified! Please head back to the checkout page to continue", comment: "Instructions after the user has verified their npub for Damus Purple purchase checkout")) + .multilineTextAlignment(.center) + .foregroundColor(.green) + } + + } + .padding([.trailing, .leading], 30) + .padding(.bottom, 20) + } + } + } + + func Subtitle(_ txt: String) -> some View { + Text(txt) + .foregroundColor(.white.opacity(0.65)) + } +} + +#Preview { + DamusPurpleVerifyNpubView(damus_state: test_damus_state, checkout_id: "123") +} diff --git a/damus/Views/Purple/DamusPurpleView.swift b/damus/Views/Purple/DamusPurpleView.swift @@ -345,35 +345,7 @@ struct DamusPurpleView: View { var MainContent: some View { VStack { - HStack(spacing: 20) { - Image("damus-dark-logo") - .resizable() - .frame(width: 60, height: 60) - .clipShape(RoundedRectangle(cornerRadius: 15.0)) - .overlay( - RoundedRectangle(cornerRadius: 15) - .stroke(LinearGradient( - colors: [DamusColors.lighterPink.opacity(0.8), .white.opacity(0), DamusColors.deepPurple.opacity(0.6)], - startPoint: .topLeading, - endPoint: .bottomTrailing), lineWidth: 1) - ) - .shadow(radius: 5) - - VStack(alignment: .leading) { - Text(NSLocalizedString("Purple", comment: "Subscription service name")) - .font(.system(size: 60.0).weight(.bold)) - .foregroundStyle( - LinearGradient( - colors: [DamusColors.lighterPink, DamusColors.deepPurple], - startPoint: .bottomLeading, - endPoint: .topTrailing - ) - ) - .foregroundColor(.white) - .tracking(-2) - } - } - .padding(.bottom, 30) + DamusPurpleLogoView() VStack(alignment: .leading, spacing: 30) { Subtitle(NSLocalizedString("Help us stay independent in our mission for Freedom tech with our Purple subscription, and look cool doing it!", comment: "Damus purple subscription pitch")) @@ -426,6 +398,17 @@ struct DamusPurpleView: View { } } + HStack { + Spacer() + Link( + NSLocalizedString("Learn more", comment: "Label for a link to the Damus Purple landing page"), + destination: damus_state.settings.purple_api_local_test_mode ? Constants.PURPLE_LANDING_PAGE_TEST_URL : Constants.PURPLE_LANDING_PAGE_PRODUCTION_URL + ) + .foregroundColor(DamusColors.pink) + .padding() + Spacer() + } + } .padding([.trailing, .leading], 30) .padding(.bottom, 20) @@ -441,6 +424,40 @@ struct DamusPurpleView: View { } } +struct DamusPurpleLogoView: View { + var body: some View { + HStack(spacing: 20) { + Image("damus-dark-logo") + .resizable() + .frame(width: 60, height: 60) + .clipShape(RoundedRectangle(cornerRadius: 15.0)) + .overlay( + RoundedRectangle(cornerRadius: 15) + .stroke(LinearGradient( + colors: [DamusColors.lighterPink.opacity(0.8), .white.opacity(0), DamusColors.deepPurple.opacity(0.6)], + startPoint: .topLeading, + endPoint: .bottomTrailing), lineWidth: 1) + ) + .shadow(radius: 5) + + VStack(alignment: .leading) { + Text(NSLocalizedString("Purple", comment: "Subscription service name")) + .font(.system(size: 60.0).weight(.bold)) + .foregroundStyle( + LinearGradient( + colors: [DamusColors.lighterPink, DamusColors.deepPurple], + startPoint: .bottomLeading, + endPoint: .topTrailing + ) + ) + .foregroundColor(.white) + .tracking(-2) + } + } + .padding(.bottom, 30) + } +} + struct DamusPurpleView_Previews: PreviewProvider { static var previews: some View { /*