securiti_consent_sdk 1.132.0
securiti_consent_sdk: ^1.132.0 copied to clipboard
A Flutter plugin for managing user consent preferences and compliance with privacy regulations. Integrates with Securiti's Consent Management Platform.
example/lib/main.dart
import 'package:securiti_consent_sdk/cmp_sdk_options.dart';
import 'package:securiti_consent_sdk/models/cmp_sdk_logger_level.dart';
import 'package:securiti_consent_sdk/models/consent_status.dart';
import 'package:securiti_consent_sdk/models/post_consents_request.dart';
import 'package:securiti_consent_sdk/models/app_permission.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'dart:developer' as developer;
import 'dart:io' show Platform;
import 'package:flutter/services.dart';
import 'package:securiti_consent_sdk/consent_sdk_plugin.dart';
import 'package:app_settings/app_settings.dart';
import 'permission_service.dart';
// Global navigation key for dialogs
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// Dialog service to safely show dialogs from anywhere
class DialogService {
static Future<T?> showAlertDialog<T>({
required String title,
required String message,
String? cancelText,
String? confirmText,
}) async {
if (navigatorKey.currentContext == null) {
developer.log("ERROR: No valid context for dialog!");
return null;
}
return showDialog<T>(
context: navigatorKey.currentContext!,
builder: (context) => AlertDialog(
title: Text(title),
content: Text(message),
actions: [
if (cancelText != null)
TextButton(
onPressed: () => Navigator.pop(context, null),
child: Text(cancelText),
),
if (confirmText != null)
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text(confirmText),
),
],
),
);
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
String _latestResult = 'No method called yet';
static const EventChannel _eventChannel = EventChannel('ai.securiti.consent_sdk_plugin/isSDKReady');
final _consentSdkPlugin = ConsentSdkPlugin();
bool _isSDKReady = false;
final ScrollController _scrollController = ScrollController();
// List to store all app permissions from the SDK
List<AppPermission> _appPermissions = [];
// We no longer need these maps as we'll use the PermissionService directly
@override
void initState() {
super.initState();
initPlatformState();
String appURL = 'https://dev-intg-2.securiti.xyz/';
String cdnURL = 'https://cdn-dev-intg-2.securiti.xyz/';
String tenantID = 'd525a59e-896e-4a85-ad1a-84921e9acce0';
String appID = 'a2d3c183-0a3c-4bb9-ba3b-6b6de1949ed3';
String locationCode = 'AQ';
if (Platform.isAndroid) {
appURL = 'https://dev-intg-2.securiti.xyz';
cdnURL = 'https://cdn-dev-intg-2.securiti.xyz/consent';
appID = '175f4dbd-ba1c-4821-9792-d5cc29237db2';
locationCode = 'PK';
}
CmpSDKOptions options = CmpSDKOptions(
appURL: appURL,
cdnURL: cdnURL,
tenantID: tenantID,
appID: appID,
testingMode: true,
loggerLevel: CmpSDKLoggerLevel.debug,
consentsCheckInterval: 60,
subjectId: 'flutterSubject',
languageCode: 'en',
locationCode: locationCode,
);
_consentSdkPlugin.setupSDK(options.toMap());
_eventChannel.receiveBroadcastStream().listen((event) {
setState(() {
_isSDKReady = event as bool;
if (_isSDKReady) {
_consentSdkPlugin.presentConsentBanner();
// Fetch permissions when SDK is ready
_loadAppPermissions();
}
});
});
}
// Load app permissions from the SDK
Future<void> _loadAppPermissions() async {
try {
final permissions = await _consentSdkPlugin.getPermissions();
setState(() {
_appPermissions = permissions;
});
developer.log("Loaded ${permissions.length} app permissions");
} catch (e) {
developer.log("Error loading app permissions: $e");
}
}
@override
void dispose() {
_scrollController.dispose();
super.dispose();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try {
platformVersion =
await _consentSdkPlugin.getPlatformVersion() ?? 'Unknown platform version';
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_platformVersion = platformVersion;
});
}
// Convert any Dart object to a JSON-formatted string efficiently
String _formatJsonForDisplay(dynamic obj, {int depth = 0, int maxDepth = 3}) {
// Limit recursion depth for performance
if (depth > maxDepth) {
return obj.toString();
}
String indent = ' ' * depth;
String childIndent = ' ' * (depth + 1);
if (obj == null) {
return 'null';
} else if (obj is Map) {
if (obj.isEmpty) return '{}';
List<String> pairs = [];
obj.forEach((key, value) {
String formattedValue = _formatJsonForDisplay(value, depth: depth + 1, maxDepth: maxDepth);
pairs.add('$childIndent"$key": $formattedValue');
});
return '{\n${pairs.join(',\n')}\n$indent}';
} else if (obj is List) {
if (obj.isEmpty) return '[]';
List<String> items = [];
for (var item in obj) {
items.add('$childIndent${_formatJsonForDisplay(item, depth: depth + 1, maxDepth: maxDepth)}');
}
return '[\n${items.join(',\n')}\n$indent]';
} else if (obj is String) {
// Escape quotes and use proper JSON string formatting
return '"${obj.replaceAll('"', '\\"')}"';
} else if (obj is num || obj is bool) {
// Numbers and booleans can be represented directly
return obj.toString();
} else {
// Try to use toJson if available, or default to toString()
try {
if (obj is dynamic && obj.toJson != null) {
return _formatJsonForDisplay(obj.toJson(), depth: depth, maxDepth: maxDepth);
}
} catch (_) {}
// Last resort
return '"${obj.toString().replaceAll('"', '\\"')}"';
}
}
void _updateResult(String methodName, dynamic result) {
// If it's a list, split it into smaller chunks for displaying
if (result is List && result.length > 0) {
// Special handling for complex collections
List<Map<String, dynamic>> formattedItems = [];
for (var i = 0; i < result.length; i++) {
var item = result[i];
// Create a simplified format with special handling for models
if (item is dynamic && item.toJson != null) {
try {
formattedItems.add(item.toJson());
continue;
} catch (_) {}
}
if (item is Map) {
formattedItems.add(Map<String, dynamic>.from(item));
} else {
// Wrap non-map items in a simple container
formattedItems.add({'value': item.toString()});
}
}
// Apply JSON formatting for the entire list
final jsonOutput = _formatJsonForDisplay(formattedItems);
setState(() {
_latestResult = "$methodName result: (${result.length} items)\n$jsonOutput";
});
}
// If result has toJson method, use that
else if (result != null && result is dynamic) {
try {
if (result.toJson != null) {
final jsonOutput = _formatJsonForDisplay(result.toJson());
setState(() {
_latestResult = "$methodName result:\n$jsonOutput";
});
return;
}
} catch (_) {}
// Fall back to generic JSON formatter
final jsonOutput = _formatJsonForDisplay(result);
setState(() {
_latestResult = "$methodName result:\n$jsonOutput";
});
}
else {
// For null or simple types
setState(() {
_latestResult = "$methodName result:\n${result ?? 'null'}";
});
}
// No need to log the entire output which can be very large
developer.log("$methodName executed successfully");
}
// Request a permission and handle the result using our custom PermissionService
Future<void> _requestPermission(String permissionId) async {
try {
// First, check the current status of the permission
PermissionStatus status = await PermissionService.checkPermissionStatus(permissionId);
developer.log("Permission $permissionId status: $status");
// Special handling for Media Library permission on iOS
if (Platform.isIOS && permissionId == 'NSAppleMusicUsageDescription') {
_updateResult('requestPermission', 'iOS: Handling Media Library permission (status: $status)');
// If status is not "notDetermined", go directly to settings
if (status != PermissionStatus.notDetermined) {
developer.log("Media Library permission status is not 'notDetermined', going to settings");
final shouldGoToSettings = await DialogService.showAlertDialog<bool>(
title: 'Media Library Permission',
message: 'Media Library access requires manual enabling in device settings. Would you like to open settings now?',
cancelText: 'Cancel',
confirmText: 'Open Settings',
);
if (shouldGoToSettings == true) {
await _openAppSettings();
}
return;
}
// If status is "notDetermined", try requesting the permission
PermissionStatus result = await PermissionService.requestPermission(permissionId);
developer.log("iOS Media Library permission request result: $result");
if (result == PermissionStatus.granted) {
_updateResult('requestPermission', 'Media Library permission was granted');
} else {
_updateResult('requestPermission', 'Media Library permission was not granted (result: $result)');
// Media Library permission on iOS often requires going to settings
final shouldGoToSettings = await DialogService.showAlertDialog<bool>(
title: 'Media Library Permission',
message: 'Media Library access requires manual enabling in device settings. Would you like to open settings now?',
cancelText: 'Cancel',
confirmText: 'Open Settings',
);
if (shouldGoToSettings == true) {
await _openAppSettings();
}
}
return;
}
// For Android, always go directly to settings
if (Platform.isAndroid) {
_updateResult('requestPermission', 'Android: Redirecting to settings for permission: $permissionId (status: $status)');
final shouldGoToSettings = await DialogService.showAlertDialog<bool>(
title: 'Permission Required',
message: 'Please enable ${PermissionService.getPermissionName(permissionId)} permission in your device settings.',
cancelText: 'Cancel',
confirmText: 'Open Settings',
);
if (shouldGoToSettings == true) {
await _openAppSettings();
}
return;
}
// iOS (for permissions other than Media Library) - handle based on permission status
if (status == PermissionStatus.granted) {
// Already granted
_updateResult('requestPermission', 'Permission $permissionId is already granted');
final shouldGoToSettings = await DialogService.showAlertDialog<bool>(
title: 'Permission Granted',
message: 'This permission is already granted. Would you like to go to settings anyway?',
cancelText: 'No',
confirmText: 'Yes',
);
if (shouldGoToSettings == true) {
await _openAppSettings();
}
}
else if (status == PermissionStatus.notDetermined || status == PermissionStatus.denied) {
// Request permission
_updateResult('requestPermission', 'Requesting system permission: $permissionId (status: $status)');
PermissionStatus result = await PermissionService.requestPermission(permissionId);
developer.log("Permission request result: $result");
if (result == PermissionStatus.granted) {
_updateResult('requestPermission', 'Permission $permissionId was granted');
} else {
_updateResult('requestPermission', 'Permission $permissionId was not granted (result: $result)');
// If permanently denied, offer to go to settings
if (result == PermissionStatus.permanentlyDenied || result == PermissionStatus.restricted) {
final shouldGoToSettings = await DialogService.showAlertDialog<bool>(
title: 'Permission Required',
message: 'This permission was denied. You need to enable it manually in Settings.',
cancelText: 'Cancel',
confirmText: 'Open Settings',
);
if (shouldGoToSettings == true) {
await _openAppSettings();
}
}
}
}
else if (status == PermissionStatus.permanentlyDenied || status == PermissionStatus.restricted) {
// Need to go to settings
_updateResult('requestPermission', 'Permission $permissionId needs to be enabled in settings');
final shouldGoToSettings = await DialogService.showAlertDialog<bool>(
title: 'Permission Required',
message: 'This permission needs to be enabled manually in Settings.',
cancelText: 'Cancel',
confirmText: 'Open Settings',
);
if (shouldGoToSettings == true) {
await _openAppSettings();
}
}
} catch (e) {
_updateResult('requestPermission', 'Error in permission request: $e');
}
}
// Open app settings page
Future<void> _openAppSettings() async {
try {
if (Platform.isAndroid) {
// For Android, use AppSettings.openAppSettings() without type parameter
await AppSettings.openAppSettings();
} else {
// For iOS, try our custom implementation first
bool opened = await PermissionService.openAppSettings();
// Fall back to app_settings plugin if needed
if (!opened) {
await AppSettings.openAppSettings();
}
}
_updateResult('openAppSettings', 'Opened app settings');
} catch (e) {
_updateResult('openAppSettings', 'Error opening app settings: $e');
// If something goes wrong, try the most direct approach as a last resort
if (Platform.isAndroid) {
try {
// Try our direct permission channel as a fallback
await PermissionService.openAppSettings();
} catch (fallbackError) {
developer.log("Fallback settings approach also failed: $fallbackError");
}
}
}
}
Future<void> _getBannerConfig() async {
try {
final config = await _consentSdkPlugin.getBannerConfig();
developer.log("getBannerConfig result type: ${config.runtimeType}");
if (config == null) {
_updateResult('getBannerConfig', 'null - No banner config available');
return;
}
// Use the complete BannerConfig model with toJson
_updateResult('getBannerConfig', config);
} catch (e) {
_updateResult('getBannerConfig', 'Error: $e');
}
}
Future<void> _getConsentByPurposeId() async {
try {
// First, get the list of purposes to find a valid purposeId
final purposes = await _consentSdkPlugin.getPurposes();
if (purposes.isEmpty) {
_updateResult('getConsentByPurposeId', 'No purposes available to check consent');
return;
}
// Get the first purpose ID
final purposeId = purposes.first.purposeId;
final purposeName = purposes.first.purposeName?['en'] ?? 'Unknown';
developer.log("Getting consent for purpose ID: $purposeId");
final status = await _consentSdkPlugin.getConsent(purposeId ?? 1);
developer.log("getConsentByPurposeId result type: ${status.runtimeType}");
// Format result with full purpose details
final result = {
'purpose_id': purposeId,
'purpose_name': purposeName,
'consent_status': status.value,
'enum_value': status.toString(),
'purpose_details': purposes.first.toJson(),
};
_updateResult('getConsentByPurposeId', result);
} catch (e) {
_updateResult('getConsentByPurposeId', 'Error: $e');
}
}
Future<void> _getConsentByPermissionId(String permissionId) async {
try {
// If we have a specific permissionId, use it directly
if (permissionId.isNotEmpty) {
final status = await _consentSdkPlugin.getConsent(permissionId);
// Find the permission in our list to get more details if possible
AppPermission? permission;
try {
permission = _appPermissions.firstWhere(
(p) => p.permissionId == permissionId
);
} catch (e) {
permission = null;
}
final permissionName = permission?.name ?? 'Unknown';
// Format result with permission details
final result = {
'permission_id': permissionId,
'permission_name': permissionName,
'consent_status': status.value,
'enum_value': status.toString(),
};
_updateResult('getConsentByPermissionId', result);
return;
}
// If no specific permission was provided, use the first one from the list
if (_appPermissions.isNotEmpty) {
final permission = _appPermissions.first;
final permissionId = permission.permissionId;
if (permissionId != null) {
final status = await _consentSdkPlugin.getConsent(permissionId);
// Format result with permission details
final result = {
'permission_id': permissionId,
'permission_name': permission.name ?? 'Unknown',
'consent_status': status.value,
'enum_value': status.toString(),
'permission_details': permission.toJson(),
};
_updateResult('getConsentByPermissionId', result);
return;
}
}
// If we get here, we need to fetch the permissions first
final permissions = await _consentSdkPlugin.getPermissions();
if (permissions.isEmpty) {
_updateResult('getConsentByPermissionId', 'No permissions available to check consent');
return;
}
// Get the first permission ID or use a standard permission
final permission = permissions.first;
final id = permission.permissionId ?? (Platform.isIOS ? "NSCameraUsageDescription" : "android.permission.CAMERA");
final permissionName = permission.name ?? 'Unknown';
final status = await _consentSdkPlugin.getConsent(id);
// Format result with permission details
final result = {
'permission_id': id,
'permission_name': permissionName,
'consent_status': status.value,
'enum_value': status.toString(),
'permission_details': permission.toJson(),
};
_updateResult('getConsentByPermissionId', result);
} catch (e) {
_updateResult('getConsentByPermissionId', 'Error: $e');
}
}
Future<void> _getPermissions() async {
try {
final permissions = await _consentSdkPlugin.getPermissions();
// Update the cached permissions list
setState(() {
_appPermissions = permissions;
});
// Pass the full permissions list directly
_updateResult('getPermissions', permissions);
} catch (e) {
_updateResult('getPermissions', 'Error: $e');
}
}
Future<void> _getPurposes() async {
try {
final purposes = await _consentSdkPlugin.getPurposes();
developer.log("getPurposes result type: ${purposes.runtimeType}, isEmpty: ${purposes.isEmpty}");
if (!purposes.isEmpty) {
developer.log("First purpose type: ${purposes.first.runtimeType}");
}
// Pass the full purposes list directly
_updateResult('getPurposes', purposes);
} catch (e) {
_updateResult('getPurposes', 'Error: $e');
}
}
Future<void> _getSdksInPurpose() async {
try {
// First, get purposes to find a valid ID
final purposes = await _consentSdkPlugin.getPurposes();
if (purposes.isEmpty) {
_updateResult('getSdksInPurpose', 'No purposes available to check SDKs');
return;
}
// Get the first purpose ID or use default 1
final purposeId = purposes.first.purposeId ?? 1;
developer.log("Getting SDKs for purpose ID: $purposeId");
final sdks = await _consentSdkPlugin.getSdksInPurpose(purposeId);
// Format the result with full SDK details
final formattedResult = {
'purpose_id': purposeId,
'purpose_name': purposes.first.purposeName?['en'] ?? 'Unknown',
'sdks_count': sdks.length,
'sdks': sdks,
};
_updateResult('getSdksInPurpose', formattedResult);
} catch (e) {
_updateResult('getSdksInPurpose', 'Error: $e');
}
}
Future<void> _getSettingsPrompt() async {
try {
final settingsPrompt = await _consentSdkPlugin.getSettingsPrompt();
if (settingsPrompt == null) {
_updateResult('getSettingsPrompt', 'null - No settings prompt available');
return;
}
// Settings prompt will be automatically formatted through toJson
_updateResult('getSettingsPrompt', settingsPrompt);
} catch (e) {
_updateResult('getSettingsPrompt', 'Error: $e');
}
}
Future<void> _setConsentForPurpose() async {
try {
// First, get the list of purposes to find a valid purposeId
final purposes = await _consentSdkPlugin.getPurposes();
if (purposes.isEmpty) {
_updateResult('setConsentForPurpose', 'No purposes available to set consent');
return;
}
// Get the first purpose ID
final purposeId = purposes.first.purposeId;
developer.log("Setting consent for purpose ID: $purposeId");
await _consentSdkPlugin.setConsent(purposeId ?? 1, ConsentStatus.granted);
_updateResult('setConsentForPurpose', 'Consent set to GRANTED for purpose ID: $purposeId');
} catch (e) {
_updateResult('setConsentForPurpose', 'Error: $e');
}
}
Future<void> _setConsentForPermission(String permissionId) async {
try {
// Set consent for the permission in the SDK
await _consentSdkPlugin.setConsent(permissionId, ConsentStatus.granted);
_updateResult('setConsentForPermission', 'Consent set to GRANTED for permission ID: $permissionId');
// Request the actual OS permission
await _requestPermission(permissionId);
} catch (e) {
_updateResult('setConsentForPermission', 'Error: $e');
}
}
Future<void> _resetConsents() async {
try {
await _consentSdkPlugin.resetConsents();
_updateResult('resetConsents', 'Consents reset successfully');
} catch (e) {
_updateResult('resetConsents', 'Error: $e');
}
}
Future<void> _getAllConsents() async {
try {
// Get all purposes and their consent statuses
final purposes = await _consentSdkPlugin.getPurposes();
// Collect full purpose data with consent status
List<Map<String, dynamic>> purposeData = [];
// Limit to first 5 for performance
int count = purposes.length > 5 ? 5 : purposes.length;
for (var i = 0; i < count; i++) {
var purpose = purposes[i];
if (purpose.purposeId != null) {
final consent = await _consentSdkPlugin.getConsent(purpose.purposeId!);
final purposeName = purpose.purposeName?['en'] ?? 'Unknown';
purposeData.add({
'purpose_id': purpose.purposeId,
'name': purposeName,
'consent_status': consent.value,
'purpose_data': purpose.toJson() // Include full purpose data
});
}
}
// Get all permissions and their consent statuses
final permissions = await _consentSdkPlugin.getPermissions();
List<Map<String, dynamic>> permissionData = [];
// Limit to first 5 for performance
count = permissions.length > 5 ? 5 : permissions.length;
for (var i = 0; i < count; i++) {
var permission = permissions[i];
if (permission.permissionId != null) {
final consent = await _consentSdkPlugin.getConsent(permission.permissionId!);
final permissionName = permission.name ?? 'Unknown';
permissionData.add({
'permission_id': permission.permissionId,
'name': permissionName,
'consent_status': consent.value,
'permission_data': permission.toJson() // Include full permission data
});
}
}
// Format result as JSON with all available details
final result = {
'total_purposes': purposes.length,
'total_permissions': permissions.length,
'purposes': purposeData,
'permissions': permissionData,
};
_updateResult('getAllConsents', result);
} catch (e) {
_updateResult('getAllConsents', 'Error: $e');
}
}
Widget _buildMethodButton(String label, VoidCallback onPressed) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: ElevatedButton(
onPressed: _isSDKReady ? onPressed : null,
child: Text(label),
),
);
}
// Build permission list UI from AppPermissions
Widget _buildPermissionsList() {
if (_appPermissions.isEmpty) {
return const Center(
child: Text('No permissions available yet. SDK may still be loading.'),
);
}
return ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: _appPermissions.length,
itemBuilder: (context, index) {
final permission = _appPermissions[index];
final permissionId = permission.permissionId ?? 'Unknown';
final permissionName = permission.name ?? 'Unnamed Permission';
// Extract description for the current language or use English as fallback
String? description;
if (permission.description != null) {
description = permission.description!['en'] ?? // Try English first
permission.description!.values.first; // Fallback to any language
}
return Card(
margin: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
child: ExpansionTile(
title: Text(permissionName),
subtitle: Text('ID: $permissionId'),
children: [
if (description != null)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text('Description: $description'),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: _isSDKReady
? () => _getConsentByPermissionId(permissionId)
: null,
child: const Text('Check Consent'),
),
ElevatedButton(
onPressed: _isSDKReady
? () => _requestPermission(permissionId)
: null,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
child: const Text('Request Permission'),
),
],
),
),
],
),
);
},
);
}
Widget _buildSDKMethodsList() {
return Expanded(
child: SingleChildScrollView(
controller: _scrollController,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// UI Methods
const Padding(
padding: EdgeInsets.only(top: 8, bottom: 8),
child: Text('UI Methods', style: TextStyle(fontWeight: FontWeight.bold)),
),
_buildMethodButton('Present Consent Banner', () {
_consentSdkPlugin.presentConsentBanner();
_updateResult('presentConsentBanner', 'Banner presented');
}),
_buildMethodButton('Open Preference Center', () {
_consentSdkPlugin.presentPreferenceCenter();
_updateResult('presentPreferenceCenter', 'Preference center opened');
}),
// Permissions section (dynamically built from SDK data)
const Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Text('App Permissions', style: TextStyle(fontWeight: FontWeight.bold)),
),
_buildMethodButton('Refresh Permissions List', _getPermissions),
_buildMethodButton('Open App Settings', _openAppSettings),
_buildPermissionsList(),
// Get Methods
const Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Text('Get Data Methods', style: TextStyle(fontWeight: FontWeight.bold)),
),
_buildMethodButton('Get Banner Config', _getBannerConfig),
_buildMethodButton('Get Purposes', _getPurposes),
_buildMethodButton('Get SDKs in Purpose', _getSdksInPurpose),
_buildMethodButton('Get Settings Prompt', _getSettingsPrompt),
// Consent Management Methods
const Padding(
padding: EdgeInsets.only(top: 16, bottom: 8),
child: Text('Consent Management', style: TextStyle(fontWeight: FontWeight.bold)),
),
_buildMethodButton('Get Consent by Purpose ID', _getConsentByPurposeId),
_buildMethodButton('Get All Consents', _getAllConsents),
_buildMethodButton('Set Consent for Purpose', _setConsentForPurpose),
_buildMethodButton('Reset All Consents', _resetConsents),
],
),
),
),
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: navigatorKey, // Use the global navigator key for dialogs
home: Scaffold(
appBar: AppBar(
title: const Text('Consent SDK Example'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Securiti\'s SDK is ${_isSDKReady ? "ready" : "not ready"}',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: _isSDKReady ? Colors.green : Colors.red,
),
),
const SizedBox(height: 10),
Text('Platform: $_platformVersion'),
Text('Permissions loaded: ${_appPermissions.length}'),
const Divider(),
],
),
),
// List of SDK methods
_buildSDKMethodsList(),
// Results display with performance optimizations
Container(
height: 300, // Double the height to show more content
margin: const EdgeInsets.all(16.0),
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
// Use a ListView builder for optimal performance with large text
child: Scrollbar(
child: ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return SelectableText(
_latestResult,
style: const TextStyle(
fontFamily: 'monospace',
fontSize: 11.0, // Smaller font for better performance
height: 1.2, // Tighter line height
),
);
},
),
),
),
],
),
),
);
}
}