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>
This commit is contained in:
committed by
William Casarin
parent
b3b6fdc29e
commit
2525799c8a
@@ -439,6 +439,9 @@
|
|||||||
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.swift */; };
|
D2277EEA2A089BD5006C3807 /* Router.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2277EE92A089BD5006C3807 /* Router.swift */; };
|
||||||
D70A3B172B02DCE5008BD568 /* NotificationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A3B162B02DCE5008BD568 /* NotificationFormatter.swift */; };
|
D70A3B172B02DCE5008BD568 /* NotificationFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D70A3B162B02DCE5008BD568 /* NotificationFormatter.swift */; };
|
||||||
D7100C562B76F8E600C59298 /* PurpleViewPrimitives.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7100C552B76F8E600C59298 /* PurpleViewPrimitives.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 */; };
|
D71DC1EC2A9129C3006E207C /* PostViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D71DC1EB2A9129C3006E207C /* PostViewTests.swift */; };
|
||||||
D72341192B6864F200E1E135 /* DamusPurpleEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72341182B6864F200E1E135 /* DamusPurpleEnvironment.swift */; };
|
D72341192B6864F200E1E135 /* DamusPurpleEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72341182B6864F200E1E135 /* DamusPurpleEnvironment.swift */; };
|
||||||
D723411A2B6864F200E1E135 /* 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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
D723C38D2AB8D83400065664 /* ContentFilters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentFilters.swift; sourceTree = "<group>"; };
|
||||||
@@ -2641,6 +2647,9 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
D7100C552B76F8E600C59298 /* PurpleViewPrimitives.swift */,
|
D7100C552B76F8E600C59298 /* PurpleViewPrimitives.swift */,
|
||||||
|
D7100C572B76FC8400C59298 /* MarketingContentView.swift */,
|
||||||
|
D7100C592B76FD5100C59298 /* LogoView.swift */,
|
||||||
|
D7100C5B2B77016700C59298 /* IAPProductStateView.swift */,
|
||||||
);
|
);
|
||||||
path = Detail;
|
path = Detail;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -3126,6 +3135,7 @@
|
|||||||
4CCEB7AE29B53D260078AA28 /* SearchingEventView.swift in Sources */,
|
4CCEB7AE29B53D260078AA28 /* SearchingEventView.swift in Sources */,
|
||||||
4CF0ABE929844AF100D66079 /* AnyCodable.swift in Sources */,
|
4CF0ABE929844AF100D66079 /* AnyCodable.swift in Sources */,
|
||||||
BA3759932ABCCEBA0018D73B /* CameraModel.swift in Sources */,
|
BA3759932ABCCEBA0018D73B /* CameraModel.swift in Sources */,
|
||||||
|
D7100C5A2B76FD5100C59298 /* LogoView.swift in Sources */,
|
||||||
4C0A3F8F280F640A000448DE /* ThreadModel.swift in Sources */,
|
4C0A3F8F280F640A000448DE /* ThreadModel.swift in Sources */,
|
||||||
4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */,
|
4C3AC79F2833115300E1F516 /* FollowButtonView.swift in Sources */,
|
||||||
D7CB5D3B2B112FBB00AD4105 /* NotificationFormatter.swift in Sources */,
|
D7CB5D3B2B112FBB00AD4105 /* NotificationFormatter.swift in Sources */,
|
||||||
@@ -3179,6 +3189,7 @@
|
|||||||
4C7D09782A0B0CC900943473 /* WalletModel.swift in Sources */,
|
4C7D09782A0B0CC900943473 /* WalletModel.swift in Sources */,
|
||||||
4C1253522A76C6130004F4B8 /* ComposeNotify.swift in Sources */,
|
4C1253522A76C6130004F4B8 /* ComposeNotify.swift in Sources */,
|
||||||
4C7D09662A0AE62100943473 /* AlbyButton.swift in Sources */,
|
4C7D09662A0AE62100943473 /* AlbyButton.swift in Sources */,
|
||||||
|
D7100C582B76FC8400C59298 /* MarketingContentView.swift in Sources */,
|
||||||
4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */,
|
4CAAD8AD298851D000060CEA /* AccountDeletion.swift in Sources */,
|
||||||
4CFF8F6329CC9AD7008DB934 /* ImageContextMenuModifier.swift in Sources */,
|
4CFF8F6329CC9AD7008DB934 /* ImageContextMenuModifier.swift in Sources */,
|
||||||
4C54AA0A29A55429003E4487 /* EventGroup.swift in Sources */,
|
4C54AA0A29A55429003E4487 /* EventGroup.swift in Sources */,
|
||||||
@@ -3385,6 +3396,7 @@
|
|||||||
3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */,
|
3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */,
|
||||||
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */,
|
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */,
|
||||||
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */,
|
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */,
|
||||||
|
D7100C5C2B77016700C59298 /* IAPProductStateView.swift in Sources */,
|
||||||
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
|
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
|
||||||
4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */,
|
4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */,
|
||||||
BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */,
|
BA37598E2ABCCE500018D73B /* VideoCaptureProcessor.swift in Sources */,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ struct DamusPurpleVerifyNpubView: View {
|
|||||||
.background(Color.black)
|
.background(Color.black)
|
||||||
|
|
||||||
VStack {
|
VStack {
|
||||||
DamusPurpleLogoView()
|
DamusPurpleView.LogoView()
|
||||||
|
|
||||||
VStack(alignment: .center, spacing: 30) {
|
VStack(alignment: .center, spacing: 30) {
|
||||||
|
|
||||||
|
|||||||
@@ -12,23 +12,6 @@ fileprivate let damus_products = ["purpleyearly","purple"]
|
|||||||
|
|
||||||
// MARK: - Helper structures
|
// 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 {
|
enum AccountInfoState {
|
||||||
case loading
|
case loading
|
||||||
case loaded(account: DamusPurple.Account)
|
case loaded(account: DamusPurple.Account)
|
||||||
@@ -45,11 +28,6 @@ enum DamusPurpleType: String {
|
|||||||
case monthly = "purple"
|
case monthly = "purple"
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PurchasedProduct {
|
|
||||||
let tx: StoreKit.Transaction
|
|
||||||
let product: Product
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Main view
|
// MARK: - Main view
|
||||||
|
|
||||||
struct DamusPurpleView: View {
|
struct DamusPurpleView: View {
|
||||||
@@ -125,7 +103,7 @@ struct DamusPurpleView: View {
|
|||||||
|
|
||||||
var MainContent: some View {
|
var MainContent: some View {
|
||||||
VStack {
|
VStack {
|
||||||
DamusPurpleLogoView()
|
DamusPurpleView.LogoView()
|
||||||
|
|
||||||
switch my_account_info_state {
|
switch my_account_info_state {
|
||||||
case .loading:
|
case .loading:
|
||||||
@@ -148,74 +126,7 @@ struct DamusPurpleView: View {
|
|||||||
|
|
||||||
var MarketingContent: some View {
|
var MarketingContent: some View {
|
||||||
VStack {
|
VStack {
|
||||||
VStack(alignment: .leading, spacing: 30) {
|
DamusPurpleView.MarketingContentView(purple: damus_state.purple)
|
||||||
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)
|
|
||||||
|
|
||||||
VStack(alignment: .center) {
|
VStack(alignment: .center) {
|
||||||
ProductStateView
|
ProductStateView
|
||||||
@@ -227,103 +138,11 @@ struct DamusPurpleView: View {
|
|||||||
var ProductStateView: some View {
|
var ProductStateView: some View {
|
||||||
Group {
|
Group {
|
||||||
if damus_state.purple.enable_purple_iap_support {
|
if damus_state.purple.enable_purple_iap_support {
|
||||||
switch self.products {
|
DamusPurpleView.IAPProductStateView(products: products, purchased: purchased, subscribe: subscribe)
|
||||||
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)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - State management
|
// MARK: - State management
|
||||||
|
|
||||||
func load_account() async {
|
func load_account() async {
|
||||||
@@ -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 {
|
struct DamusPurpleView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
/*
|
/*
|
||||||
|
|||||||
139
damus/Views/Purple/Detail/IAPProductStateView.swift
Normal file
139
damus/Views/Purple/Detail/IAPProductStateView.swift
Normal file
@@ -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 })
|
||||||
|
}
|
||||||
50
damus/Views/Purple/Detail/LogoView.swift
Normal file
50
damus/Views/Purple/Detail/LogoView.swift
Normal file
@@ -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()
|
||||||
|
}
|
||||||
89
damus/Views/Purple/Detail/MarketingContentView.swift
Normal file
89
damus/Views/Purple/Detail/MarketingContentView.swift
Normal file
@@ -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)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user