Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Customer Center] CustomerCenterViewModel checks whether the app is the latest version #4169

Merged
merged 66 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from 54 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
444d450
Create file
vegaro Jun 17, 2024
c5aaf56
[Customer Center] Create `CustomerCenterView` (#3919)
vegaro Jun 28, 2024
9bc2c08
[Customer Center] Add API call to get Customer Center config (#3933)
vegaro Jul 9, 2024
fec9486
[Customer Center] Build feedback survey from JSON (#3959)
vegaro Jul 11, 2024
b087782
[Customer Center] Show the right subscription on the Manage Subscript…
JayShortway Jul 16, 2024
6cd489f
[CustomerCenter] Add `presentCustomerCenter` modifier (#4053)
tonidero Jul 16, 2024
5ea67b2
[Customer Center] Adds the Customer Center to PaywallsTester (#4055)
JayShortway Jul 17, 2024
5030a3c
[Customer Center] Improves the UI of the current subscription (#4072)
JayShortway Jul 18, 2024
1868044
[Customer Center] Updates the presentation of the refund status (#4082)
JayShortway Jul 18, 2024
2a9cd2c
[CustomerCenter] Add action handler (#4057)
tonidero Jul 18, 2024
fa06324
[Customer Center] Promotional Offers support (#3968)
vegaro Jul 19, 2024
0d7530e
Move No subscriptions page strings to Localization (#4089)
tonidero Jul 19, 2024
bd7e4c9
Merge branch 'main' into integration/customer_support_workflow
tonidero Jul 19, 2024
b45e274
[Customer Center] Add colors support (#3983)
vegaro Jul 19, 2024
dcbfb7d
[Customer Center] SubscriptionDetailsView gets its strings from Commo…
JayShortway Jul 22, 2024
ced36e8
Merge branch 'main' into integration/customer_support_workflow
vegaro Jul 22, 2024
e3f9250
Merge branch 'main' into integration/customer_support_workflow
vegaro Jul 24, 2024
dc22e0d
ignore tags
vegaro Jul 24, 2024
acbc391
[Customer Center] Fix project.pbxproj (#4122)
vegaro Jul 29, 2024
29340ca
[Customer Center] Fix `BackendGetCustomerCenterConfigTests` (#4124)
vegaro Jul 29, 2024
7a9e3e9
Merge branch 'main' into integration/customer_support_workflow
vegaro Jul 29, 2024
2977e6b
[Customer Center] Add contact support button (#4023)
vegaro Jul 29, 2024
b6a3069
Merge branch 'main' into integration/customer_support_workflow
vegaro Jul 30, 2024
c255107
[Customer Center] Fix checking eligibility (#4138)
vegaro Jul 31, 2024
167a609
[Customer Center] Make colors nullable (#4134)
vegaro Aug 1, 2024
43ad9b1
Merge branch 'main' into integration/customer_support_workflow
vegaro Aug 1, 2024
dbd43aa
[Customer Center] Fix for disabled promo offer button (#4142)
vegaro Aug 2, 2024
6084a2c
Version 5.2.2-customercenter.alpha.3
vegaro Aug 2, 2024
7e9b355
[Customer Center] Fixes an extra blank screen after popping FeedbackS…
JayShortway Aug 6, 2024
e1b0cf4
[Customer Center] Improve subscription details view (#4152)
codykerns Aug 8, 2024
92db864
Customer Center compilation flag (#4149)
aboedo Aug 8, 2024
789d26a
Merge branch 'main' of github.com:RevenueCat/purchases-ios into integ…
tonidero Aug 8, 2024
c52f3cf
[Customer Center] UI polish for empty content (#4147)
codykerns Aug 8, 2024
3662879
[Customer Center] Use system navigation titles (#4161)
codykerns Aug 8, 2024
9284107
Disable `CustomerCenter` build flags (#4160)
tonidero Aug 9, 2024
759fd53
Fix compilation issues in older targets
tonidero Aug 9, 2024
ae44b59
Adds SemanticVersion
JayShortway Aug 9, 2024
52195fb
Revert "Disable `CustomerCenter` build flags (#4160)"
JayShortway Aug 9, 2024
f1e4da2
CustomerCenterViewModel checks whether the app is the latest version.
JayShortway Aug 12, 2024
9e943fa
Merge branch 'main' into check-latest-version
JayShortway Aug 12, 2024
08000e5
Cleanup
JayShortway Aug 12, 2024
9d5cffb
More cleanup.
JayShortway Aug 12, 2024
b11307b
Merge branch 'main' into check-latest-version
JayShortway Aug 13, 2024
dc1f795
CustomerCenterConfigResponse now provides lastPublishedAppVersion.
JayShortway Aug 13, 2024
be65640
Fixes CustomerCenterConfigDataTests.
JayShortway Aug 13, 2024
507d91c
Adds some more test cases.
JayShortway Aug 13, 2024
71171ac
Correctly (?) adds SemanticVersion to Xcode.
JayShortway Aug 13, 2024
5be6750
Fixes some warnings and adds the compiler flag to SemanticVersion[Tes…
JayShortway Aug 13, 2024
305d28e
Fixes a compile error.
JayShortway Aug 13, 2024
b9e241b
Fixes some warnings.
JayShortway Aug 13, 2024
50d7102
SemanticVersion only accepts UInts now.
JayShortway Aug 14, 2024
54c6ff6
appIsLatestVersion is initialized with defaultAppIsLatestVersion.
JayShortway Aug 14, 2024
8072747
Renames takeVersion to versionString.
JayShortway Aug 14, 2024
a64e6b4
Fixes a compilation error in SemanticVersionTests.
JayShortway Aug 14, 2024
385ab4e
defaultAppIsLatestVersion is static now.
JayShortway Aug 15, 2024
bbe3fca
Revert "Disable `CustomerCenter` build flags (#4160)"
tonidero Aug 9, 2024
7329cb6
Uses the existing SystemInfo.appVersion.
JayShortway Aug 15, 2024
19b7881
Uses a single guard let statement.
JayShortway Aug 15, 2024
1473222
Adds some more test cases.
JayShortway Aug 15, 2024
1ae81ea
Revert "Revert "Disable `CustomerCenter` build flags (#4160)""
JayShortway Aug 15, 2024
d32e24a
Uses CFBundleShortVersionString directly.
JayShortway Aug 15, 2024
b72d05c
Fixes CustomerCenterConfigDataAPI.
JayShortway Aug 15, 2024
aae889a
Revert "Disable `CustomerCenter` build flags (#4160)"
tonidero Aug 9, 2024
1412b6b
Revert "Revert "Disable `CustomerCenter` build flags (#4160)""
JayShortway Aug 15, 2024
0c2bdaa
Merge branch 'main' into check-latest-version
JayShortway Aug 15, 2024
129b124
Merge branch 'main' into check-latest-version
JayShortway Aug 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions RevenueCat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,8 @@
57FFD2512922DBED00A9A878 /* MockStoreTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FFD2502922DBED00A9A878 /* MockStoreTransaction.swift */; };
57FFD2522922DBED00A9A878 /* MockStoreTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57FFD2502922DBED00A9A878 /* MockStoreTransaction.swift */; };
6E38843A0CAFD551013D0A3F /* StoreProduct.swift in Sources */ = {isa = PBXBuildFile; fileRef = FECF627761D375C8431EB866 /* StoreProduct.swift */; };
77791ECF2C6B852000BCEF03 /* SemanticVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77791ECE2C6B851F00BCEF03 /* SemanticVersion.swift */; };
777FB4882C661C0600CD4749 /* SemanticVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 777FB4872C661C0600CD4749 /* SemanticVersionTests.swift */; };
805B60C97993B311CEC93EAF /* ProductsFetcherSK2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3628C1F100BB3C1782860D24 /* ProductsFetcherSK2.swift */; };
80E80EF226970E04008F245A /* ReceiptFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80E80EF026970DC3008F245A /* ReceiptFetcher.swift */; };
8834AFA52C2B9375005A72FE /* PresentIfNeededTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887A62222C1D168B00E1A461 /* PresentIfNeededTests.swift */; };
Expand Down Expand Up @@ -1787,6 +1789,8 @@
57FDAABD28493A29009A48F1 /* SandboxEnvironmentDetectorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SandboxEnvironmentDetectorTests.swift; sourceTree = "<group>"; };
57FDAABF28493C13009A48F1 /* MockSandboxEnvironmentDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSandboxEnvironmentDetector.swift; sourceTree = "<group>"; };
57FFD2502922DBED00A9A878 /* MockStoreTransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockStoreTransaction.swift; sourceTree = "<group>"; };
77791ECE2C6B851F00BCEF03 /* SemanticVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemanticVersion.swift; sourceTree = "<group>"; };
777FB4872C661C0600CD4749 /* SemanticVersionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SemanticVersionTests.swift; sourceTree = "<group>"; };
80E80EF026970DC3008F245A /* ReceiptFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiptFetcher.swift; sourceTree = "<group>"; };
84C3F1AC1D7E1E64341D3936 /* Pods_RevenueCat_PurchasesTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RevenueCat_PurchasesTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
887A5FB42C1D024300E1A461 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3103,6 +3107,7 @@
353756562C382C2800A1B8D6 /* Data */ = {
isa = PBXGroup;
children = (
77791ECE2C6B851F00BCEF03 /* SemanticVersion.swift */,
3525D8A32C4AB3D500C21D99 /* CustomerCenterEnvironment.swift */,
353756532C382C2800A1B8D6 /* CustomerCenterConfigTestData.swift */,
353756542C382C2800A1B8D6 /* CustomerCenterError.swift */,
Expand Down Expand Up @@ -4089,6 +4094,7 @@
887A612A2C1D168B00E1A461 /* PaywallDataValidationTests.swift */,
887A612B2C1D168B00E1A461 /* TemplateViewConfigurationTests.swift */,
887A612C2C1D168B00E1A461 /* VariablesTests.swift */,
777FB4872C661C0600CD4749 /* SemanticVersionTests.swift */,
);
path = Data;
sourceTree = "<group>";
Expand Down Expand Up @@ -5789,6 +5795,7 @@
887A60CC2C1D037000E1A461 /* PaywallFontProvider.swift in Sources */,
887A60B82C1D037000E1A461 /* Template1View.swift in Sources */,
887A60C62C1D037000E1A461 /* LoadingPaywallView.swift in Sources */,
77791ECF2C6B852000BCEF03 /* SemanticVersion.swift in Sources */,
887A60C72C1D037000E1A461 /* PackageButtonStyle.swift in Sources */,
887A60C52C1D037000E1A461 /* IntroEligibilityStateView.swift in Sources */,
88A543E72C37A4C40039C6A5 /* TierSelectorView.swift in Sources */,
Expand Down Expand Up @@ -5909,6 +5916,7 @@
887A633A2C1D177800E1A461 /* PaywallViewDynamicTypeTests.swift in Sources */,
887A633B2C1D177800E1A461 /* PaywallViewLocalizationTests.swift in Sources */,
887A633C2C1D177800E1A461 /* Template1ViewTests.swift in Sources */,
777FB4882C661C0600CD4749 /* SemanticVersionTests.swift in Sources */,
88AD4C482C24E8EA00943C3E /* ExternalPurchaseAndRestoreTests.swift in Sources */,
887A633D2C1D177800E1A461 /* Template2ViewTests.swift in Sources */,
887A633E2C1D177800E1A461 /* Template3ViewTests.swift in Sources */,
Expand Down
169 changes: 88 additions & 81 deletions RevenueCatUI/CustomerCenter/Data/CustomerCenterConfigTestData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,87 +21,94 @@ import RevenueCat
enum CustomerCenterConfigTestData {

@available(iOS 14.0, *)
static let customerCenterData = CustomerCenterConfigData(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend reviewing this file while hiding whitespace (on GitHub), as the actual change is tiny.

screens: [.management:
.init(
type: .management,
title: "Manage Subscription",
subtitle: "Manage your subscription details here",
paths: [
.init(
id: "1",
title: "Didn't receive purchase",
type: .missingPurchase,
detail: nil
),
.init(
id: "2",
title: "Request a refund",
type: .refundRequest,
detail: .promotionalOffer(CustomerCenterConfigData.HelpPath.PromotionalOffer(
iosOfferId: "offer_id",
eligible: true,
title: "title",
subtitle: "subtitle"
))
),
.init(
id: "3",
title: "Change plans",
type: .changePlans,
detail: nil
),
.init(
id: "4",
title: "Cancel subscription",
type: .cancel,
detail: .feedbackSurvey(.init(
title: "Why are you cancelling?",
options: [
.init(
id: "1",
title: "Too expensive",
promotionalOffer: nil
),
.init(
id: "2",
title: "Don't use the app",
promotionalOffer: nil
),
.init(
id: "3",
title: "Bought by mistake",
promotionalOffer: nil
)
]
))
)
]
),
.noActive: .init(
type: .noActive,
title: "No Active Subscription",
subtitle: "You currently have no active subscriptions",
paths: [
.init(
id: "9q9719171o",
title: "Check purchases",
type: .missingPurchase,
detail: nil
)
]
)
],
appearance: standardAppearance,
localization: .init(
locale: "en_US",
localizedStrings: [
"cancel": "Cancel",
"back": "Back"
]
),
support: .init(email: "[email protected]")
)
// swiftlint:disable:next function_body_length
static func customerCenterData(lastPublishedAppVersion: String?) -> CustomerCenterConfigData {
CustomerCenterConfigData(
screens: [.management:
.init(
type: .management,
title: "Manage Subscription",
subtitle: "Manage your subscription details here",
paths: [
.init(
id: "1",
title: "Didn't receive purchase",
type: .missingPurchase,
detail: nil
),
.init(
id: "2",
title: "Request a refund",
type: .refundRequest,
detail: .promotionalOffer(CustomerCenterConfigData.HelpPath.PromotionalOffer(
iosOfferId: "offer_id",
eligible: true,
title: "title",
subtitle: "subtitle"
))
),
.init(
id: "3",
title: "Change plans",
type: .changePlans,
detail: nil
),
.init(
id: "4",
title: "Cancel subscription",
type: .cancel,
detail: .feedbackSurvey(.init(
title: "Why are you cancelling?",
options: [
.init(
id: "1",
title: "Too expensive",
promotionalOffer: nil
),
.init(
id: "2",
title: "Don't use the app",
promotionalOffer: nil
),
.init(
id: "3",
title: "Bought by mistake",
promotionalOffer: nil
)
]
))
)
]
),
.noActive: .init(
type: .noActive,
title: "No Active Subscription",
subtitle: "You currently have no active subscriptions",
paths: [
.init(
id: "9q9719171o",
title: "Check purchases",
type: .missingPurchase,
detail: nil
)
]
)
],
appearance: standardAppearance,
localization: .init(
locale: "en_US",
localizedStrings: [
"cancel": "Cancel",
"back": "Back"
]
),
support: .init(email: "[email protected]"),
lastPublishedAppVersion: lastPublishedAppVersion
)
}

@available(iOS 14.0, *)
static let customerCenterData = customerCenterData(lastPublishedAppVersion: "1.0.0")

static let standardAppearance = CustomerCenterConfigData.Appearance(
accentColor: .init(light: "#007AFF", dark: "#007AFF"),
Expand Down
73 changes: 73 additions & 0 deletions RevenueCatUI/CustomerCenter/Data/SemanticVersion.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// 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
//
// SemanticVersion.swift
//
// Created by JayShortway on 08/08/2024.

#if CUSTOMER_CENTER_ENABLED

import Foundation

struct SemanticVersion: Comparable {
let major: UInt
let minor: UInt
let patch: UInt

init(major: UInt, minor: UInt, patch: UInt) {
self.major = major
self.minor = minor
self.patch = patch
}

init(_ version: String) throws {
let pattern = #"^(\d+)(?:\.(\d+))?(?:\.(\d+))?$"#
guard let regex = try? NSRegularExpression(pattern: pattern),
JayShortway marked this conversation as resolved.
Show resolved Hide resolved
let match = regex.firstMatch(in: version, range: NSRange(version.startIndex..., in: version)) else {
throw SemanticVersionError.invalidVersionString(version)
}

let major = UInt(version[Range(match.range(at: 1), in: version)!])!
let minor = match.range(at: 2).location != NSNotFound ?
UInt(version[Range(match.range(at: 2), in: version)!])! :
0
let patch = match.range(at: 3).location != NSNotFound ?
UInt(version[Range(match.range(at: 3), in: version)!])! :
0

self.init(major: major, minor: minor, patch: patch)
}

static func < (lhs: SemanticVersion, rhs: SemanticVersion) -> Bool {
if lhs.major != rhs.major {
return lhs.major < rhs.major
} else if lhs.minor != rhs.minor {
return lhs.minor < rhs.minor
} else {
return lhs.patch < rhs.patch
}
}

static func == (lhs: SemanticVersion, rhs: SemanticVersion) -> Bool {
return lhs.major == rhs.major && lhs.minor == rhs.minor && lhs.patch == rhs.patch
}
}

enum SemanticVersionError: LocalizedError {
case invalidVersionString(String)

var errorDescription: String? {
switch self {
case .invalidVersionString(let version):
return "Invalid version string: '\(version)'. Expected format: 'major.minor.patch'"
}
}
}

#endif
Loading