Skip to content

Commit

Permalink
Create a completion handler
Browse files Browse the repository at this point in the history
  • Loading branch information
vegaro committed Jul 10, 2024
1 parent 7ccc4f5 commit f6621c6
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 15 deletions.
12 changes: 12 additions & 0 deletions RevenueCat.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,9 @@
354895D6267BEDE3001DC5B1 /* ReservedSubscriberAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 354895D5267BEDE3001DC5B1 /* ReservedSubscriberAttributes.swift */; };
35549323269E298B005F9AE9 /* OfferingsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 35549322269E298B005F9AE9 /* OfferingsFactory.swift */; };
357349012C3BEB5C000EEB86 /* CustomerCenterConfigDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 357348FF2C3BEB0A000EEB86 /* CustomerCenterConfigDataTests.swift */; };
357348F12C3931FC000EEB86 /* View+CustomerCenterCompleted.swift in Sources */ = {isa = PBXBuildFile; fileRef = 357348F02C3931FC000EEB86 /* View+CustomerCenterCompleted.swift */; };
357348F32C39342F000EEB86 /* CustomerCenterCompletionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 357348F22C39342F000EEB86 /* CustomerCenterCompletionHandler.swift */; };
357348F52C393642000EEB86 /* CustomerCenterStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 357348F42C393642000EEB86 /* CustomerCenterStatus.swift */; };
3592E8862C2ED51700D7F91D /* CustomerCenterConfigCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3592E8852C2ED51700D7F91D /* CustomerCenterConfigCallback.swift */; };
3592E88A2C2ED54A00D7F91D /* CustomerCenterConfigData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3592E8882C2ED54A00D7F91D /* CustomerCenterConfigData.swift */; };
3592E88C2C2ED58900D7F91D /* GetCustomerCenterConfigOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3592E88B2C2ED58900D7F91D /* GetCustomerCenterConfigOperation.swift */; };
Expand Down Expand Up @@ -1187,6 +1190,9 @@
354895D5267BEDE3001DC5B1 /* ReservedSubscriberAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReservedSubscriberAttributes.swift; sourceTree = "<group>"; };
35549322269E298B005F9AE9 /* OfferingsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OfferingsFactory.swift; sourceTree = "<group>"; };
357348FF2C3BEB0A000EEB86 /* CustomerCenterConfigDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerCenterConfigDataTests.swift; sourceTree = "<group>"; };
357348F02C3931FC000EEB86 /* View+CustomerCenterCompleted.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+CustomerCenterCompleted.swift"; sourceTree = "<group>"; };
357348F22C39342F000EEB86 /* CustomerCenterCompletionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerCenterCompletionHandler.swift; sourceTree = "<group>"; };
357348F42C393642000EEB86 /* CustomerCenterStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomerCenterStatus.swift; sourceTree = "<group>"; };
357C9BC022725CFA006BC624 /* iAd.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = iAd.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/iAd.framework; sourceTree = DEVELOPER_DIR; };
3592E8852C2ED51700D7F91D /* CustomerCenterConfigCallback.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomerCenterConfigCallback.swift; sourceTree = "<group>"; };
3592E8882C2ED54A00D7F91D /* CustomerCenterConfigData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomerCenterConfigData.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2561,6 +2567,7 @@
353756542C382C2800A1B8D6 /* CustomerCenterError.swift */,
35C200AE2C39252D00B9778B /* FeedbackSurveyData.swift */,
353756552C382C2800A1B8D6 /* SubscriptionInformation.swift */,
357348F42C393642000EEB86 /* CustomerCenterStatus.swift */,
);
path = Data;
sourceTree = "<group>";
Expand All @@ -2587,6 +2594,8 @@
3546355E2C391F4D001D7E85 /* PromotionalOfferView.swift */,
3537565E2C382C2800A1B8D6 /* RestorePurchasesAlert.swift */,
3537565F2C382C2800A1B8D6 /* WrongPlatformView.swift */,
357348F02C3931FC000EEB86 /* View+CustomerCenterCompleted.swift */,
357348F22C39342F000EEB86 /* CustomerCenterCompletionHandler.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -5221,8 +5230,10 @@
887A60712C1D037000E1A461 /* PaywallViewConfiguration.swift in Sources */,
3537566C2C382C2800A1B8D6 /* ManageSubscriptionsView.swift in Sources */,
887A60C82C1D037000E1A461 /* ProgressView.swift in Sources */,
357348F52C393642000EEB86 /* CustomerCenterStatus.swift in Sources */,
887A60D02C1D037000E1A461 /* View+PurchaseRestoreCompleted.swift in Sources */,
887A60CD2C1D037000E1A461 /* PaywallView.swift in Sources */,
357348F12C3931FC000EEB86 /* View+CustomerCenterCompleted.swift in Sources */,
887A60C12C1D037000E1A461 /* DebugErrorView.swift in Sources */,
887A607C2C1D037000E1A461 /* ColorInformation+MultiScheme.swift in Sources */,
887A60782C1D037000E1A461 /* TestData.swift in Sources */,
Expand Down Expand Up @@ -5255,6 +5266,7 @@
3546355D2C391F38001D7E85 /* PromotionalOfferViewModel.swift in Sources */,
887A60762C1D037000E1A461 /* TemplateViewConfiguration+Extensions.swift in Sources */,
887A607A2C1D037000E1A461 /* Variables.swift in Sources */,
357348F32C39342F000EEB86 /* CustomerCenterCompletionHandler.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,16 @@ enum CustomerCenterConfigTestData {
]
)
],
// swiftlint:disable force_try
appearance: .init(
mode: .custom(accentColor: try! RCColor(light: RCColor(stringRepresentation: "#ffffff"),
mode: .custom(accentColor: try! RCColor(light: RCColor(stringRepresentation: "#ffffff"),
dark: try! RCColor(stringRepresentation: "#000000")),
backgroundColor: try! RCColor(light: RCColor(stringRepresentation: "#000000"),
backgroundColor: try! RCColor(light: RCColor(stringRepresentation: "#000000"),
dark: try! RCColor(stringRepresentation: "#ffffff")),
textColor: try! RCColor(light: RCColor(stringRepresentation: "#000000"),
textColor: try! RCColor(light: RCColor(stringRepresentation: "#000000"),
dark: try! RCColor(stringRepresentation: "#ffffff")))
),
// swiftlint:enable force_try
localization: .init(
locale: "en_US",
localizedStrings: [
Expand Down
24 changes: 24 additions & 0 deletions RevenueCatUI/CustomerCenter/Data/CustomerCenterStatus.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// 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
//
// CustomerCenterStatus.swift
//
// Created by Cesar de la Vega on 6/7/24.

import Foundation

public enum CustomerCenterStatus {

case promotionalOffer
case canceledSubscription
case contactSupport
case refundRequest
case changePlan

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// 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
//
// CustomerCenterCompletionHandler.swift
//
// Created by Cesar de la Vega on 6/7/24.

import Foundation
import SwiftUI

final class CustomerCenterCompletionHandler: ObservableObject {

@Published
fileprivate(set) var customerCenterResult: CustomerCenterResult?

static func `default`() -> Self {
return .init()
}

func supportContacted() {
self.customerCenterResult = CustomerCenterResult(status: .contactSupport)
}

}

struct CustomerCenterResult: Equatable {

var status: CustomerCenterStatus
// swiftlint:disable:next todo
// TODO: store error

init(status: CustomerCenterStatus) {
self.status = status
}

init?(status: CustomerCenterStatus?) {
guard let status else { return nil }
self.init(status: status)
}

}

struct CustomerCenterResultPreferenceKey: PreferenceKey {

static var defaultValue: CustomerCenterResult?

static func reduce(value: inout CustomerCenterResult?, nextValue: () -> CustomerCenterResult?) {
value = nextValue()
}

}
15 changes: 12 additions & 3 deletions RevenueCatUI/CustomerCenter/Views/CustomerCenterView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ import SwiftUI
@available(visionOS, unavailable)
public struct CustomerCenterView: View {

@StateObject private var viewModel = CustomerCenterViewModel()
@StateObject
private var viewModel = CustomerCenterViewModel()
@StateObject
private var completionHandler: CustomerCenterCompletionHandler = .default()

/// Create a view to handle common customer support tasks
public init() {}

fileprivate init(viewModel: CustomerCenterViewModel) {
self._viewModel = .init(wrappedValue: viewModel)
self._completionHandler = .init(wrappedValue: .default())
}

// swiftlint:disable:next missing_docs
Expand All @@ -49,6 +53,8 @@ public struct CustomerCenterView: View {
.task {
await loadInformationIfNeeded()
}
.preference(key: CustomerCenterResultPreferenceKey.self,
value: .init(status: self.completionHandler.customerCenterResult?.status))
}

}
Expand All @@ -72,12 +78,15 @@ private extension CustomerCenterView {
if viewModel.hasSubscriptions {
if viewModel.subscriptionsAreFromApple,
let screen = configuration.screens[.management] {
ManageSubscriptionsView(screen: screen, appearance: configuration.appearance)
ManageSubscriptionsView(screen: screen,
appearance: configuration.appearance,
completionHandler: completionHandler)
} else {
WrongPlatformView()
}
} else {
NoSubscriptionsView(configuration: configuration)
NoSubscriptionsView(configuration: configuration,
completionHandler: completionHandler)
}
}

Expand Down
16 changes: 13 additions & 3 deletions RevenueCatUI/CustomerCenter/Views/ManageSubscriptionsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,21 @@ struct ManageSubscriptionsView: View {

@StateObject
private var viewModel: ManageSubscriptionsViewModel
@ObservedObject
private var completionHandler: CustomerCenterCompletionHandler

init(screen: CustomerCenterConfigData.Screen,
appearance: CustomerCenterConfigData.Appearance) {
appearance: CustomerCenterConfigData.Appearance,
completionHandler: CustomerCenterCompletionHandler) {
let viewModel = ManageSubscriptionsViewModel(screen: screen, appearance: appearance)
self._viewModel = .init(wrappedValue: viewModel)
self._completionHandler = .init(initialValue: completionHandler)
}

fileprivate init(viewModel: ManageSubscriptionsViewModel) {
fileprivate init(viewModel: ManageSubscriptionsViewModel,
completionHandler: CustomerCenterCompletionHandler) {
self._viewModel = .init(wrappedValue: viewModel)
self._completionHandler = .init(initialValue: completionHandler)
}

var body: some View {
Expand All @@ -52,6 +58,7 @@ struct ManageSubscriptionsView: View {
Spacer()

ManageSubscriptionsButtonsView(viewModel: self.viewModel,
completionHandler: self.completionHandler,
loadingPath: self.$viewModel.loadingPath)

} else {
Expand Down Expand Up @@ -161,6 +168,8 @@ struct ManageSubscriptionsButtonsView: View {

@ObservedObject
var viewModel: ManageSubscriptionsViewModel
@ObservedObject
var completionHandler: CustomerCenterCompletionHandler
@Binding
var loadingPath: CustomerCenterConfigData.HelpPath?
@Environment(\.openURL)
Expand All @@ -182,6 +191,7 @@ struct ManageSubscriptionsButtonsView: View {
Task {
openURL(URLUtilities.createMailURL()!)
}
completionHandler.supportContacted()
}
.padding()
}
Expand Down Expand Up @@ -241,7 +251,7 @@ struct ManageSubscriptionsView_Previews: PreviewProvider {
screen: CustomerCenterConfigTestData.customerCenterData.screens[.management]!,
appearance: CustomerCenterConfigTestData.customerCenterData.appearance,
subscriptionInformation: CustomerCenterConfigTestData.subscriptionInformation)
ManageSubscriptionsView(viewModel: viewModel)
ManageSubscriptionsView(viewModel: viewModel, completionHandler: .default())
}

}
Expand Down
26 changes: 20 additions & 6 deletions RevenueCatUI/CustomerCenter/Views/NoSubscriptionsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,25 @@ import SwiftUI
@available(watchOS, unavailable)
@available(visionOS, unavailable)
struct NoSubscriptionsView: View {

init(configuration: CustomerCenterConfigData) {
self.configuration = configuration
}

// swiftlint:disable:next todo
// TODO: build screen using this configuration
private let configuration: CustomerCenterConfigData


@Environment(\.openURL)
private var openURL
@ObservedObject
private var completionHandler: CustomerCenterCompletionHandler
@Environment(\.dismiss)
private var dismiss
@State
private var showRestoreAlert: Bool = false

init(configuration: CustomerCenterConfigData, completionHandler: CustomerCenterCompletionHandler) {
self.configuration = configuration
_completionHandler = .init(initialValue: completionHandler)
}

var body: some View {
VStack {
Text("No Subscriptions found")
Expand All @@ -54,6 +59,14 @@ struct NoSubscriptionsView: View {
}
.restorePurchasesAlert(isPresented: $showRestoreAlert)
.buttonStyle(ManageSubscriptionsButtonStyle(appearance: self.configuration.appearance))

Button("Contact support") {
Task {
openURL(URLUtilities.createMailURL()!)
}
completionHandler.supportContacted()
}
.padding()

Button("Cancel") {
dismiss()
Expand All @@ -75,7 +88,8 @@ struct NoSubscriptionsView: View {
struct NoSubscriptionsView_Previews: PreviewProvider {

static var previews: some View {
NoSubscriptionsView(configuration: CustomerCenterConfigTestData.customerCenterData)
NoSubscriptionsView(configuration: CustomerCenterConfigTestData.customerCenterData,
completionHandler: .default())
}

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// 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
//
// View+CustomerCenterCompleted.swift
//
// Created by Cesar de la Vega on 6/7/24.

import Foundation
import SwiftUI

public typealias CustomerCenterCompletedHandler = @MainActor @Sendable (_ status: CustomerCenterStatus) -> Void

extension View {

public func onCustomerCenterCompleted(
_ handler: @escaping CustomerCenterCompletedHandler
) -> some View {
return self.modifier(CustomerCenterCompletedViewModifier(handler: handler))
}

}

private struct CustomerCenterCompletedViewModifier: ViewModifier {

let handler: CustomerCenterCompletedHandler

init(handler: @escaping CustomerCenterCompletedHandler) {
self.handler = handler
}

func body(content: Content) -> some View {
content.onPreferenceChange(CustomerCenterResultPreferenceKey.self) { result in
if let result {
self.handler(result.status)
}
}
}

}

0 comments on commit f6621c6

Please sign in to comment.