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:
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 {
/*