securiti_consent_sdk 1.132.0 copy "securiti_consent_sdk: ^1.132.0" to clipboard
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
                      ),
                    );
                  },
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
140
points
138
downloads

Publisher

verified publishersecuriti.ai

Weekly Downloads

A Flutter plugin for managing user consent preferences and compliance with privacy regulations. Integrates with Securiti's Consent Management Platform.

Repository
View/report issues

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on securiti_consent_sdk