DVConsentPolicy.fromConfig constructor

DVConsentPolicy.fromConfig(
  1. Map<String, Object?> consent
)

Reads dartvel.analytics.consent from pubspec.yaml.

The version is required. Without one a changed set of categories could never ask again, and every earlier answer would stand for purposes nobody was asked about.

Read strictly. A key it does not know is refused rather than skipped: tracknig: true skipped is a tracking category that never shows the App Tracking Transparency prompt, and required: "yes" read as false is a category the application needs defaulting to denied. Neither throws anywhere later, so the configuration is the only place to catch them.

Implementation

factory DVConsentPolicy.fromConfig(Map<String, Object?> consent) {
  for (final String key in consent.keys) {
    if (!_consentKeys.contains(key)) {
      throw ArgumentError.value(key, 'consent',
          'is not a consent setting; accepted: ${_consentKeys.join(', ')}');
    }
  }
  final Object? version = consent['version'];
  if (version == null || '$version'.trim().isEmpty) {
    throw ArgumentError.value(consent, 'consent',
        'declares no version; a changed policy could never ask again');
  }
  final Object? raw = consent['categories'];
  if (raw is! Map) {
    throw ArgumentError.value(raw, 'categories', 'must be a map');
  }
  final List<DVConsentDeclaration> declarations = <DVConsentDeclaration>[];
  for (final MapEntry<Object?, Object?> entry in raw.entries) {
    final Object? body = entry.value;
    if (body != null && body is! Map) {
      throw ArgumentError.value(body, '${entry.key}',
          'must be a map of ${_categoryKeys.join(', ')}, such as '
              '{ default: denied }');
    }
    final Map<Object?, Object?> fields =
        body is Map ? body : const <Object?, Object?>{};
    for (final Object? key in fields.keys) {
      if (!_categoryKeys.contains(key)) {
        throw ArgumentError.value(key, '${entry.key}',
            'is not a category setting; accepted: ${_categoryKeys.join(', ')}');
      }
    }
    bool flag(String key) {
      final Object? value = fields[key];
      if (value == null) return false;
      if (value is bool) return value;
      throw ArgumentError.value(
          value, '${entry.key}.$key', 'must be true or false');
    }

    final bool required = flag('required');
    final bool tracking = flag('tracking');
    final Object? def = fields['default'];
    final bool? granted = switch (def) {
      null => null,
      'denied' => false,
      'granted' => true,
      _ => throw ArgumentError.value(def, '${entry.key}.default',
          'must be granted or denied'),
    };
    declarations.add(DVConsentDeclaration(
      DVConsentCategory('${entry.key}'),
      required: required,
      defaultGranted: granted,
      tracking: tracking,
    ));
  }
  return DVConsentPolicy(version: '$version', categories: declarations);
}