Restrict paywall to on-demand rules (#639)

Rather than whole module.

Closes #638
This commit is contained in:
Davide 2024-09-30 15:56:32 +02:00 committed by GitHub
parent a9fa6a2f62
commit 4877c2bd20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 59 additions and 16 deletions

View File

@ -32,7 +32,7 @@
"kind" : "remoteSourceControl",
"location" : "git@github.com:passepartoutvpn/passepartoutkit",
"state" : {
"revision" : "263bedc756d07eb107d7bfe3b50dbc5db28675d4"
"revision" : "3d1a60be9722861f9de45e355d520bae33ac87a9"
}
},
{

View File

@ -31,7 +31,7 @@ let package = Package(
],
dependencies: [
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit", from: "0.7.0"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit", revision: "263bedc756d07eb107d7bfe3b50dbc5db28675d4"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit", revision: "3d1a60be9722861f9de45e355d520bae33ac87a9"),
// .package(path: "../../../passepartoutkit"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-openvpn-openssl", from: "0.6.0"),
// .package(path: "../../../passepartoutkit-openvpn-openssl"),

View File

@ -30,11 +30,16 @@ extension IAPManager: ProfileProcessor {
func processedProfile(_ profile: Profile) throws -> Profile {
var builder = profile.builder()
// suppress on-demand module if not eligible
// suppress on-demand rules if not eligible
if !isEligible(for: .onDemand) {
pp_log(.app, .notice, "Disable on-demand rules, not eligible")
builder.modules.removeAll {
$0 is OnDemandModule
pp_log(.app, .notice, "Suppress on-demand rules, not eligible")
if let onDemandModuleIndex = builder.modules.firstIndex(where: { $0 is OnDemandModule }),
let onDemandModule = builder.modules[onDemandModuleIndex] as? OnDemandModule {
var onDemandBuilder = onDemandModule.builder()
onDemandBuilder.policy = .any
builder.modules[onDemandModuleIndex] = onDemandBuilder.tryBuild()
}
}

View File

@ -243,6 +243,8 @@ public enum Strings {
public static let `protocol` = Strings.tr("Localizable", "global.protocol", fallback: "Protocol")
/// Public key
public static let publicKey = Strings.tr("Localizable", "global.public_key", fallback: "Public key")
/// Purchase
public static let purchase = Strings.tr("Localizable", "global.purchase", fallback: "Purchase")
/// Delete
public static let remove = Strings.tr("Localizable", "global.remove", fallback: "Delete")
/// Restart
@ -312,6 +314,8 @@ public enum Strings {
public static let mobile = Strings.tr("Localizable", "modules.on_demand.mobile", fallback: "Mobile")
/// Policy
public static let policy = Strings.tr("Localizable", "modules.on_demand.policy", fallback: "Policy")
/// Add on-demand rules
public static let purchase = Strings.tr("Localizable", "modules.on_demand.purchase", fallback: "Add on-demand rules")
public enum Policy {
/// Activate the VPN %@.
public static func footer(_ p1: Any) -> String {

View File

@ -47,6 +47,7 @@
"global.private_key" = "Private key";
"global.protocol" = "Protocol";
"global.public_key" = "Public key";
"global.purchase" = "Purchase";
"global.remove" = "Delete";
"global.restart" = "Restart";
"global.route" = "Route";
@ -168,6 +169,7 @@
"modules.ip.routes.excluded" = "Excluded routes";
"modules.ip.routes.add_family" = "Add %@";
"modules.on_demand.purchase" = "Add on-demand rules";
"modules.on_demand.policy" = "Policy";
"modules.on_demand.policy.footer" = "Activate the VPN %@.";
"modules.on_demand.policy.footer.any" = "in any network";

View File

@ -38,6 +38,9 @@ private struct OnDemandView: View {
@EnvironmentObject
private var theme: Theme
@EnvironmentObject
private var iapManager: IAPManager
@ObservedObject
private var editor: ProfileEditor
@ -46,6 +49,9 @@ private struct OnDemandView: View {
@Binding
private var draft: OnDemandModule.Builder
@State
private var paywallReason: PaywallReason?
init(
editor: ProfileEditor,
original: OnDemandModule.Builder,
@ -59,15 +65,10 @@ private struct OnDemandView: View {
var body: some View {
Group {
enabledSection
if draft.isEnabled {
policySection
if draft.policy != .any {
networkSection
wifiSection
}
}
restrictedSection
}
.asModuleView(with: editor, draft: draft)
.modifier(PaywallModifier(reason: $paywallReason))
}
}
@ -84,6 +85,28 @@ private extension OnDemandView {
}
}
@ViewBuilder
var restrictedSection: some View {
switch iapManager.paywallReason(forFeature: .onDemand) {
case .purchase(let feature):
Button(Strings.Modules.OnDemand.purchase) {
paywallReason = .purchase(feature)
}
case .restricted:
EmptyView()
default:
if draft.isEnabled {
policySection
if draft.policy != .any {
networkSection
wifiSection
}
}
}
}
var policySection: some View {
Picker(Strings.Modules.OnDemand.policy, selection: $draft.policy) {
ForEach(Self.allPolicies, id: \.self) {

View File

@ -104,7 +104,7 @@ private extension ProfileCoordinator {
func onNewModule(_ moduleType: ModuleType) {
switch moduleType {
case .onDemand:
paywallReason = iapManager.paywallReason(forFeature: .onDemand)
break
default:
paywallReason = iapManager.paywallReason(forFeature: .networkSettings)

View File

@ -34,7 +34,7 @@ extension EditableModule where Self: ModuleViewProviding {
moduleView(with: ProfileEditor(modules: [self]))
.navigationTitle(title)
}
.environmentObject(Theme())
.withMockEnvironment()
}
@MainActor
@ -42,6 +42,15 @@ extension EditableModule where Self: ModuleViewProviding {
NavigationStack {
content(ProfileEditor(modules: [self]), self)
}
.environmentObject(Theme())
.withMockEnvironment()
}
}
@MainActor
private extension View {
func withMockEnvironment() -> some View {
environmentObject(Theme())
.environmentObject(IAPManager.mock)
.environmentObject(ConnectionObserver.mock)
}
}