Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class UsercentricsPlugin : FlutterPlugin,
GetDpsMetadataBridge(),
NotifyLoginSuccessBridge(),
NotifySubscribeSuccessBridge(),
NotifySubscriptionLapsedBridge(),
).associateBy { it.name }
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.usercentrics.sdk.flutter.bridge

import com.usercentrics.sdk.flutter.api.FlutterMethodCall
import com.usercentrics.sdk.flutter.api.FlutterResult
import com.usercentrics.sdk.flutter.api.UsercentricsProxy
import com.usercentrics.sdk.flutter.api.UsercentricsProxySingleton

internal class NotifySubscriptionLapsedBridge(
private val usercentrics: UsercentricsProxy = UsercentricsProxySingleton
) : MethodBridge {

companion object {
private const val notifySubscriptionLapsedErrorCode =
"usercentrics_flutter_notifySubscriptionLapsed_error"
}

override val name: String
get() = "notifySubscriptionLapsed"

override fun invoke(call: FlutterMethodCall, result: FlutterResult) {
assert(name == call.method)
usercentrics.instance.notifySubscriptionLapsed(
onSuccess = {
result.success(null)
},
onError = {
result.error(
notifySubscriptionLapsedErrorCode,
it.message,
it
)
},
)
}
}
11 changes: 11 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,17 @@ class HomePageState extends State<HomePage> {
),
child: const Text("GPP Testing"),
),
ElevatedButton(
onPressed: isSdkReady
? () async {
await Usercentrics.notifySubscriptionLapsed();
setState(() {
_statusMessage = 'notifySubscriptionLapsed() called';
});
}
: null,
child: const Text("Notify Subscription Lapsed"),
),
],
),
),
Expand Down
5 changes: 5 additions & 0 deletions example/test/fake_usercentrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -201,4 +201,9 @@ class FakeUsercentrics extends UsercentricsPlatform {
Future<void> notifySubscribeSuccess() {
throw UnimplementedError();
}

@override
Future<void> notifySubscriptionLapsed() {
throw UnimplementedError();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Flutter
import Foundation

struct NotifySubscriptionLapsedBridge : MethodBridge {

let name: String = "notifySubscriptionLapsed"
let usercentrics: UsercentricsProxyProtocol

func invoke(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
assert(call.method == name)

usercentrics.shared.notifySubscriptionLapsed(onSuccess: {
result(nil)
}, onError: { error in
result(FlutterError(code: "usercentrics_flutter_notifySubscriptionLapsed_error",
message: error.localizedDescription,
details: nil))
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ public class UsercentricsPlugin: NSObject, FlutterPlugin {
SetGPPConsentBridge(usercentrics: usercentrics),
GetDpsMetadataBridge(usercentrics: usercentrics),
NotifyLoginSuccessBridge(usercentrics: usercentrics),
NotifySubscribeSuccessBridge(usercentrics: usercentrics)
NotifySubscribeSuccessBridge(usercentrics: usercentrics),
NotifySubscriptionLapsedBridge(usercentrics: usercentrics)
]
return bridges.reduce([String : MethodBridge]()) { dict, value in
var dict = dict
Expand Down
1 change: 1 addition & 0 deletions lib/src/internal/bridge/bridge.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ export 'set_gpp_consent_bridge.dart';
export 'get_dps_metadata_bridge.dart';
export 'notify_login_success_bridge.dart';
export 'notify_subscribe_success_bridge.dart';
export 'notify_subscription_lapsed_bridge.dart';
19 changes: 19 additions & 0 deletions lib/src/internal/bridge/notify_subscription_lapsed_bridge.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:flutter/services.dart';

abstract class NotifySubscriptionLapsedBridge {
const NotifySubscriptionLapsedBridge();

Future<void> invoke({required MethodChannel channel});
}

class MethodChannelNotifySubscriptionLapsed
extends NotifySubscriptionLapsedBridge {
const MethodChannelNotifySubscriptionLapsed();

static const String _name = 'notifySubscriptionLapsed';

@override
Future<void> invoke({required MethodChannel channel}) async {
await channel.invokeMethod(_name);
}
}
11 changes: 10 additions & 1 deletion lib/src/internal/platform/method_channel_usercentrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ class MethodChannelUsercentrics extends UsercentricsPlatform {
this.getDpsMetadataBridge = const MethodChannelGetDpsMetadata(),
this.notifyLoginSuccessBridge = const MethodChannelNotifyLoginSuccess(),
this.notifySubscribeSuccessBridge =
const MethodChannelNotifySubscribeSuccess()});
const MethodChannelNotifySubscribeSuccess(),
this.notifySubscriptionLapsedBridge =
const MethodChannelNotifySubscriptionLapsed()});

static const MethodChannel _channel = MethodChannel('usercentrics');
static const EventChannel _gppSectionChangeEventChannel =
Expand Down Expand Up @@ -82,6 +84,7 @@ class MethodChannelUsercentrics extends UsercentricsPlatform {
final GetDpsMetadataBridge getDpsMetadataBridge;
final NotifyLoginSuccessBridge notifyLoginSuccessBridge;
final NotifySubscribeSuccessBridge notifySubscribeSuccessBridge;
final NotifySubscriptionLapsedBridge notifySubscriptionLapsedBridge;

@visibleForTesting
Completer<Object?>? isReadyCompleter;
Expand Down Expand Up @@ -436,4 +439,10 @@ class MethodChannelUsercentrics extends UsercentricsPlatform {
await _ensureIsReady();
await notifySubscribeSuccessBridge.invoke(channel: _channel);
}

@override
Future<void> notifySubscriptionLapsed() async {
await _ensureIsReady();
await notifySubscriptionLapsedBridge.invoke(channel: _channel);
}
}
6 changes: 6 additions & 0 deletions lib/src/platform/usercentrics_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -136,4 +136,10 @@ abstract class UsercentricsPlatform {

/// Clears stored TCF consent data after a successful Consent-or-Pay subscription.
Future<void> notifySubscribeSuccess();

/// Notifies the SDK that the host app's user is no longer an active Consent-or-Pay
/// subscriber (e.g. their subscription lapsed or was cancelled). Resets the subscriber
/// flag and clears TCF consent storage, so the user is presented a fresh consent banner
/// next time, exactly as a new user would see it.
Future<void> notifySubscriptionLapsed();
}
7 changes: 7 additions & 0 deletions lib/src/usercentrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,11 @@ class Usercentrics {
/// Clears stored TCF consent data after a successful Consent-or-Pay subscription.
static Future<void> notifySubscribeSuccess() =>
_delegate.notifySubscribeSuccess();

/// Notifies the SDK that the host app's user is no longer an active Consent-or-Pay
/// subscriber (e.g. their subscription lapsed or was cancelled). Resets the subscriber
/// flag so the host app can re-surface the Consent-or-Pay banner; does not alter any
/// existing consent data, which remains accurate.
static Future<void> notifySubscriptionLapsed() =>
_delegate.notifySubscriptionLapsed();
}
15 changes: 15 additions & 0 deletions test/internal/bridge/fake_notify_subscription_lapsed_bridge.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import 'package:flutter/src/services/platform_channel.dart';
import 'package:usercentrics_sdk/src/internal/bridge/notify_subscription_lapsed_bridge.dart';

class FakeNotifySubscriptionLapsedBridge
extends NotifySubscriptionLapsedBridge {
var invokeCount = 0;
MethodChannel? invokeChannelArgument;

@override
Future<void> invoke({required MethodChannel channel}) {
invokeCount++;
invokeChannelArgument = channel;
return Future.value(null);
}
}
37 changes: 37 additions & 0 deletions test/internal/platform/method_channel_usercentrics_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import '../bridge/fake_restore_user_session_bridge.dart';
import '../bridge/fake_clear_user_session_bridge.dart';
import '../bridge/fake_show_first_layer_bridge.dart';
import '../bridge/fake_show_second_layer_bridge.dart';
import '../bridge/fake_notify_subscription_lapsed_bridge.dart';
import '../bridge/get_cmp_data_bridge_test.dart';

void main() {
Expand Down Expand Up @@ -530,4 +531,40 @@ void main() {
);
});
});

group('notifySubscriptionLapsed', () {
test('default', () {
final instance = MethodChannelUsercentrics();
expect(instance.notifySubscriptionLapsedBridge,
const TypeMatcher<MethodChannelNotifySubscriptionLapsed>());
});

test('success', () async {
final notifySubscriptionLapsedBridge =
FakeNotifySubscriptionLapsedBridge();

final instance = MethodChannelUsercentrics(
notifySubscriptionLapsedBridge: notifySubscriptionLapsedBridge,
);

instance.isReadyCompleter = Completer();
instance.isReadyCompleter?.complete();

await instance.notifySubscriptionLapsed();

expect(notifySubscriptionLapsedBridge.invokeCount, 1);
expect(notifySubscriptionLapsedBridge.invokeChannelArgument?.name,
"usercentrics");
});

test('when it is not ready', () {
final instance = MethodChannelUsercentrics();
instance.isReadyCompleter = null;

expect(
() => instance.notifySubscriptionLapsed(),
throwsA(const TypeMatcher<NotInitializedException>()),
);
});
});
}
16 changes: 10 additions & 6 deletions test/platform/fake_usercentrics_platform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -420,14 +420,10 @@ class FakeUsercentricsPlatform extends UsercentricsPlatform {
}

@override
Stream<String?> get onLoginClicked {
return const Stream.empty();
}
Stream<String?> get onLoginClicked => const Stream.empty();

@override
Stream<String?> get onSubscribeClicked {
return const Stream.empty();
}
Stream<String?> get onSubscribeClicked => const Stream.empty();

var notifyLoginSuccessCount = 0;

Expand All @@ -444,4 +440,12 @@ class FakeUsercentricsPlatform extends UsercentricsPlatform {
notifySubscribeSuccessCount++;
return Future.value(null);
}

var notifySubscriptionLapsedCount = 0;

@override
Future<void> notifySubscriptionLapsed() {
notifySubscriptionLapsedCount++;
return Future.value(null);
}
}
Loading