damus

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

commit 2525799c8a334fa0267ad07a35205cda2f41baba
parent b3b6fdc29e24885c94af08d1fcfc2299b45faf40
Author: Daniel D’Aquino <daniel@daquino.me>
Date:   Wed, 14 Feb 2024 21:31:50 +0000

refactor: split views from DamusPurpleView into separate files

This refactoring commit splits several view blocks from DamusPurpleView
into separate files.

- New view structs were defined within the DamusPurpleView namespace, to
  avoid polluting the global namespace

- No logical changes were made. The functionality should have stayed
  equivalent

- Changes were made conservatively, and as semantically as possible, to
  make the code easier to work with.

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

Diffstat:
Mdamus.xcodeproj/project.pbxproj | 12++++++++++++
Mdamus/Views/Purple/DamusPurpleVerifyNpubView.swift | 2+-
Mdamus/Views/Purple/DamusPurpleView.swift | 223++-----------------------------------------------------------------------------
Adamus/Views/Purple/Detail/IAPProductStateView.swift | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adamus/Views/Purple/Detail/LogoView.swift | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Adamus/Views/Purple/Detail/MarketingContentView.swift | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 294 insertions(+), 221 deletions(-)

diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj @@ -439,6 +439,9 @@ D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.swift */; }; D70A3B172B02DCE5008BD568 /* NotificationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A3B162B02DCE5008BD568 /* NotificationFormatter.swift */; }; D7100C562B76F8E600C59298 /* PurpleViewPrimitives.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7100C552B76F8E600C59298 /* PurpleViewPrimitives.swift */; }; + D7100C582B76FC8400C59298 /* MarketingContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7100C572B76FC8400C59298 /* MarketingContentView.swift */; }; + D7100C5A2B76FD5100C59298 /* LogoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7100C592B76FD5100C59298 /* LogoView.swift */; }; + D7100C5C2B77016700C59298 /* IAPProductStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7100C5B2B77016700C59298 /* IAPProductStateView.swift */; }; D71DC1EC2A9129C3006E207C /* PostViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71DC1EB2A9129C3006E207C /* PostViewTests.swift */; }; D72341192B6864F200E1E135 /* DamusPurpleEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72341182B6864F200E1E135 /* DamusPurpleEnvironment.swift */; }; D723411A2B6864F200E1E135 /* DamusPurpleEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72341182B6864F200E1E135 /* DamusPurpleEnvironment.swift */; }; @@ -1338,6 +1341,9 @@ D2277EE92A089BD5006C3807 /* Router.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Router.swift; sourceTree = "<group>"; }; D70A3B162B02DCE5008BD568 /* NotificationFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationFormatter.swift; sourceTree = "<group>"; }; D7100C552B76F8E600C59298 /* PurpleViewPrimitives.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurpleViewPrimitives.swift; sourceTree = "<group>"; }; + D7100C572B76FC8400C59298 /* MarketingContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarketingContentView.swift; sourceTree = "<group>"; }; + D7100C592B76FD5100C59298 /* LogoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoView.swift; sourceTree = "<group>"; }; + D7100C5B2B77016700C59298 /* IAPProductStateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IAPProductStateView.swift; sourceTree = "<group>"; }; D71DC1EB2A9129C3006E207C /* PostViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostViewTests.swift; sourceTree = "<group>"; }; D72341182B6864F200E1E135 /* DamusPurpleEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusPurpleEnvironment.swift; sourceTree = "<group>"; }; D723C38D2AB8D83400065664 /* ContentFilters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentFilters.swift; sourceTree = "<group>"; }; @@ -2641,6 +2647,9 @@ isa = PBXGroup; children = ( D7100C552B76F8E600C59298 /* PurpleViewPrimitives.swift */, + D7100C572B76FC8400C59298 /* MarketingContentView.swift */, + D7100C592B76FD5100C59298 /* LogoView.swift */, + D7100C5B2B77016700C59298 /* IAPProductStateView.swift */, ); path = Detail; sourceTree = "<group>"; @@ -3126,6 +3135,7 @@ 4CCEB7AE29B53D260078AA28 /* SearchingEventView.swift in Sources */, 4CF0ABE929844AF100D66079 /* AnyCodable.swift in Sources */, BA3759932ABCCEBA0018D73B /* CameraModel.swift in Sources */, + D7100C5A2B76FD5100C59298 /* LogoView.swift in Sources */, 4C0A3F8F280F640A000448DE /* ThreadModel.swift in Sources */, 4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */, D7CB5D3B2B112FBB00AD4105 /* NotificationFormatter.swift in Sources */, @@ -3179,6 +3189,7 @@ 4C7D09782A0B0CC900943473 /* WalletModel.swift in Sources */, 4C1253522A76C6130004F4B8 /* ComposeNotify.swift in Sources */, 4C7D09662A0AE62100943473 /* AlbyButton.swift in Sources */, + D7100C582B76FC8400C59298 /* MarketingContentView.swift in Sources */, 4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */, 4CFF8F6329CC9AD7008DB934 /* ImageContextMenuModifier.swift in Sources */, 4C54AA0A29A55429003E4487 /* EventGroup.swift in Sources */, @@ -3385,6 +3396,7 @@ 3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */, 3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */, 4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */, + D7100C5C2B77016700C59298 /* IAPProductStateView.swift in Sources */, 4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */, 4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */, BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */, diff --git a/damus/Views/Purple/DamusPurpleVerifyNpubView.swift b/damus/Views/Purple/DamusPurpleVerifyNpubView.swift @@ -34,7 +34,7 @@ struct DamusPurpleVerifyNpubView: View { .background(Color.black) VStack { - DamusPurpleLogoView() + DamusPurpleView.LogoView() VStack(alignment: .center, spacing: 30) { diff --git a/damus/Views/Purple/DamusPurpleView.swift b/damus/Views/Purple/DamusPurpleView.swift @@ -12,23 +12,6 @@ fileprivate let damus_products = ["purpleyearly","purple"] // MARK: - Helper structures -enum ProductState { - case loading - case loaded([Product]) - case failed - - var products: [Product]? { - switch self { - case .loading: - return nil - case .loaded(let ps): - return ps - case .failed: - return nil - } - } -} - enum AccountInfoState { case loading case loaded(account: DamusPurple.Account) @@ -45,11 +28,6 @@ enum DamusPurpleType: String { case monthly = "purple" } -struct PurchasedProduct { - let tx: StoreKit.Transaction - let product: Product -} - // MARK: - Main view struct DamusPurpleView: View { @@ -125,7 +103,7 @@ struct DamusPurpleView: View { var MainContent: some View { VStack { - DamusPurpleLogoView() + DamusPurpleView.LogoView() switch my_account_info_state { case .loading: @@ -148,74 +126,7 @@ struct DamusPurpleView: View { var MarketingContent: some View { VStack { - VStack(alignment: .leading, spacing: 30) { - PurpleViewPrimitives.SubtitleView(text: 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")) - .multilineTextAlignment(.center) - - HStack(spacing: 20) { - PurpleViewPrimitives.IconOnBoxView(name: "heart.fill") - - VStack(alignment: .leading) { - PurpleViewPrimitives.TitleView(text: NSLocalizedString("Help Build The Future", comment: "Title for funding future damus development")) - - PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("Support Damus development to help build the future of decentralized communication on the web.", comment: "Reason for supporting damus development")) - } - } - - HStack(spacing: 20) { - PurpleViewPrimitives.IconOnBoxView(name: "ai-3-stars.fill") - - VStack(alignment: .leading) { - PurpleViewPrimitives.TitleView(text: NSLocalizedString("Exclusive features", comment: "Features only available on subscription service")) - .padding(.bottom, -3) - - HStack(spacing: 3) { - Image("calendar") - .resizable() - .frame(width: 15, height: 15) - - Text(NSLocalizedString("Coming soon", comment: "Feature is still in development and will be available soon")) - .font(.caption) - .bold() - } - .foregroundColor(DamusColors.pink) - .padding(.vertical, 3) - .padding(.horizontal, 8) - .background(DamusColors.lightBackgroundPink) - .cornerRadius(30.0) - - PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("Be the first to access upcoming premium features: Automatic translations, longer note storage, and more", comment: "Description of new features to be expected")) - .padding(.top, 3) - } - } - - HStack(spacing: 20) { - PurpleViewPrimitives.IconOnBoxView(name: "badge") - - VStack(alignment: .leading) { - PurpleViewPrimitives.TitleView(text: NSLocalizedString("Supporter Badge", comment: "Title for supporter badge")) - - PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("Get a special badge on your profile to show everyone your contribution to Freedom tech", comment: "Supporter badge description")) - } - } - - HStack { - Spacer() - Link( - damus_state.purple.enable_purple_iap_support ? - NSLocalizedString("Learn more about the features", comment: "Label for a link to the Damus website, to allow the user to learn more about the features of Purple") - : - NSLocalizedString("Coming soon! Visit our website to learn more", comment: "Label announcing Purple, and inviting the user to learn more on the website"), - destination: damus_state.purple.environment.damus_website_url() - ) - .foregroundColor(DamusColors.pink) - .padding() - Spacer() - } - - } - .padding([.trailing, .leading], 30) - .padding(.bottom, 20) + DamusPurpleView.MarketingContentView(purple: damus_state.purple) VStack(alignment: .center) { ProductStateView @@ -227,100 +138,8 @@ struct DamusPurpleView: View { var ProductStateView: some View { Group { if damus_state.purple.enable_purple_iap_support { - switch self.products { - case .failed: - PurpleViewPrimitives.ProductLoadErrorView() - case .loaded(let products): - if let purchased { - PurchasedView(purchased) - } else { - ProductsView(products) - } - case .loading: - ProgressView() - .progressViewStyle(.circular) - } - } - } - } - - func PurchasedView(_ purchased: PurchasedProduct) -> some View { - VStack(spacing: 10) { - Text(NSLocalizedString("Purchased!", comment: "User purchased a subscription")) - .font(.title2) - .foregroundColor(.white) - price_description(product: purchased.product) - .foregroundColor(.white) - .opacity(0.65) - .frame(width: 200) - Text(NSLocalizedString("Purchased on", comment: "Indicating when the user purchased the subscription")) - .font(.title2) - .foregroundColor(.white) - Text(format_date(date: purchased.tx.purchaseDate)) - .foregroundColor(.white) - .opacity(0.65) - if let expiry = purchased.tx.expirationDate { - Text(NSLocalizedString("Renews on", comment: "Indicating when the subscription will renew")) - .font(.title2) - .foregroundColor(.white) - Text(format_date(date: expiry)) - .foregroundColor(.white) - .opacity(0.65) + DamusPurpleView.IAPProductStateView(products: products, purchased: purchased, subscribe: subscribe) } - Button(action: { - show_manage_subscriptions = true - }, label: { - Text(NSLocalizedString("Manage", comment: "Manage the damus subscription")) - }) - .buttonStyle(GradientButtonStyle()) - } - } - - func ProductsView(_ products: [Product]) -> some View { - VStack(spacing: 10) { - Text(NSLocalizedString("Save 20% off on an annual subscription", comment: "Savings for purchasing an annual subscription")) - .font(.callout.bold()) - .foregroundColor(.white) - ForEach(products) { product in - Button(action: { - Task { @MainActor in - do { - try await subscribe(product) - } catch { - print(error.localizedDescription) - } - } - }, label: { - price_description(product: product) - }) - .buttonStyle(GradientButtonStyle()) - } - } - .padding(.horizontal, 20) - } - - func price_description(product: Product) -> some View { - if product.id == "purpleyearly" { - return ( - AnyView( - HStack(spacing: 10) { - Text(NSLocalizedString("Annually", comment: "Annual renewal of purple subscription")) - Spacer() - Text(verbatim: non_discounted_price(product)).strikethrough().foregroundColor(DamusColors.white.opacity(0.5)) - Text(verbatim: product.displayPrice).fontWeight(.bold) - } - ) - ) - } else { - return ( - AnyView( - HStack(spacing: 10) { - Text(NSLocalizedString("Monthly", comment: "Monthly renewal of purple subscription")) - Spacer() - Text(verbatim: product.displayPrice).fontWeight(.bold) - } - ) - ) } } @@ -408,42 +227,6 @@ struct DamusPurpleView: View { } } -// MARK: - More helper views - -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 { /* diff --git a/damus/Views/Purple/Detail/IAPProductStateView.swift b/damus/Views/Purple/Detail/IAPProductStateView.swift @@ -0,0 +1,139 @@ +// +// PurchasedProductView.swift +// damus +// +// Created by Daniel D’Aquino on 2024-02-09. +// + +import SwiftUI +import StoreKit + +// MARK: - IAPProductStateView + +extension DamusPurpleView { + struct IAPProductStateView: View { + let products: ProductState + let purchased: PurchasedProduct? + let subscribe: (Product) async throws -> Void + + var body: some View { + switch self.products { + case .failed: + PurpleViewPrimitives.ProductLoadErrorView() + case .loaded(let products): + if let purchased { + PurchasedView(purchased) + } else { + ProductsView(products) + } + case .loading: + ProgressView() + .progressViewStyle(.circular) + } + } + + func PurchasedView(_ purchased: PurchasedProduct) -> some View { + VStack(spacing: 10) { + Text(NSLocalizedString("Purchased!", comment: "User purchased a subscription")) + .font(.title2) + .foregroundColor(.white) + price_description(product: purchased.product) + .foregroundColor(.white) + .opacity(0.65) + .frame(width: 200) + Text(NSLocalizedString("Purchased on", comment: "Indicating when the user purchased the subscription")) + .font(.title2) + .foregroundColor(.white) + Text(format_date(date: purchased.tx.purchaseDate)) + .foregroundColor(.white) + .opacity(0.65) + if let expiry = purchased.tx.expirationDate { + Text(NSLocalizedString("Renews on", comment: "Indicating when the subscription will renew")) + .font(.title2) + .foregroundColor(.white) + Text(format_date(date: expiry)) + .foregroundColor(.white) + .opacity(0.65) + } + } + } + + func ProductsView(_ products: [Product]) -> some View { + VStack(spacing: 10) { + Text(NSLocalizedString("Save 20% off on an annual subscription", comment: "Savings for purchasing an annual subscription")) + .font(.callout.bold()) + .foregroundColor(.white) + ForEach(products) { product in + Button(action: { + Task { @MainActor in + do { + try await subscribe(product) + } catch { + print(error.localizedDescription) + } + } + }, label: { + price_description(product: product) + }) + .buttonStyle(GradientButtonStyle()) + } + } + .padding(.horizontal, 20) + } + + func price_description(product: Product) -> some View { + if product.id == "purpleyearly" { + return ( + AnyView( + HStack(spacing: 10) { + Text(NSLocalizedString("Annually", comment: "Annual renewal of purple subscription")) + Spacer() + Text(verbatim: non_discounted_price(product)).strikethrough().foregroundColor(DamusColors.white.opacity(0.5)) + Text(verbatim: product.displayPrice).fontWeight(.bold) + } + ) + ) + } else { + return ( + AnyView( + HStack(spacing: 10) { + Text(NSLocalizedString("Monthly", comment: "Monthly renewal of purple subscription")) + Spacer() + Text(verbatim: product.displayPrice).fontWeight(.bold) + } + ) + ) + } + } + } +} + +// MARK: - Helper structures + +extension DamusPurpleView { + enum ProductState { + case loading + case loaded([Product]) + case failed + + var products: [Product]? { + switch self { + case .loading: + return nil + case .loaded(let ps): + return ps + case .failed: + return nil + } + } + } + + struct PurchasedProduct { + let tx: StoreKit.Transaction + let product: Product + } +} + +#Preview { + DamusPurpleView.IAPProductStateView(products: .loaded([]), purchased: nil, subscribe: {_ in }) +} diff --git a/damus/Views/Purple/Detail/LogoView.swift b/damus/Views/Purple/Detail/LogoView.swift @@ -0,0 +1,50 @@ +// +// LogoView.swift +// damus +// +// Created by Daniel D’Aquino on 2024-02-09. +// + +import SwiftUI + +// MARK: - More helper views + +extension DamusPurpleView { + struct LogoView: 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) + } + } +} + +#Preview { + DamusPurpleView.LogoView() +} diff --git a/damus/Views/Purple/Detail/MarketingContentView.swift b/damus/Views/Purple/Detail/MarketingContentView.swift @@ -0,0 +1,89 @@ +// +// DamusPurpleMarketingContentView.swift +// damus +// +// Created by Daniel D’Aquino on 2024-02-09. +// + +import SwiftUI + +extension DamusPurpleView { + struct MarketingContentView: View { + let purple: DamusPurple + + var body: some View { + VStack(alignment: .leading, spacing: 30) { + PurpleViewPrimitives.SubtitleView(text: 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")) + .multilineTextAlignment(.center) + + HStack(spacing: 20) { + PurpleViewPrimitives.IconOnBoxView(name: "heart.fill") + + VStack(alignment: .leading) { + PurpleViewPrimitives.TitleView(text: NSLocalizedString("Help Build The Future", comment: "Title for funding future damus development")) + + PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("Support Damus development to help build the future of decentralized communication on the web.", comment: "Reason for supporting damus development")) + } + } + + HStack(spacing: 20) { + PurpleViewPrimitives.IconOnBoxView(name: "ai-3-stars.fill") + + VStack(alignment: .leading) { + PurpleViewPrimitives.TitleView(text: NSLocalizedString("Exclusive features", comment: "Features only available on subscription service")) + .padding(.bottom, -3) + + HStack(spacing: 3) { + Image("calendar") + .resizable() + .frame(width: 15, height: 15) + + Text(NSLocalizedString("Coming soon", comment: "Feature is still in development and will be available soon")) + .font(.caption) + .bold() + } + .foregroundColor(DamusColors.pink) + .padding(.vertical, 3) + .padding(.horizontal, 8) + .background(DamusColors.lightBackgroundPink) + .cornerRadius(30.0) + + PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("Be the first to access upcoming premium features: Automatic translations, longer note storage, and more", comment: "Description of new features to be expected")) + .padding(.top, 3) + } + } + + HStack(spacing: 20) { + PurpleViewPrimitives.IconOnBoxView(name: "badge") + + VStack(alignment: .leading) { + PurpleViewPrimitives.TitleView(text: NSLocalizedString("Supporter Badge", comment: "Title for supporter badge")) + + PurpleViewPrimitives.SubtitleView(text: NSLocalizedString("Get a special badge on your profile to show everyone your contribution to Freedom tech", comment: "Supporter badge description")) + } + } + + HStack { + Spacer() + Link( + purple.enable_purple_iap_support ? + NSLocalizedString("Learn more about the features", comment: "Label for a link to the Damus website, to allow the user to learn more about the features of Purple") + : + NSLocalizedString("Coming soon! Visit our website to learn more", comment: "Label announcing Purple, and inviting the user to learn more on the website"), + destination: purple.environment.damus_website_url() + ) + .foregroundColor(DamusColors.pink) + .padding() + Spacer() + } + + } + .padding([.trailing, .leading], 30) + .padding(.bottom, 20) + } + } +} + +#Preview { + DamusPurpleView.MarketingContentView(purple: test_damus_state.purple) +}