diff --git a/RevenueCat.xcodeproj/project.pbxproj b/RevenueCat.xcodeproj/project.pbxproj index 0e1d5c19f2..2e0f6793fa 100644 --- a/RevenueCat.xcodeproj/project.pbxproj +++ b/RevenueCat.xcodeproj/project.pbxproj @@ -19,11 +19,18 @@ 2C2AEB3B2CA7209F00A50F38 /* PaywallPackageComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB3A2CA7209F00A50F38 /* PaywallPackageComponent.swift */; }; 2C2AEB3D2CA720B700A50F38 /* PaywallPackageGroupComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB3C2CA720B700A50F38 /* PaywallPackageGroupComponent.swift */; }; 2C2AEB3F2CA7235300A50F38 /* PaywallPurchaseButtonComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB3E2CA7235300A50F38 /* PaywallPurchaseButtonComponent.swift */; }; + 2C2AEB442CA72D9F00A50F38 /* PackageGroupComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB432CA72D9F00A50F38 /* PackageGroupComponentViewModel.swift */; }; + 2C2AEB462CA7302400A50F38 /* PackageComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB452CA7302400A50F38 /* PackageComponentViewModel.swift */; }; + 2C2AEB482CA7304900A50F38 /* PurchaseButtonComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB472CA7304900A50F38 /* PurchaseButtonComponentViewModel.swift */; }; + 2C2AEB4A2CA7338A00A50F38 /* PackageGroupComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB492CA7338A00A50F38 /* PackageGroupComponentView.swift */; }; + 2C2AEB4C2CA7339200A50F38 /* PackageComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB4B2CA7339200A50F38 /* PackageComponentView.swift */; }; + 2C2AEB4E2CA7339E00A50F38 /* PurchaseButtonComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C2AEB4D2CA7339E00A50F38 /* PurchaseButtonComponentView.swift */; }; 2C4C36132C6FBA8B00AE959B /* CompatibilityTopBarTrailing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C4C36122C6FBA8B00AE959B /* CompatibilityTopBarTrailing.swift */; }; 2C6CC1162B8D2B6900432E4D /* PurchasesSyncAttributesAndOfferingsIfNeededTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C6CC1152B8D2B6800432E4D /* PurchasesSyncAttributesAndOfferingsIfNeededTests.swift */; }; 2C7F0AD32B8EEB4600381179 /* RateLimiter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C7F0AD22B8EEB4600381179 /* RateLimiter.swift */; }; 2C7F0AD62B8EEF7B00381179 /* RateLimiterRests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C7F0AD42B8EEF0B00381179 /* RateLimiterRests.swift */; }; 2CAB87F12CAA3B7800247013 /* Stackable+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB87F02CAA3B7800247013 /* Stackable+Extensions.swift */; }; + 2CAB87F72CAAB13200247013 /* CornerBorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CAB87F62CAAB13200247013 /* CornerBorder.swift */; }; 2CB8CF9327BF538F00C34DE3 /* PlatformInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CB8CF9227BF538F00C34DE3 /* PlatformInfo.swift */; }; 2CC790CA2CC00C5900FBE120 /* PackageComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790B12CC00C5900FBE120 /* PackageComponentView.swift */; }; 2CC790CC2CC00C5900FBE120 /* PurchaseButtonComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790B82CC00C5900FBE120 /* PurchaseButtonComponentViewModel.swift */; }; @@ -31,11 +38,18 @@ 2CC790D02CC00C5900FBE120 /* PackageGroupComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790B52CC00C5900FBE120 /* PackageGroupComponentViewModel.swift */; }; 2CC790D32CC00C5900FBE120 /* PackageGroupComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790B42CC00C5900FBE120 /* PackageGroupComponentView.swift */; }; 2CC790D82CC00C5900FBE120 /* PurchaseButtonComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790B72CC00C5900FBE120 /* PurchaseButtonComponentView.swift */; }; - 2CC790DF2CC00DF100FBE120 /* StackableComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790DD2CC00DF100FBE120 /* StackableComponent.swift */; }; - 2CC790E02CC00DF100FBE120 /* PaywallComponentBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790DA2CC00DF100FBE120 /* PaywallComponentBase.swift */; }; - 2CC790E12CC00DF100FBE120 /* Dimension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790D92CC00DF100FBE120 /* Dimension.swift */; }; - 2CC790E22CC00DF100FBE120 /* PaywallComponentLocalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790DB2CC00DF100FBE120 /* PaywallComponentLocalization.swift */; }; - 2CC790E32CC00DF100FBE120 /* PaywallComponentPropertyTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC790DC2CC00DF100FBE120 /* PaywallComponentPropertyTypes.swift */; }; + 2CC791282CC01F1200FBE120 /* PurchaseButtonComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791252CC01F1200FBE120 /* PurchaseButtonComponentViewModel.swift */; }; + 2CC791292CC01F1200FBE120 /* PackageComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC7911F2CC01F1200FBE120 /* PackageComponentViewModel.swift */; }; + 2CC7912A2CC01F1200FBE120 /* PurchaseButtonComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791242CC01F1200FBE120 /* PurchaseButtonComponentView.swift */; }; + 2CC7912B2CC01F1200FBE120 /* PackageGroupComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791212CC01F1200FBE120 /* PackageGroupComponentView.swift */; }; + 2CC7912C2CC01F1200FBE120 /* PackageComponentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC7911E2CC01F1200FBE120 /* PackageComponentView.swift */; }; + 2CC7912D2CC01F1200FBE120 /* PackageGroupComponentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791222CC01F1200FBE120 /* PackageGroupComponentViewModel.swift */; }; + 2CC791352CC0212900FBE120 /* Border.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC7912E2CC0212900FBE120 /* Border.swift */; }; + 2CC791362CC0212900FBE120 /* PaywallComponentBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791302CC0212900FBE120 /* PaywallComponentBase.swift */; }; + 2CC791372CC0212900FBE120 /* Dimension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC7912F2CC0212900FBE120 /* Dimension.swift */; }; + 2CC791382CC0212900FBE120 /* PaywallComponentLocalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791312CC0212900FBE120 /* PaywallComponentLocalization.swift */; }; + 2CC791392CC0212900FBE120 /* StackableComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791332CC0212900FBE120 /* StackableComponent.swift */; }; + 2CC7913A2CC0212900FBE120 /* PaywallComponentPropertyTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CC791322CC0212900FBE120 /* PaywallComponentPropertyTypes.swift */; }; 2CD72942268A823900BFC976 /* Data+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD72941268A823900BFC976 /* Data+Extensions.swift */; }; 2CD72944268A826F00BFC976 /* Date+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CD72943268A826F00BFC976 /* Date+Extensions.swift */; }; 2D00A41D2767C08300FC3DD8 /* ManageSubscriptionsStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D00A41C2767C08300FC3DD8 /* ManageSubscriptionsStrings.swift */; }; @@ -1166,6 +1180,12 @@ 2C2AEB3A2CA7209F00A50F38 /* PaywallPackageComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallPackageComponent.swift; sourceTree = ""; }; 2C2AEB3C2CA720B700A50F38 /* PaywallPackageGroupComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallPackageGroupComponent.swift; sourceTree = ""; }; 2C2AEB3E2CA7235300A50F38 /* PaywallPurchaseButtonComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaywallPurchaseButtonComponent.swift; sourceTree = ""; }; + 2C2AEB432CA72D9F00A50F38 /* PackageGroupComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageGroupComponentViewModel.swift; sourceTree = ""; }; + 2C2AEB452CA7302400A50F38 /* PackageComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageComponentViewModel.swift; sourceTree = ""; }; + 2C2AEB472CA7304900A50F38 /* PurchaseButtonComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseButtonComponentViewModel.swift; sourceTree = ""; }; + 2C2AEB492CA7338A00A50F38 /* PackageGroupComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageGroupComponentView.swift; sourceTree = ""; }; + 2C2AEB4B2CA7339200A50F38 /* PackageComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageComponentView.swift; sourceTree = ""; }; + 2C2AEB4D2CA7339E00A50F38 /* PurchaseButtonComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseButtonComponentView.swift; sourceTree = ""; }; 2C4C36122C6FBA8B00AE959B /* CompatibilityTopBarTrailing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CompatibilityTopBarTrailing.swift; sourceTree = ""; }; 2C5F71F52C3D6C2600B0FE4B /* header.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = header.heic; sourceTree = ""; }; 2C5F71F62C3D6C2600B0FE4B /* background.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = background.heic; sourceTree = ""; }; @@ -1176,6 +1196,8 @@ 2CAB87EC2CA78ED800247013 /* StackableComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackableComponent.swift; sourceTree = ""; }; 2CAB87EE2CA78EF600247013 /* Dimension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dimension.swift; sourceTree = ""; }; 2CAB87F02CAA3B7800247013 /* Stackable+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Stackable+Extensions.swift"; sourceTree = ""; }; + 2CAB87F32CAAAF9300247013 /* Border.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Border.swift; sourceTree = ""; }; + 2CAB87F62CAAB13200247013 /* CornerBorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CornerBorder.swift; sourceTree = ""; }; 2CB8CF9227BF538F00C34DE3 /* PlatformInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlatformInfo.swift; sourceTree = ""; }; 2CC790B12CC00C5900FBE120 /* PackageComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageComponentView.swift; sourceTree = ""; }; 2CC790B22CC00C5900FBE120 /* PackageComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageComponentViewModel.swift; sourceTree = ""; }; @@ -1188,6 +1210,18 @@ 2CC790DB2CC00DF100FBE120 /* PaywallComponentLocalization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallComponentLocalization.swift; sourceTree = ""; }; 2CC790DC2CC00DF100FBE120 /* PaywallComponentPropertyTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallComponentPropertyTypes.swift; sourceTree = ""; }; 2CC790DD2CC00DF100FBE120 /* StackableComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackableComponent.swift; sourceTree = ""; }; + 2CC7911E2CC01F1200FBE120 /* PackageComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageComponentView.swift; sourceTree = ""; }; + 2CC7911F2CC01F1200FBE120 /* PackageComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageComponentViewModel.swift; sourceTree = ""; }; + 2CC791212CC01F1200FBE120 /* PackageGroupComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageGroupComponentView.swift; sourceTree = ""; }; + 2CC791222CC01F1200FBE120 /* PackageGroupComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PackageGroupComponentViewModel.swift; sourceTree = ""; }; + 2CC791242CC01F1200FBE120 /* PurchaseButtonComponentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseButtonComponentView.swift; sourceTree = ""; }; + 2CC791252CC01F1200FBE120 /* PurchaseButtonComponentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchaseButtonComponentViewModel.swift; sourceTree = ""; }; + 2CC7912E2CC0212900FBE120 /* Border.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Border.swift; sourceTree = ""; }; + 2CC7912F2CC0212900FBE120 /* Dimension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dimension.swift; sourceTree = ""; }; + 2CC791302CC0212900FBE120 /* PaywallComponentBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallComponentBase.swift; sourceTree = ""; }; + 2CC791312CC0212900FBE120 /* PaywallComponentLocalization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallComponentLocalization.swift; sourceTree = ""; }; + 2CC791322CC0212900FBE120 /* PaywallComponentPropertyTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallComponentPropertyTypes.swift; sourceTree = ""; }; + 2CC791332CC0212900FBE120 /* StackableComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackableComponent.swift; sourceTree = ""; }; 2CD72941268A823900BFC976 /* Data+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+Extensions.swift"; sourceTree = ""; }; 2CD72943268A826F00BFC976 /* Date+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Date+Extensions.swift"; sourceTree = ""; }; 2D00A41C2767C08300FC3DD8 /* ManageSubscriptionsStrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManageSubscriptionsStrings.swift; sourceTree = ""; }; @@ -2291,60 +2325,79 @@ path = TemplateComponentsViewPreviews; sourceTree = ""; }; - 2CC7908E2CC00C0F00FBE120 /* Recovered References */ = { + 2CC791122CC01F0100FBE120 /* Recovered References */ = { isa = PBXGroup; children = ( + 2CAB87F32CAAAF9300247013 /* Border.swift */, 2CAB87EC2CA78ED800247013 /* StackableComponent.swift */, + 2CC790DD2CC00DF100FBE120 /* StackableComponent.swift */, + 2CC790DA2CC00DF100FBE120 /* PaywallComponentBase.swift */, + 2CC790D92CC00DF100FBE120 /* Dimension.swift */, + 2CC790DB2CC00DF100FBE120 /* PaywallComponentLocalization.swift */, + 2CC790DC2CC00DF100FBE120 /* PaywallComponentPropertyTypes.swift */, 2CAB87EE2CA78EF600247013 /* Dimension.swift */, + 2C2AEB4D2CA7339E00A50F38 /* PurchaseButtonComponentView.swift */, + 2C2AEB452CA7302400A50F38 /* PackageComponentViewModel.swift */, + 2C2AEB4B2CA7339200A50F38 /* PackageComponentView.swift */, + 2C2AEB492CA7338A00A50F38 /* PackageGroupComponentView.swift */, + 2CC790B12CC00C5900FBE120 /* PackageComponentView.swift */, + 2CC790B82CC00C5900FBE120 /* PurchaseButtonComponentViewModel.swift */, + 2CC790B22CC00C5900FBE120 /* PackageComponentViewModel.swift */, + 2CC790B52CC00C5900FBE120 /* PackageGroupComponentViewModel.swift */, + 2CC790B42CC00C5900FBE120 /* PackageGroupComponentView.swift */, + 2CC790B72CC00C5900FBE120 /* PurchaseButtonComponentView.swift */, + 2C2AEB472CA7304900A50F38 /* PurchaseButtonComponentViewModel.swift */, + 2C2AEB432CA72D9F00A50F38 /* PackageGroupComponentViewModel.swift */, ); name = "Recovered References"; sourceTree = ""; }; - 2CC790B32CC00C5900FBE120 /* Package */ = { + 2CC791202CC01F1200FBE120 /* Package */ = { isa = PBXGroup; children = ( - 2CC790B12CC00C5900FBE120 /* PackageComponentView.swift */, - 2CC790B22CC00C5900FBE120 /* PackageComponentViewModel.swift */, + 2CC7911E2CC01F1200FBE120 /* PackageComponentView.swift */, + 2CC7911F2CC01F1200FBE120 /* PackageComponentViewModel.swift */, ); path = Package; sourceTree = ""; }; - 2CC790B62CC00C5900FBE120 /* PackageGroup */ = { + 2CC791232CC01F1200FBE120 /* PackageGroup */ = { isa = PBXGroup; children = ( - 2CC790B42CC00C5900FBE120 /* PackageGroupComponentView.swift */, - 2CC790B52CC00C5900FBE120 /* PackageGroupComponentViewModel.swift */, + 2CC791212CC01F1200FBE120 /* PackageGroupComponentView.swift */, + 2CC791222CC01F1200FBE120 /* PackageGroupComponentViewModel.swift */, ); path = PackageGroup; sourceTree = ""; }; - 2CC790B92CC00C5900FBE120 /* PurchaseButton */ = { + 2CC791262CC01F1200FBE120 /* PurchaseButton */ = { isa = PBXGroup; children = ( - 2CC790B72CC00C5900FBE120 /* PurchaseButtonComponentView.swift */, - 2CC790B82CC00C5900FBE120 /* PurchaseButtonComponentViewModel.swift */, + 2CC791242CC01F1200FBE120 /* PurchaseButtonComponentView.swift */, + 2CC791252CC01F1200FBE120 /* PurchaseButtonComponentViewModel.swift */, ); path = PurchaseButton; sourceTree = ""; }; - 2CC790BA2CC00C5900FBE120 /* Packages */ = { + 2CC791272CC01F1200FBE120 /* Packages */ = { isa = PBXGroup; children = ( - 2CC790B32CC00C5900FBE120 /* Package */, - 2CC790B62CC00C5900FBE120 /* PackageGroup */, - 2CC790B92CC00C5900FBE120 /* PurchaseButton */, + 2CC791202CC01F1200FBE120 /* Package */, + 2CC791232CC01F1200FBE120 /* PackageGroup */, + 2CC791262CC01F1200FBE120 /* PurchaseButton */, ); path = Packages; sourceTree = ""; }; - 2CC790DE2CC00DF100FBE120 /* Common */ = { + 2CC791342CC0212900FBE120 /* Common */ = { isa = PBXGroup; children = ( - 2CC790D92CC00DF100FBE120 /* Dimension.swift */, - 2CC790DA2CC00DF100FBE120 /* PaywallComponentBase.swift */, - 2CC790DB2CC00DF100FBE120 /* PaywallComponentLocalization.swift */, - 2CC790DC2CC00DF100FBE120 /* PaywallComponentPropertyTypes.swift */, - 2CC790DD2CC00DF100FBE120 /* StackableComponent.swift */, + 2CC7912E2CC0212900FBE120 /* Border.swift */, + 2CC7912F2CC0212900FBE120 /* Dimension.swift */, + 2CC791302CC0212900FBE120 /* PaywallComponentBase.swift */, + 2CC791312CC0212900FBE120 /* PaywallComponentLocalization.swift */, + 2CC791322CC0212900FBE120 /* PaywallComponentPropertyTypes.swift */, + 2CC791332CC0212900FBE120 /* StackableComponent.swift */, ); path = Common; sourceTree = ""; @@ -3197,7 +3250,7 @@ 3530C18722653E8F00D6DF52 /* Frameworks */, 57B530E52858F3FD00FA4E37 /* SwiftStyleGuide.swift */, 887A5FB42C1D024300E1A461 /* Package.swift */, - 2CC7908E2CC00C0F00FBE120 /* Recovered References */, + 2CC791122CC01F0100FBE120 /* Recovered References */, ); sourceTree = ""; }; @@ -4369,7 +4422,7 @@ 88AD010B2C740CF400AA1F2B /* Components */ = { isa = PBXGroup; children = ( - 2CC790DE2CC00DF100FBE120 /* Common */, + 2CC791342CC0212900FBE120 /* Common */, 7707A94B2CAD93AC006E0313 /* PaywallButtonComponent.swift */, 88AD01032C740CF400AA1F2B /* PaywallImageComponent.swift */, 88AD01062C740CF400AA1F2B /* PaywallSpacerComponent.swift */, @@ -4391,11 +4444,12 @@ 88B1BAE32C813A3C001B7EE5 /* TemplateComponentsView.swift */, 88EA80EC2C8771A7003E6675 /* TemplateComponentsView+extensions.swift */, 2CAB87F02CAA3B7800247013 /* Stackable+Extensions.swift */, + 2CAB87F62CAAB13200247013 /* CornerBorder.swift */, 2C2AEB0D2CA64DA900A50F38 /* TemplateComponentsViewPreviews */, 7707A94A2CAD936A006E0313 /* Button */, 88B1BAE62C813A3C001B7EE5 /* Image */, 88B1BAE22C813A3C001B7EE5 /* LinkButton */, - 2CC790BA2CC00C5900FBE120 /* Packages */, + 2CC791272CC01F1200FBE120 /* Packages */, 88B1BADF2C813A3C001B7EE5 /* Spacer */, 88B1BAEA2C813A3C001B7EE5 /* Stack */, 88B1BADC2C813A3C001B7EE5 /* Text */, @@ -5431,6 +5485,12 @@ 35D159CB2BC4396F004D8061 /* DiagnosticsPostOperation.swift in Sources */, 575642B62910116900719219 /* EligibilityStrings.swift in Sources */, 4F87610F2A5C9E490006FA14 /* PaywallData.swift in Sources */, + 2CC791352CC0212900FBE120 /* Border.swift in Sources */, + 2CC791362CC0212900FBE120 /* PaywallComponentBase.swift in Sources */, + 2CC791372CC0212900FBE120 /* Dimension.swift in Sources */, + 2CC791382CC0212900FBE120 /* PaywallComponentLocalization.swift in Sources */, + 2CC791392CC0212900FBE120 /* StackableComponent.swift in Sources */, + 2CC7913A2CC0212900FBE120 /* PaywallComponentPropertyTypes.swift in Sources */, 57A0FBF22749CF66009E2FC3 /* SynchronizedUserDefaults.swift in Sources */, F5714EE526DC2F1D00635477 /* CodableStrings.swift in Sources */, 57488BE829CB7FB60000EE7E /* OfflineEntitlementsStrings.swift in Sources */, @@ -5559,11 +5619,6 @@ 4FC083292A4A35FB00A97089 /* Integer+Extensions.swift in Sources */, F5BE447D269E4ADB00254A30 /* ASIdManagerProxy.swift in Sources */, 80E80EF226970E04008F245A /* ReceiptFetcher.swift in Sources */, - 2CC790DF2CC00DF100FBE120 /* StackableComponent.swift in Sources */, - 2CC790E02CC00DF100FBE120 /* PaywallComponentBase.swift in Sources */, - 2CC790E12CC00DF100FBE120 /* Dimension.swift in Sources */, - 2CC790E22CC00DF100FBE120 /* PaywallComponentLocalization.swift in Sources */, - 2CC790E32CC00DF100FBE120 /* PaywallComponentPropertyTypes.swift in Sources */, 2DDF41AB24F6F37C005BC22D /* AppleReceipt.swift in Sources */, 2DDF41BB24F6F392005BC22D /* UInt8+Extensions.swift in Sources */, 57CB2A7829CCC3AA00C91439 /* ProductEntitlementMappingFetcher.swift in Sources */, @@ -6067,11 +6122,20 @@ 88B1BB132C81479F001B7EE5 /* PaywallComponentTypeTransformers.swift in Sources */, 88B1BB042C813A3C001B7EE5 /* StackComponentViewModel.swift in Sources */, 1E5F8F782C46BBD90041EECD /* CustomerCenterAction.swift in Sources */, + 2C2AEB4E2CA7339E00A50F38 /* PurchaseButtonComponentView.swift in Sources */, 887A60CC2C1D037000E1A461 /* PaywallFontProvider.swift in Sources */, 887A60B82C1D037000E1A461 /* Template1View.swift in Sources */, + 2CC791282CC01F1200FBE120 /* PurchaseButtonComponentViewModel.swift in Sources */, + 2CC791292CC01F1200FBE120 /* PackageComponentViewModel.swift in Sources */, + 2CC7912A2CC01F1200FBE120 /* PurchaseButtonComponentView.swift in Sources */, + 2CC7912B2CC01F1200FBE120 /* PackageGroupComponentView.swift in Sources */, + 2CC7912C2CC01F1200FBE120 /* PackageComponentView.swift in Sources */, + 2CC7912D2CC01F1200FBE120 /* PackageGroupComponentViewModel.swift in Sources */, + 2C2AEB462CA7302400A50F38 /* PackageComponentViewModel.swift in Sources */, 887A60C62C1D037000E1A461 /* LoadingPaywallView.swift in Sources */, 88B1BAF22C813A3C001B7EE5 /* SpacerComponentView.swift in Sources */, 77791ECF2C6B852000BCEF03 /* SemanticVersion.swift in Sources */, + 2CAB87F72CAAB13200247013 /* CornerBorder.swift in Sources */, 887A60C72C1D037000E1A461 /* PackageButtonStyle.swift in Sources */, 77372D992C6F8C7B008E59D3 /* AppUpdateWarningView.swift in Sources */, 887A60C52C1D037000E1A461 /* IntroEligibilityStateView.swift in Sources */, @@ -6079,6 +6143,7 @@ 88A543E12C37A4820039C6A5 /* TemplateView+MultiTier.swift in Sources */, 887A60B72C1D037000E1A461 /* WatchTemplateView.swift in Sources */, 887A60722C1D037000E1A461 /* PaywallViewMode+Extensions.swift in Sources */, + 2C2AEB4C2CA7339200A50F38 /* PackageComponentView.swift in Sources */, 887A60C32C1D037000E1A461 /* FooterView.swift in Sources */, 887A607F2C1D037000E1A461 /* Optional+Extensions.swift in Sources */, 3511088F2C47F6DA0048C4D8 /* CustomerInfo+CurrentEntitlement.swift in Sources */, @@ -6150,6 +6215,7 @@ 887A607C2C1D037000E1A461 /* ColorInformation+MultiScheme.swift in Sources */, 88B1BAFE2C813A3C001B7EE5 /* ImageComponentViewModel.swift in Sources */, 35C200B12C39254100B9778B /* FeedbackSurveyView.swift in Sources */, + 2C2AEB4A2CA7338A00A50F38 /* PackageGroupComponentView.swift in Sources */, 35F249CC2C493DCC0058993A /* CustomerCenterPurchasesType.swift in Sources */, 887A60672C1D037000E1A461 /* PaywallError.swift in Sources */, 88A543E52C37A4AF0039C6A5 /* ConsistentTierContentView.swift in Sources */, @@ -6166,11 +6232,13 @@ 887A60CE2C1D037000E1A461 /* View+PresentPaywall.swift in Sources */, 357CEC702C5940CE00A80837 /* ColorFromAppearance.swift in Sources */, 887A60832C1D037000E1A461 /* VersionDetector.swift in Sources */, + 2C2AEB482CA7304900A50F38 /* PurchaseButtonComponentViewModel.swift in Sources */, 88B1BAFC2C813A3C001B7EE5 /* ImageComponentView.swift in Sources */, 887A60872C1D037000E1A461 /* ViewExtensions.swift in Sources */, 88B1BB022C813A3C001B7EE5 /* StackComponentView.swift in Sources */, 353756712C382C2800A1B8D6 /* ManageSubscriptionsPurchaseType.swift in Sources */, 35C200AF2C39252D00B9778B /* FeedbackSurveyData.swift in Sources */, + 2C2AEB442CA72D9F00A50F38 /* PackageGroupComponentViewModel.swift in Sources */, 353FDC0D2CA41CB20055F328 /* SubscriptionPeriod+Extensions.swift in Sources */, 3551E39D2C4A6A1400D27C25 /* TintedProgressView.swift in Sources */, 88B1BAF82C813A3C001B7EE5 /* LinkButtonComponentViewModel.swift in Sources */, diff --git a/RevenueCatUI/Templates/Components/CornerBorder.swift b/RevenueCatUI/Templates/Components/CornerBorder.swift new file mode 100644 index 0000000000..8173e65fa2 --- /dev/null +++ b/RevenueCatUI/Templates/Components/CornerBorder.swift @@ -0,0 +1,301 @@ +// +// Copyright RevenueCat Inc. All Rights Reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// CornerBorder.swift +// +// Created by Josh Holtz on 9/30/24. + +import Foundation +import SwiftUI + +#if PAYWALL_COMPONENTS + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +struct CornerBorderModifier: ViewModifier { + + struct BorderInfo { + + let color: Color + let width: CGFloat + + init(color: Color, width: Double) { + self.color = color + self.width = width + } + + } + + struct RaidusInfo { + + let topLeft: CGFloat? + let topRight: CGFloat? + let bottomLeft: CGFloat? + let bottomRight: CGFloat? + + init(topLeft: Double? = nil, topRight: Double? = nil, bottomLeft: Double? = nil, bottomRight: Double? = nil) { + self.topLeft = topLeft.flatMap { CGFloat($0) } + self.topRight = topRight.flatMap { CGFloat($0) } + self.bottomLeft = bottomLeft.flatMap { CGFloat($0) } + self.bottomRight = bottomRight.flatMap { CGFloat($0) } + } + + } + + var border: BorderInfo? + var radiuses: RaidusInfo? + + func body(content: Content) -> some View { + content + .conditionalClipShape(topLeft: self.radiuses?.topLeft, + topRight: self.radiuses?.topRight, + bottomLeft: self.radiuses?.bottomLeft, + bottomRight: self.radiuses?.bottomRight) + .conditionalOverlay(color: self.border?.color, + width: self.border?.width, + topLeft: self.radiuses?.topLeft, + topRight: self.radiuses?.topRight, + bottomLeft: self.radiuses?.bottomLeft, + bottomRight: self.radiuses?.bottomRight) + } +} + +// Helper extensions to conditionally apply clipShape and overlay without AnyView + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +extension View { + + func conditionalClipShape( + topLeft: CGFloat?, + topRight: CGFloat?, + bottomLeft: CGFloat?, + bottomRight: CGFloat? + ) -> some View { + Group { + if let topLeft = topLeft, + let topRight = topRight, + let bottomLeft = bottomLeft, + let bottomRight = bottomRight, + topLeft > 0 || topRight > 0 || bottomLeft > 0 || bottomRight > 0 { + self + .applyIf(topLeft > 0) { + $0.clipShape(SingleRoundedCornerShape(radius: topLeft, corners: [.topLeft])) + } + .applyIf(topRight > 0) { + $0.clipShape(SingleRoundedCornerShape(radius: topLeft, corners: [.topRight])) + } + .applyIf(bottomLeft > 0) { + $0.clipShape(SingleRoundedCornerShape(radius: topLeft, corners: [.bottomLeft])) + } + .applyIf(bottomRight > 0) { + $0.clipShape(SingleRoundedCornerShape(radius: topLeft, corners: [.bottomRight])) + } + } else { + self + } + } + } + + // swiftlint:disable:next function_parameter_count + func conditionalOverlay( + color: Color?, + width: CGFloat?, + topLeft: CGFloat?, + topRight: CGFloat?, + bottomLeft: CGFloat?, + bottomRight: CGFloat? + ) -> some View { + Group { + if let color = color, let width = width, width > 0 { + if let topLeft = topLeft, + let topRight = topRight, + let bottomLeft = bottomLeft, + let bottomRight = bottomRight, + topLeft > 0 || topRight > 0 || bottomLeft > 0 || bottomRight > 0 { + self.overlay( + BorderRoundedCornerShape( + topLeft: topLeft, + topRight: topRight, + bottomLeft: bottomLeft, + bottomRight: bottomRight + ) + .stroke(color, lineWidth: width) + ) + } else { + self + .border(color, width: width) + } + } else { + self + } + } + } + +} + +private struct SingleRoundedCornerShape: Shape { + var radius: CGFloat + var corners: UIRectCorner + + func path(in rect: CGRect) -> Path { + let path = UIBezierPath( + roundedRect: rect, + byRoundingCorners: corners, + cornerRadii: CGSize(width: radius, height: radius) + ) + return Path(path.cgPath) + } +} + +private struct BorderRoundedCornerShape: Shape { + var topLeft: CGFloat + var topRight: CGFloat + var bottomLeft: CGFloat + var bottomRight: CGFloat + + func path(in rect: CGRect) -> Path { + var path = Path() + + // Start from the top-left corner + path.move(to: CGPoint(x: rect.minX + topLeft, y: rect.minY)) + + // Top edge and top-right corner + path.addLine(to: CGPoint(x: rect.maxX - topRight, y: rect.minY)) + path.addQuadCurve(to: CGPoint(x: rect.maxX, y: rect.minY + topRight), + control: CGPoint(x: rect.maxX, y: rect.minY)) + + // Right edge and bottom-right corner + path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - bottomRight)) + path.addQuadCurve(to: CGPoint(x: rect.maxX - bottomRight, y: rect.maxY), + control: CGPoint(x: rect.maxX, y: rect.maxY)) + + // Bottom edge and bottom-left corner + path.addLine(to: CGPoint(x: rect.minX + bottomLeft, y: rect.maxY)) + path.addQuadCurve(to: CGPoint(x: rect.minX, y: rect.maxY - bottomLeft), + control: CGPoint(x: rect.minX, y: rect.maxY)) + + // Left edge and top-left corner + path.addLine(to: CGPoint(x: rect.minX, y: rect.minY + topLeft)) + path.addQuadCurve(to: CGPoint(x: rect.minX + topLeft, y: rect.minY), + control: CGPoint(x: rect.minX, y: rect.minY)) + + return path + } +} + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +extension View { + func cornerBorder( + border: CornerBorderModifier.BorderInfo?, + radiuses: CornerBorderModifier.RaidusInfo? + ) -> some View { + self.modifier( + CornerBorderModifier( + border: border, + radiuses: radiuses + ) + ) + } +} + +#if DEBUG + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +struct CornerBorder_Previews: PreviewProvider { + + static var previews: some View { + // Equal Radius - No Border + VStack { + Text("Hello") + .padding(.vertical, 10) + .padding(.horizontal, 20) + .background(.yellow) + .cornerBorder( + border: nil, + radiuses: .init(topLeft: 8, + topRight: 8, + bottomLeft: 8, + bottomRight: 8)) + .padding() + } + .previewLayout(.sizeThatFits) + .previewDisplayName("Equal Radius - No Border") + + // No - Blue Border + VStack { + Text("Hello") + .padding(.vertical, 10) + .padding(.horizontal, 20) + .background(.yellow) + .cornerBorder( + border: .init(color: .blue, + width: 4), + radiuses: nil) + .padding() + } + .previewLayout(.sizeThatFits) + .previewDisplayName("No Right - Blue Border") + + // Top Left and Bottom Right Radius - No Border + VStack { + Text("Hello") + .padding(.vertical, 10) + .padding(.horizontal, 20) + .background(.yellow) + .cornerBorder( + border: nil, + radiuses: .init(topLeft: 8, + topRight: 0, + bottomLeft: 0, + bottomRight: 8)) + .padding() + } + .previewLayout(.sizeThatFits) + .previewDisplayName("Top Left and Bottom Right Radius - No Border") + + // Equal Radius - Blue Border + VStack { + Text("Hello") + .padding(.vertical, 10) + .padding(.horizontal, 20) + .background(.yellow) + .cornerBorder( + border: .init(color: .blue, + width: 6), + radiuses: .init(topLeft: 8, + topRight: 8, + bottomLeft: 8, + bottomRight: 8)) + .padding() + } + .previewLayout(.sizeThatFits) + .previewDisplayName("Equal Radius - Blue Border") + + // Top Left and Bottom Right Radius - Blue Border + VStack { + Text("Hello") + .padding(.vertical, 10) + .padding(.horizontal, 20) + .background(.yellow) + .cornerBorder( + border: .init(color: .blue, + width: 6), + radiuses: .init(topLeft: 8, + topRight: 0, + bottomLeft: 0, + bottomRight: 8)) + .padding() + } + .previewLayout(.sizeThatFits) + .previewDisplayName("Top Left and Bottom Right - Blue Border") + } +} + +#endif + +#endif diff --git a/RevenueCatUI/Templates/Components/Image/ImageComponentView.swift b/RevenueCatUI/Templates/Components/Image/ImageComponentView.swift index dd47747987..8d916c52bd 100644 --- a/RevenueCatUI/Templates/Components/Image/ImageComponentView.swift +++ b/RevenueCatUI/Templates/Components/Image/ImageComponentView.swift @@ -56,10 +56,8 @@ struct ImageComponentView: View { endPoint: .bottom ) ) - .roundedCorner(viewModel.cornerRadiuses.topLeading, corners: .topLeft) - .roundedCorner(viewModel.cornerRadiuses.topTrailing, corners: .topRight) - .roundedCorner(viewModel.cornerRadiuses.bottomLeading, corners: .bottomLeft) - .roundedCorner(viewModel.cornerRadiuses.bottomTrailing, corners: .bottomRight) + .cornerBorder(border: nil, + radiuses: viewModel.cornerRadiuses) } } @@ -139,7 +137,33 @@ struct ImageComponentView_Previews: PreviewProvider { ) } .previewLayout(.fixed(width: 400, height: 400)) - .previewDisplayName("Light - Fill") + .previewDisplayName("Light - Gradient") + + // Light - Fit with Rounded Corner + VStack { + ImageComponentView( + // swiftlint:disable:next force_try + viewModel: try! .init( + localizedStrings: [:], + component: .init( + source: .init( + light: .init( + original: catUrl, + heic: catUrl, + heicLowRes: catUrl + ) + ), + fitMode: .fit, + cornerRadiuses: .init(topLeading: 40, + topTrailing: 40, + bottomLeading: 40, + bottomTrailing: 40) + ) + ) + ) + } + .previewLayout(.fixed(width: 400, height: 400)) + .previewDisplayName("Light - Rounded Corner") } } diff --git a/RevenueCatUI/Templates/Components/Image/ImageComponentViewModel.swift b/RevenueCatUI/Templates/Components/Image/ImageComponentViewModel.swift index 7329e52a73..6b6e5c82c3 100644 --- a/RevenueCatUI/Templates/Components/Image/ImageComponentViewModel.swift +++ b/RevenueCatUI/Templates/Components/Image/ImageComponentViewModel.swift @@ -40,8 +40,15 @@ class ImageComponentViewModel { self.imageInfo.light.heic } - var cornerRadiuses: PaywallComponent.CornerRadiuses { - component.cornerRadiuses + var cornerRadiuses: CornerBorderModifier.RaidusInfo? { + component.cornerRadiuses.flatMap { cornerRadiuses in + CornerBorderModifier.RaidusInfo( + topLeft: cornerRadiuses.topLeading, + topRight: cornerRadiuses.topTrailing, + bottomLeft: cornerRadiuses.bottomLeading, + bottomRight: cornerRadiuses.bottomLeading + ) + } } var gradientColors: [Color] { diff --git a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift index b6152eb87a..4e840f56e0 100644 --- a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift +++ b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentView.swift @@ -40,14 +40,8 @@ struct PurchaseButtonComponentView: View { .padding(viewModel.padding) .background(viewModel.backgroundColor) .shape(viewModel.clipShape) - .applyIfLet(viewModel.cornerRadiuses, apply: { view, value in - view - .roundedCorner(value.topLeading, corners: .topLeft) - .roundedCorner(value.topTrailing, corners: .topRight) - .roundedCorner(value.bottomLeading, corners: .bottomLeft) - .roundedCorner(value.bottomTrailing, corners: .bottomRight) - }) - .padding(viewModel.margin) + .cornerBorder(border: nil, + radiuses: viewModel.cornerRadiuses) .padding(viewModel.margin) } } diff --git a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift index fee1d89f49..8356a2803c 100644 --- a/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift +++ b/RevenueCatUI/Templates/Components/Packages/PurchaseButton/PurchaseButtonComponentViewModel.swift @@ -73,8 +73,15 @@ class PurchaseButtonComponentViewModel { component.shape } - var cornerRadiuses: PaywallComponent.CornerRadiuses? { - component.cornerRadiuses + var cornerRadiuses: CornerBorderModifier.RaidusInfo? { + component.cornerRadiuses.flatMap { cornerRadiuses in + CornerBorderModifier.RaidusInfo( + topLeft: cornerRadiuses.topLeading, + topRight: cornerRadiuses.topTrailing, + bottomLeft: cornerRadiuses.bottomLeading, + bottomRight: cornerRadiuses.bottomLeading + ) + } } } diff --git a/RevenueCatUI/Templates/Components/Stack/StackComponentView.swift b/RevenueCatUI/Templates/Components/Stack/StackComponentView.swift index a8cfdd04d6..b999c6c3a0 100644 --- a/RevenueCatUI/Templates/Components/Stack/StackComponentView.swift +++ b/RevenueCatUI/Templates/Components/Stack/StackComponentView.swift @@ -46,10 +46,8 @@ struct StackComponentView: View { .padding(viewModel.padding) .width(viewModel.width) .background(viewModel.backgroundColor) - .roundedCorner(viewModel.cornerRadiuses.topLeading, corners: .topLeft) - .roundedCorner(viewModel.cornerRadiuses.topTrailing, corners: .topRight) - .roundedCorner(viewModel.cornerRadiuses.bottomLeading, corners: .bottomLeft) - .roundedCorner(viewModel.cornerRadiuses.bottomTrailing, corners: .bottomRight) + .cornerBorder(border: viewModel.border, + radiuses: viewModel.cornerRadiuses) .padding(viewModel.margin) } diff --git a/RevenueCatUI/Templates/Components/Stack/StackComponentViewModel.swift b/RevenueCatUI/Templates/Components/Stack/StackComponentViewModel.swift index 64982768fc..09ae7579e3 100644 --- a/RevenueCatUI/Templates/Components/Stack/StackComponentViewModel.swift +++ b/RevenueCatUI/Templates/Components/Stack/StackComponentViewModel.swift @@ -57,14 +57,30 @@ class StackComponentViewModel { component.margin.edgeInsets } - var cornerRadiuses: PaywallComponent.CornerRadiuses { - component.cornerRadiuses - } - var width: PaywallComponent.WidthSize? { component.width } + var cornerRadiuses: CornerBorderModifier.RaidusInfo? { + component.cornerRadiuses.flatMap { cornerRadiuses in + CornerBorderModifier.RaidusInfo( + topLeft: cornerRadiuses.topLeading, + topRight: cornerRadiuses.topTrailing, + bottomLeft: cornerRadiuses.bottomLeading, + bottomRight: cornerRadiuses.bottomLeading + ) + } + } + + var border: CornerBorderModifier.BorderInfo? { + component.border.flatMap { border in + CornerBorderModifier.BorderInfo( + color: border.color.toDyanmicColor(), + width: border.width + ) + } + } + } #endif diff --git a/RevenueCatUI/Templates/Components/Stackable+Extensions.swift b/RevenueCatUI/Templates/Components/Stackable+Extensions.swift index 2e7c6e181e..cb5b449c8c 100644 --- a/RevenueCatUI/Templates/Components/Stackable+Extensions.swift +++ b/RevenueCatUI/Templates/Components/Stackable+Extensions.swift @@ -32,7 +32,8 @@ extension PaywallComponent.StackableComponent { backgroundColor: self.backgroundColor, padding: self.padding, margin: self.margin, - cornerRadiuses: self.cornerRadiuses + cornerRadiuses: self.cornerRadiuses, + border: self.border ), localizedStrings: localizedStrings, offering: offering diff --git a/Sources/Paywalls/Components/Common/Border.swift b/Sources/Paywalls/Components/Common/Border.swift new file mode 100644 index 0000000000..a2882f5e38 --- /dev/null +++ b/Sources/Paywalls/Components/Common/Border.swift @@ -0,0 +1,30 @@ +// +// Copyright RevenueCat Inc. All Rights Reserved. +// +// Licensed under the MIT License (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://opensource.org/licenses/MIT +// +// Border.swift +// +// Created by Josh Holtz on 9/30/24. +// swiftlint:disable missing_docs + +import Foundation + +#if PAYWALL_COMPONENTS + +public extension PaywallComponent { + + struct Border: Codable, Sendable, Hashable { + + public let color: ColorInfo + public let width: Double + + } + +} + +#endif diff --git a/Sources/Paywalls/Components/Common/StackableComponent.swift b/Sources/Paywalls/Components/Common/StackableComponent.swift index 7cf572a9f4..6647cf7dac 100644 --- a/Sources/Paywalls/Components/Common/StackableComponent.swift +++ b/Sources/Paywalls/Components/Common/StackableComponent.swift @@ -27,7 +27,8 @@ public extension PaywallComponent { var dimension: Dimension { get } var padding: Padding { get } var margin: Padding { get } - var cornerRadiuses: CornerRadiuses { get } + var cornerRadiuses: CornerRadiuses? { get } + var border: Border? { get } } diff --git a/Sources/Paywalls/Components/PaywallImageComponent.swift b/Sources/Paywalls/Components/PaywallImageComponent.swift index 952309e1de..6573448aa6 100644 --- a/Sources/Paywalls/Components/PaywallImageComponent.swift +++ b/Sources/Paywalls/Components/PaywallImageComponent.swift @@ -17,7 +17,7 @@ public extension PaywallComponent { let type: ComponentType public let source: ThemeImageUrls public let overrideSourceLid: LocalizationKey? - public let cornerRadiuses: CornerRadiuses + public let cornerRadiuses: CornerRadiuses? public let gradientColors: [ColorHex]? public let maxHeight: CGFloat? public let fitMode: FitMode @@ -27,7 +27,7 @@ public extension PaywallComponent { overrideSourceLid: LocalizationKey? = nil, fitMode: FitMode = .fit, maxHeight: CGFloat? = nil, - cornerRadiuses: CornerRadiuses = .zero, + cornerRadiuses: CornerRadiuses? = nil, gradientColors: [ColorHex]? = [] ) { self.type = .image diff --git a/Sources/Paywalls/Components/PaywallPackageComponent.swift b/Sources/Paywalls/Components/PaywallPackageComponent.swift index 81207b5050..d14882659b 100644 --- a/Sources/Paywalls/Components/PaywallPackageComponent.swift +++ b/Sources/Paywalls/Components/PaywallPackageComponent.swift @@ -31,7 +31,8 @@ public extension PaywallComponent { public let dimension: Dimension public let padding: Padding public let margin: Padding - public let cornerRadiuses: CornerRadiuses + public let cornerRadiuses: CornerRadiuses? + public let border: Border? public init(packageID: String, components: [PaywallComponent], @@ -41,7 +42,8 @@ public extension PaywallComponent { backgroundColor: ColorInfo? = nil, padding: Padding = .zero, margin: Padding = .zero, - cornerRadiuses: CornerRadiuses = .zero + cornerRadiuses: CornerRadiuses? = nil, + border: Border? = nil ) { self.type = .package self.packageID = packageID @@ -53,6 +55,7 @@ public extension PaywallComponent { self.padding = padding self.margin = margin self.cornerRadiuses = cornerRadiuses + self.border = border } } diff --git a/Sources/Paywalls/Components/PaywallPackageGroupComponent.swift b/Sources/Paywalls/Components/PaywallPackageGroupComponent.swift index 90d6c661d7..11971d636f 100644 --- a/Sources/Paywalls/Components/PaywallPackageGroupComponent.swift +++ b/Sources/Paywalls/Components/PaywallPackageGroupComponent.swift @@ -31,7 +31,8 @@ public extension PaywallComponent { public let dimension: Dimension public let padding: Padding public let margin: Padding - public let cornerRadiuses: CornerRadiuses + public let cornerRadiuses: CornerRadiuses? + public let border: Border? public init(defaultSelectedPackageID: String, components: [PaywallComponent], @@ -41,7 +42,8 @@ public extension PaywallComponent { backgroundColor: ColorInfo? = nil, padding: Padding = .zero, margin: Padding = .zero, - cornerRadiuses: CornerRadiuses = .zero + cornerRadiuses: CornerRadiuses? = nil, + border: Border? = nil ) { self.type = .packageGroup self.defaultSelectedPackageID = defaultSelectedPackageID @@ -53,6 +55,7 @@ public extension PaywallComponent { self.padding = padding self.margin = margin self.cornerRadiuses = cornerRadiuses + self.border = border } } diff --git a/Sources/Paywalls/Components/PaywallStackComponent.swift b/Sources/Paywalls/Components/PaywallStackComponent.swift index cd7df47d8d..4cd03cadcf 100644 --- a/Sources/Paywalls/Components/PaywallStackComponent.swift +++ b/Sources/Paywalls/Components/PaywallStackComponent.swift @@ -28,7 +28,8 @@ public extension PaywallComponent { public let dimension: Dimension public let padding: Padding public let margin: Padding - public let cornerRadiuses: CornerRadiuses + public let cornerRadiuses: CornerRadiuses? + public let border: Border? public init(components: [PaywallComponent], dimension: Dimension = .vertical(.center), @@ -37,7 +38,8 @@ public extension PaywallComponent { backgroundColor: ColorInfo? = nil, padding: Padding = .zero, margin: Padding = .zero, - cornerRadiuses: CornerRadiuses = .zero + cornerRadiuses: CornerRadiuses? = nil, + border: Border? = nil ) { self.components = components self.width = width @@ -48,6 +50,7 @@ public extension PaywallComponent { self.padding = padding self.margin = margin self.cornerRadiuses = cornerRadiuses + self.border = border } }