From a63efd1435531c473cbe82484c390abb0ece1d36 Mon Sep 17 00:00:00 2001 From: Vova Ignatov Date: Mon, 1 Apr 2024 17:27:05 +0100 Subject: [PATCH] IOS-2456 Use features from API --- Anytype/Generated/Strings.swift | 54 ++++---- .../Strings/en.lproj/Localizable.strings | 24 ++-- .../Models/MembershipTierExtensions.swift | 122 +++++++++++++----- .../Views/MembershipTierInfoView.swift | 4 +- .../Membership/Model/MembershipTier.swift | 59 ++++++++- 5 files changed, 184 insertions(+), 79 deletions(-) diff --git a/Anytype/Generated/Strings.swift b/Anytype/Generated/Strings.swift index 512f850916..ae0bf1b542 100644 --- a/Anytype/Generated/Strings.swift +++ b/Anytype/Generated/Strings.swift @@ -1458,28 +1458,10 @@ internal enum Loc { internal static let title4 = Loc.tr("Localizable", "Membership.Banner.Title4", fallback: "Invest in Connectivity") } internal enum Builder { - /// Unique name (from 7 characters) - internal static let benefit1 = Loc.tr("Localizable", "Membership.Builder.Benefit1", fallback: "Unique name (from 7 characters)") - /// 128 GB of network space - internal static let benefit2 = Loc.tr("Localizable", "Membership.Builder.Benefit2", fallback: "128 GB of network space") - /// 10 Guest collaborator seats - internal static let benefit3 = Loc.tr("Localizable", "Membership.Builder.Benefit3", fallback: "10 Guest collaborator seats") - /// Priority support - internal static let benefit4 = Loc.tr("Localizable", "Membership.Builder.Benefit4", fallback: "Priority support") /// Unlock the magic of multi-party collaboration and enjoy top-notch support internal static let subtitle = Loc.tr("Localizable", "Membership.Builder.Subtitle", fallback: "Unlock the magic of multi-party collaboration and enjoy top-notch support") } internal enum CoCreator { - /// Unique name (from 5 characters) - internal static let benefit1 = Loc.tr("Localizable", "Membership.CoCreator.Benefit1", fallback: "Unique name (from 5 characters)") - /// 256 GB of network space - internal static let benefit2 = Loc.tr("Localizable", "Membership.CoCreator.Benefit2", fallback: "256 GB of network space") - /// 25 Guest collaborator seats - internal static let benefit3 = Loc.tr("Localizable", "Membership.CoCreator.Benefit3", fallback: "25 Guest collaborator seats") - /// Chat with the team - internal static let benefit4 = Loc.tr("Localizable", "Membership.CoCreator.Benefit4", fallback: "Chat with the team") - /// Unique collectible - internal static let benefit5 = Loc.tr("Localizable", "Membership.CoCreator.Benefit5", fallback: "Unique collectible") /// Support our adventure and unlock exclusive access and perks internal static let subtitle = Loc.tr("Localizable", "Membership.CoCreator.Subtitle", fallback: "Support our adventure and unlock exclusive access and perks") } @@ -1511,15 +1493,39 @@ internal enum Loc { internal static let title = Loc.tr("Localizable", "Membership.EmailForm.Title", fallback: "Get your free membership") } internal enum Explorer { - /// 1 GB of network space - internal static let benefit1 = Loc.tr("Localizable", "Membership.Explorer.Benefit1", fallback: "1 GB of network space") - /// 10 one-to-one spaces - internal static let benefit2 = Loc.tr("Localizable", "Membership.Explorer.Benefit2", fallback: "10 one-to-one spaces") - /// Up to 10 shared spaces in read-only mode - internal static let benefit3 = Loc.tr("Localizable", "Membership.Explorer.Benefit3", fallback: "Up to 10 shared spaces in read-only mode") /// Dive into the network and enjoy the thrill of one-on-one collaboration internal static let subtitle = Loc.tr("Localizable", "Membership.Explorer.Subtitle", fallback: "Dive into the network and enjoy the thrill of one-on-one collaboration") } + internal enum Feature { + /// %@ Invitations + internal static func invites(_ p1: Any) -> String { + return Loc.tr("Localizable", "Membership.Feature.Invites", String(describing: p1), fallback: "%@ Invitations") + } + /// Local, non-unique name + internal static let localName = Loc.tr("Localizable", "Membership.Feature.LocalName", fallback: "Local, non-unique name") + /// %@ Shared spaces + internal static func sharedSpaces(_ p1: Any) -> String { + return Loc.tr("Localizable", "Membership.Feature.SharedSpaces", String(describing: p1), fallback: "%@ Shared spaces") + } + /// %@ Editors per space + internal static func spaceWriters(_ p1: Any) -> String { + return Loc.tr("Localizable", "Membership.Feature.SpaceWriters", String(describing: p1), fallback: "%@ Editors per space") + } + /// %@ GB of backup & sync space + internal static func storageGB(_ p1: Any) -> String { + return Loc.tr("Localizable", "Membership.Feature.StorageGB", String(describing: p1), fallback: "%@ GB of backup & sync space") + } + /// Unique Network name (%@+ characters) + internal static func uniqueName(_ p1: Any) -> String { + return Loc.tr("Localizable", "Membership.Feature.UniqueName", String(describing: p1), fallback: "Unique Network name (%@+ characters)") + } + /// Unlimited Viewers for shared spaces + internal static let unlimitedViewers = Loc.tr("Localizable", "Membership.Feature.UnlimitedViewers", fallback: "Unlimited Viewers for shared spaces") + /// %@ Viewers for shared spaces + internal static func viewers(_ p1: Any) -> String { + return Loc.tr("Localizable", "Membership.Feature.Viewers", String(describing: p1), fallback: "%@ Viewers for shared spaces") + } + } internal enum Legal { /// Membership levels details internal static let details = Loc.tr("Localizable", "Membership.Legal.Details", fallback: "Membership levels details") diff --git a/Anytype/Resources/Strings/en.lproj/Localizable.strings b/Anytype/Resources/Strings/en.lproj/Localizable.strings index 7283507775..adad362099 100644 --- a/Anytype/Resources/Strings/en.lproj/Localizable.strings +++ b/Anytype/Resources/Strings/en.lproj/Localizable.strings @@ -1106,27 +1106,19 @@ "Membership.Payment.Google subscription" = "Google subscription"; -// MARK: - Membership Tiers "Membership.Explorer.Subtitle" = "Dive into the network and enjoy the thrill of one-on-one collaboration"; -"Membership.Explorer.Benefit1" = "1 GB of network space"; -"Membership.Explorer.Benefit2" = "10 one-to-one spaces"; -"Membership.Explorer.Benefit3" = "Up to 10 shared spaces in read-only mode"; - "Membership.Builder.Subtitle" = "Unlock the magic of multi-party collaboration and enjoy top-notch support"; -"Membership.Builder.Benefit1" = "Unique name (from 7 characters)"; -"Membership.Builder.Benefit2" = "128 GB of network space"; -"Membership.Builder.Benefit3" = "10 Guest collaborator seats"; -"Membership.Builder.Benefit4" = "Priority support"; - "Membership.CoCreator.Subtitle" = "Support our adventure and unlock exclusive access and perks"; -"Membership.CoCreator.Benefit1" = "Unique name (from 5 characters)"; -"Membership.CoCreator.Benefit2" = "256 GB of network space"; -"Membership.CoCreator.Benefit3" = "25 Guest collaborator seats"; -"Membership.CoCreator.Benefit4" = "Chat with the team"; -"Membership.CoCreator.Benefit5" = "Unique collectible"; - "Membership.Custom.Subtitle" = "Membership tailored to your specific needs and preferences"; +"Membership.Feature.LocalName" = "Local, non-unique name"; +"Membership.Feature.UniqueName" = "Unique Network name (%@+ characters)"; +"Membership.Feature.StorageGB" = "%@ GB of backup & sync space"; +"Membership.Feature.Invites" = "%@ Invitations"; +"Membership.Feature.SpaceWriters" = "%@ Editors per space"; +"Membership.Feature.UnlimitedViewers" = "Unlimited Viewers for shared spaces"; +"Membership.Feature.Viewers" = "%@ Viewers for shared spaces"; +"Membership.Feature.SharedSpaces" = "%@ Shared spaces"; // MARK: - Debug "Debug.MimeTypes" = "Mime Types - %@"; diff --git a/Anytype/Sources/PresentationLayer/Modules/Membership/Models/MembershipTierExtensions.swift b/Anytype/Sources/PresentationLayer/Modules/Membership/Models/MembershipTierExtensions.swift index 3cd0291ddc..28db5c3e86 100644 --- a/Anytype/Sources/PresentationLayer/Modules/Membership/Models/MembershipTierExtensions.swift +++ b/Anytype/Sources/PresentationLayer/Modules/Membership/Models/MembershipTierExtensions.swift @@ -17,36 +17,6 @@ extension MembershipTier { } } - var benefits: [String] { - switch self.type { - case .explorer: - [ - Loc.Membership.Explorer.benefit1, - Loc.Membership.Explorer.benefit2, - Loc.Membership.Explorer.benefit3 - ] - case .builder: - [ - Loc.Membership.Builder.benefit1, - Loc.Membership.Builder.benefit2, - Loc.Membership.Builder.benefit3, - Loc.Membership.Builder.benefit4 - ] - case .coCreator: - [ - Loc.Membership.CoCreator.benefit1, - Loc.Membership.CoCreator.benefit2, - Loc.Membership.CoCreator.benefit3, - Loc.Membership.CoCreator.benefit4, - Loc.Membership.CoCreator.benefit5 - ] - case .custom: - [ - // TBD in future updates - ] - } - } - var mediumIcon: ImageAsset { switch self.type { case .explorer: @@ -86,23 +56,107 @@ extension MembershipTier { .purple } } + + var featureDescriptions: [String] { + var featureDescriptions = [anyName.description] + featureDescriptions.append(contentsOf: features.map(\.description)) + return featureDescriptions + } } +extension MembershipAnyName { + var description: String { + switch self { + case .none: + Loc.Membership.Feature.localName + case .some(let minLenght): + Loc.Membership.Feature.uniqueName(minLenght) + } + } +} + +extension MembershipFeature { + var description: String { + switch self { + case .storageGbs(let value): + Loc.Membership.Feature.storageGB(value) + case .invites(let value): + Loc.Membership.Feature.invites(value) + case .spaceWriters(let value): + Loc.Membership.Feature.spaceWriters(value) + case .spaceReaders(let value): + switch value { + case .int(let intValue): + if intValue == 1024 { // Middleware understanding of Unlimited + Loc.Membership.Feature.unlimitedViewers + } else { + Loc.Membership.Feature.viewers(intValue) + } + case .string(let stringValue): + Loc.Membership.Feature.viewers(stringValue) + } + case .sharedSpaces(let value): + Loc.Membership.Feature.sharedSpaces(value) + } + } +} + + // MARK: - Mocks extension MembershipTier { static var mockExplorer: MembershipTier { - MembershipTier(type: .explorer, name: "Explorer", anyName: .none) + MembershipTier( + type: .explorer, + name: "Explorer", + anyName: .none, + features: [ + .storageGbs(.int(1)), + .sharedSpaces(.int(3)), + .spaceWriters(.int(3)), + .spaceReaders(.int(3)) + ] + ) } static var mockBuilder: MembershipTier { - MembershipTier(type: .builder, name: "Builder", anyName: .some(minLenght: 7)) + MembershipTier( + type: .builder, + name: "Builder", + anyName: .some(minLenght: 7), + features: [ + .storageGbs(.int(128)), + .sharedSpaces(.int(3)), + .spaceWriters(.int(10)), + .spaceReaders(.int(1024)) + ] + ) } static var mockCoCreator: MembershipTier { - MembershipTier(type: .coCreator, name: "CockCreator", anyName: .some(minLenght: 5)) + MembershipTier( + type: .coCreator, + name: "CockCreator", + anyName: .some(minLenght: 5), + features: [ + .storageGbs(.int(256)), + .sharedSpaces(.int(3)), + .spaceWriters(.int(10)), + .spaceReaders(.int(1024)) + ] + ) } static var mockCustom: MembershipTier { - MembershipTier(type: .custom(id: 228), name: "Na-Baron", anyName: .some(minLenght: 3)) + MembershipTier( + type: .custom(id: 228), + name: "Na-Baron", + anyName: .some(minLenght: 3), + features: [ + .storageGbs(.int(2560)), + .sharedSpaces(.int(333)), + .spaceWriters(.int(100)), + .spaceReaders(.int(1024)), + ] + ) } } diff --git a/Anytype/Sources/PresentationLayer/Modules/Membership/TierSelection/Views/MembershipTierInfoView.swift b/Anytype/Sources/PresentationLayer/Modules/Membership/TierSelection/Views/MembershipTierInfoView.swift index d842aae8c0..2a5d30a534 100644 --- a/Anytype/Sources/PresentationLayer/Modules/Membership/TierSelection/Views/MembershipTierInfoView.swift +++ b/Anytype/Sources/PresentationLayer/Modules/Membership/TierSelection/Views/MembershipTierInfoView.swift @@ -36,12 +36,12 @@ struct MembershipTierInfoView: View { VStack(alignment: .leading, spacing: 0) { AnytypeText(Loc.whatSIncluded, style: .calloutRegular, color: .Text.secondary) Spacer.fixedHeight(6) - ForEach(tier.benefits, id: \.self) { benefit in + ForEach(tier.featureDescriptions, id: \.self) { feature in HStack(spacing: 8) { Image(asset: .System.textCheckMark) .frame(width: 16, height: 16) .foregroundColor(.Text.primary) - AnytypeText(benefit, style: .calloutRegular, color: .Text.primary) + AnytypeText(feature, style: .calloutRegular, color: .Text.primary) .lineLimit(1) } } diff --git a/Modules/Services/Sources/Services/Membership/Model/MembershipTier.swift b/Modules/Services/Sources/Services/Membership/Model/MembershipTier.swift index e5bba18314..55478e3435 100644 --- a/Modules/Services/Sources/Services/Membership/Model/MembershipTier.swift +++ b/Modules/Services/Sources/Services/Membership/Model/MembershipTier.swift @@ -46,21 +46,46 @@ public enum MembershipAnyName: Hashable, Equatable { case some(minLenght: UInt32) } +public enum MembershipFeature: Hashable, Equatable { + public enum Value: Hashable, Equatable, CustomStringConvertible { + case int(UInt32) + case string(String) + + public var description: String { + switch self { + case .int(let int): + String(describing: int) + case .string(let string): + string + } + } + } + + case storageGbs(Value) + case invites(Value) + case spaceWriters(Value) + case spaceReaders(Value) + case sharedSpaces(Value) +} + public struct MembershipTier: Hashable, Identifiable, Equatable { public let type: MembershipTierType public let name: String public let anyName: MembershipAnyName + public let features: [MembershipFeature] public var id: MembershipTierType { type } public init( type: MembershipTierType, name: String, - anyName: MembershipAnyName + anyName: MembershipAnyName, + features: [MembershipFeature] ) { self.type = type self.name = name self.anyName = anyName + self.features = features } } @@ -71,12 +96,40 @@ extension Anytype_Model_MembershipTierData { func asModel() -> MembershipTier? { guard let type = MembershipTierType(intId: id) else { return nil } - let anyName: MembershipAnyName = anyNamesCountIncluded > 0 ? .some(minLenght: anyNamesCountIncluded) : .none + let anyName: MembershipAnyName = anyNamesCountIncluded > 0 ? .some(minLenght: anyNameMinLength) : .none return MembershipTier( type: type, name: name, - anyName: anyName + anyName: anyName, + features: getFeatures() ) } + + func getFeatures() -> [MembershipFeature] { + features.compactMap { feature in + switch feature.featureID { + case .storageGbs: + return .storageGbs(extractFeatureValue(feature: feature)) + case .invites: + return .invites(extractFeatureValue(feature: feature)) + case .spaceWriters: + return .spaceWriters(extractFeatureValue(feature: feature)) + case .spaceReaders: + return .spaceReaders(extractFeatureValue(feature: feature)) + case .sharedSpaces: + return .sharedSpaces(extractFeatureValue(feature: feature)) + case .UNRECOGNIZED, .unknown: + return nil + } + } + } + + private func extractFeatureValue(feature: Feature) -> MembershipFeature.Value { + if feature.valueUint > 0 { + return .int(feature.valueUint) + } + + return .string(feature.valueStr) + } }