From b89ecd325f7dc9346903c91c2b6f7a464ffba849 Mon Sep 17 00:00:00 2001 From: "bruno.silva" Date: Thu, 19 Feb 2026 11:01:18 +0000 Subject: [PATCH 1/2] feat(MSDK-3261): add storage info and sdks field to ConsentDisclosureObject - Add ConsentDisclosureSDK model to Flutter - Update ConsentDisclosureObject to include sdks field - Update ConsentDisclosureObjectSerializer to handle new dict format {disclosures, sdks} - Update ConsentDisclosureSerializer (iOS/Android) to serialize sdks field - Update mocks to reflect new data structure Co-authored-by: Cursor --- .../serializer/ConsentDisclosureSerializer.kt | 13 ++++- .../sdk/flutter/mock/GetCMPDataMock.kt | 28 +++++----- .../ConsentDisclosureSerializer.swift | 5 +- .../consent_disclosure_object_serializer.dart | 33 +++++++++++- lib/src/model/consent_disclosure.dart | 29 +++++++++-- .../bridge/get_cmp_data_bridge_test.mock.dart | 51 ++++++++++--------- 6 files changed, 117 insertions(+), 42 deletions(-) diff --git a/android/src/main/kotlin/com/usercentrics/sdk/flutter/serializer/ConsentDisclosureSerializer.kt b/android/src/main/kotlin/com/usercentrics/sdk/flutter/serializer/ConsentDisclosureSerializer.kt index f45dbf3e..c2e8a4ad 100644 --- a/android/src/main/kotlin/com/usercentrics/sdk/flutter/serializer/ConsentDisclosureSerializer.kt +++ b/android/src/main/kotlin/com/usercentrics/sdk/flutter/serializer/ConsentDisclosureSerializer.kt @@ -2,12 +2,23 @@ package com.usercentrics.sdk.flutter.serializer import com.usercentrics.sdk.v2.settings.data.ConsentDisclosure import com.usercentrics.sdk.v2.settings.data.ConsentDisclosureObject +import com.usercentrics.sdk.v2.settings.data.ConsentDisclosureSDK internal fun ConsentDisclosureObject?.serializer(): Any? { if (this == null) { return null } - return disclosures.map { it.serializer() } + return mapOf( + "disclosures" to disclosures.map { it.serializer() }, + "sdks" to sdks.map { it.serializer() } + ) +} + +private fun ConsentDisclosureSDK.serializer(): Map { + return mapOf( + "name" to name, + "use" to use + ) } internal fun ConsentDisclosure.serializer(): Any { diff --git a/android/src/test/java/com/usercentrics/sdk/flutter/mock/GetCMPDataMock.kt b/android/src/test/java/com/usercentrics/sdk/flutter/mock/GetCMPDataMock.kt index b4003645..5cc38da5 100644 --- a/android/src/test/java/com/usercentrics/sdk/flutter/mock/GetCMPDataMock.kt +++ b/android/src/test/java/com/usercentrics/sdk/flutter/mock/GetCMPDataMock.kt @@ -90,7 +90,8 @@ internal object GetCMPDataMock { domain = "domain", description = "description", ) - ) + ), + sdks = listOf() ), isHidden = false, ) @@ -709,17 +710,20 @@ internal object GetCMPDataMock { "disableLegalBasis" to false, "isEssential" to false, "technologyUsed" to listOf("Cookies", "Pixel Tags"), - "deviceStorage" to listOf( - mapOf( - "identifier" to "identifier", - "type" to "APP", - "name" to "name", - "maxAgeSeconds" to 123123L, - "cookieRefresh" to true, - "purposes" to listOf(1, 2, 3), - "domain" to "domain", - "description" to "description", - ) + "deviceStorage" to mapOf( + "disclosures" to listOf( + mapOf( + "identifier" to "identifier", + "type" to "APP", + "name" to "name", + "maxAgeSeconds" to 123123L, + "cookieRefresh" to true, + "purposes" to listOf(1, 2, 3), + "domain" to "domain", + "description" to "description", + ) + ), + "sdks" to emptyList>() ), "isHidden" to false, ) diff --git a/ios/Classes/Serializer/ConsentDisclosureSerializer.swift b/ios/Classes/Serializer/ConsentDisclosureSerializer.swift index 9b5fd901..0903d6de 100644 --- a/ios/Classes/Serializer/ConsentDisclosureSerializer.swift +++ b/ios/Classes/Serializer/ConsentDisclosureSerializer.swift @@ -2,7 +2,10 @@ import Usercentrics extension ConsentDisclosureObject { func serialize() -> Any { - return self.disclosures.map { $0.serialize() } + return [ + "disclosures": self.disclosures.map { $0.serialize() }, + "sdks": self.sdks.map { ["name": $0.name, "use": $0.use] } + ] as [String: Any] } } diff --git a/lib/src/internal/serializer/consent_disclosure_object_serializer.dart b/lib/src/internal/serializer/consent_disclosure_object_serializer.dart index c42a5297..badd2a59 100644 --- a/lib/src/internal/serializer/consent_disclosure_object_serializer.dart +++ b/lib/src/internal/serializer/consent_disclosure_object_serializer.dart @@ -6,12 +6,32 @@ class ConsentDisclosureObjectSerializer { return null; } - List values = value ?? []; + // New format: { disclosures: [...], sdks: [...] } + if (value is Map) { + final disclosures = value['disclosures'] as List? ?? []; + final sdks = value['sdks'] as List? ?? []; + if (disclosures.isEmpty && sdks.isEmpty) { + return null; + } + return ConsentDisclosureObject( + disclosures: disclosures + .map( + (e) => ConsentDisclosureSerializer.deserialize(e)) + .toList(), + sdks: sdks + .map( + (e) => ConsentDisclosureSDKSerializer.deserialize(e)) + .toList(), + ); + } + + // Legacy format: array of disclosures + final values = value is List ? value : []; if (values.isEmpty) { return null; } return ConsentDisclosureObject( - disclosures: (value ?? []) + disclosures: values .map( (e) => ConsentDisclosureSerializer.deserialize(e)) .toList(), @@ -19,6 +39,15 @@ class ConsentDisclosureObjectSerializer { } } +class ConsentDisclosureSDKSerializer { + static ConsentDisclosureSDK deserialize(dynamic value) { + return ConsentDisclosureSDK( + name: value['name'] ?? '', + use: value['use'] ?? '', + ); + } +} + class ConsentDisclosureSerializer { static ConsentDisclosure deserialize(dynamic value) { return ConsentDisclosure( diff --git a/lib/src/model/consent_disclosure.dart b/lib/src/model/consent_disclosure.dart index 3e423901..2a4efa75 100644 --- a/lib/src/model/consent_disclosure.dart +++ b/lib/src/model/consent_disclosure.dart @@ -1,19 +1,42 @@ import 'package:flutter/foundation.dart'; +class ConsentDisclosureSDK { + const ConsentDisclosureSDK({required this.name, required this.use}); + + final String name; + final String use; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is ConsentDisclosureSDK && + runtimeType == other.runtimeType && + name == other.name && + use == other.use; + + @override + int get hashCode => Object.hash(name, use); +} + class ConsentDisclosureObject { - const ConsentDisclosureObject({required this.disclosures}); + const ConsentDisclosureObject({ + required this.disclosures, + this.sdks = const [], + }); final List disclosures; + final List sdks; @override bool operator ==(Object other) => identical(this, other) || other is ConsentDisclosureObject && runtimeType == other.runtimeType && - listEquals(disclosures, other.disclosures); + listEquals(disclosures, other.disclosures) && + listEquals(sdks, other.sdks); @override - int get hashCode => disclosures.hashCode; + int get hashCode => Object.hash(disclosures, sdks); } class ConsentDisclosure { diff --git a/test/internal/bridge/get_cmp_data_bridge_test.mock.dart b/test/internal/bridge/get_cmp_data_bridge_test.mock.dart index f00795a1..b24c9432 100644 --- a/test/internal/bridge/get_cmp_data_bridge_test.mock.dart +++ b/test/internal/bridge/get_cmp_data_bridge_test.mock.dart @@ -354,18 +354,21 @@ const _responseServices = [ "disableLegalBasis": false, "isEssential": false, "technologyUsed": ["Cookies", "Pixel Tags"], - "deviceStorage": [ - { - "identifier": "identifier", - "type": "APP", - "name": "name", - "maxAgeSeconds": 10, - "cookieRefresh": false, - "purposes": [1, 2, 3], - "domain": "domain", - "description": "description" - } - ], + "deviceStorage": { + "disclosures": [ + { + "identifier": "identifier", + "type": "APP", + "name": "name", + "maxAgeSeconds": 10, + "cookieRefresh": false, + "purposes": [1, 2, 3], + "domain": "domain", + "description": "description" + } + ], + "sdks": [] + }, "isHidden": false, } ]; @@ -473,17 +476,19 @@ const _expectedServices = [ disableLegalBasis: false, isEssential: false, technologyUsed: ["Cookies", "Pixel Tags"], - deviceStorage: ConsentDisclosureObject(disclosures: [ - ConsentDisclosure( - identifier: "identifier", - type: ConsentDisclosureType.app, - name: "name", - maxAgeSeconds: 10, - cookieRefresh: false, - purposes: [1, 2, 3], - domain: "domain", - description: "description") - ]), + deviceStorage: ConsentDisclosureObject( + disclosures: [ + ConsentDisclosure( + identifier: "identifier", + type: ConsentDisclosureType.app, + name: "name", + maxAgeSeconds: 10, + cookieRefresh: false, + purposes: [1, 2, 3], + domain: "domain", + description: "description") + ], + sdks: []), isHidden: false) ]; From daff16c85082ffbb1de1e50c0a9b35f31d939121 Mon Sep 17 00:00:00 2001 From: "bruno.silva" Date: Thu, 19 Feb 2026 11:16:18 +0000 Subject: [PATCH 2/2] chore(MSDK-3261): apply dart format to mock file Co-authored-by: Cursor --- .../bridge/get_cmp_data_bridge_test.mock.dart | 576 +++++++++--------- 1 file changed, 292 insertions(+), 284 deletions(-) diff --git a/test/internal/bridge/get_cmp_data_bridge_test.mock.dart b/test/internal/bridge/get_cmp_data_bridge_test.mock.dart index b24c9432..3847721e 100644 --- a/test/internal/bridge/get_cmp_data_bridge_test.mock.dart +++ b/test/internal/bridge/get_cmp_data_bridge_test.mock.dart @@ -7,11 +7,9 @@ const mockResponse = { "categories": _responseCategories, "activeVariant": "TCF", "userLocation": _responseUserLocation, - "legalBasis": _responseLegalBasis -}; -const _responseFirstLayer = { - "hideButtonDeny": false, + "legalBasis": _responseLegalBasis, }; +const _responseFirstLayer = {"hideButtonDeny": false}; const _responseSecondLayer = { "tabsCategoriesLabel": "Categories", "tabsServicesLabel": "Services", @@ -169,10 +167,10 @@ const _responseTCF2Settings = { "scope": "SERVICE", "changedPurposes": { "purposes": [1, 2, 3], - "legIntPurposes": [1, 2, 3] + "legIntPurposes": [1, 2, 3], }, "acmV2Enabled": true, - "selectedATPIds": [1, 2, 3, 4, 5] + "selectedATPIds": [1, 2, 3, 4, 5], }; const _responseCCPASettings = { "optOutNoticeLabel": "Do not sell my personal information", @@ -218,7 +216,7 @@ const _responseCustomization = { "font": { "family": "BlinkMacSystemFont,-apple-system,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,Helvetica,Arial,sans-serif", - "size": 14 + "size": 14, }, "logoUrl": "https://www.munich-startup.de/wp-content/uploads/2018/01/usercentrics-logo-4c@4x.png", @@ -252,15 +250,15 @@ const _responseSettings = { "variants": { "enabled": true, "experimentsJson": "experimentsJson", - "activateWith": "activateWith" + "activateWith": "activateWith", }, "dpsDisplayFormat": "ALL", "framework": "CPA", "publishedApps": [ - {"bundleId": "bundleId", "platform": "ANDROID"} + {"bundleId": "bundleId", "platform": "ANDROID"}, ], "renewConsentsTimestamp": 1000, - "consentWebhook": true + "consentWebhook": true, }; const _responseCategories = [ @@ -270,7 +268,7 @@ const _responseCategories = [ "description": "These technologies are required to activate the core functionality of the website.", "isEssential": true, - } + }, ]; const _responseUserLocation = { "countryCode": "PT", @@ -306,12 +304,12 @@ const _responseLabelsAria = { "usercentricsList": "usercentricsList", "vendorConsentToggle": "vendorConsentToggle", "vendorDetailedStorageInformation": "vendorDetailedStorageInformation", - "vendorLegIntToggle": "vendorLegIntToggle" + "vendorLegIntToggle": "vendorLegIntToggle", }; const _responseData = {"key1": "value1", "key2": "value2", "key3": "value3"}; const _responseLegalBasis = { "labelsAria": _responseLabelsAria, - "data": _responseData + "data": _responseData, }; const _responseServices = [ @@ -364,55 +362,59 @@ const _responseServices = [ "cookieRefresh": false, "purposes": [1, 2, 3], "domain": "domain", - "description": "description" - } + "description": "description", + }, ], - "sdks": [] + "sdks": [], }, "isHidden": false, - } + }, ]; // Expected const expectedResult = UsercentricsCMPData( - settings: _expectedSettings, - services: _expectedServices, - categories: _expectedCategories, - activeVariant: UsercentricsVariant.tcf, - userLocation: _expectedUserLocation, - legalBasis: _expectedLegalBasis); + settings: _expectedSettings, + services: _expectedServices, + categories: _expectedCategories, + activeVariant: UsercentricsVariant.tcf, + userLocation: _expectedUserLocation, + legalBasis: _expectedLegalBasis, +); const _expectedLegalBasis = LegalBasisLocalization( - labelsAria: _expectedTranslationsAriaLabels, data: _expectedData); + labelsAria: _expectedTranslationsAriaLabels, + data: _expectedData, +); const _expectedTranslationsAriaLabels = TranslationAriaLabels( - acceptAllButton: "acceptAllButton", - ccpaButton: "ccpaButton", - ccpaMoreInformation: "ccpaMoreInformation", - closeButton: "closeButton", - collapse: "collapse", - cookiePolicyButton: "cookiePolicyButton", - copyControllerId: "copyControllerId", - denyAllButton: "denyAllButton", - expand: "expand", - fullscreenButton: "fullscreenButton", - imprintButton: "imprintButton", - languageSelector: "languageSelector", - privacyButton: "privacyButton", - privacyPolicyButton: "privacyPolicyButton", - saveButton: "saveButton", - serviceInCategoryDetails: "serviceInCategoryDetails", - servicesInCategory: "servicesInCategory", - tabButton: "tabButton", - usercentricsCMPButtons: "usercentricsCMPButtons", - usercentricsCMPContent: "usercentricsCMPContent", - usercentricsCMPHeader: "usercentricsCMPHeader", - usercentricsCMPUI: "usercentricsCMPUI", - usercentricsCard: "usercentricsCard", - usercentricsList: "usercentricsList", - vendorConsentToggle: "vendorConsentToggle", - vendorDetailedStorageInformation: "vendorDetailedStorageInformation", - vendorLegIntToggle: "vendorLegIntToggle"); + acceptAllButton: "acceptAllButton", + ccpaButton: "ccpaButton", + ccpaMoreInformation: "ccpaMoreInformation", + closeButton: "closeButton", + collapse: "collapse", + cookiePolicyButton: "cookiePolicyButton", + copyControllerId: "copyControllerId", + denyAllButton: "denyAllButton", + expand: "expand", + fullscreenButton: "fullscreenButton", + imprintButton: "imprintButton", + languageSelector: "languageSelector", + privacyButton: "privacyButton", + privacyPolicyButton: "privacyPolicyButton", + saveButton: "saveButton", + serviceInCategoryDetails: "serviceInCategoryDetails", + servicesInCategory: "servicesInCategory", + tabButton: "tabButton", + usercentricsCMPButtons: "usercentricsCMPButtons", + usercentricsCMPContent: "usercentricsCMPContent", + usercentricsCMPHeader: "usercentricsCMPHeader", + usercentricsCMPUI: "usercentricsCMPUI", + usercentricsCard: "usercentricsCard", + usercentricsList: "usercentricsList", + vendorConsentToggle: "vendorConsentToggle", + vendorDetailedStorageInformation: "vendorDetailedStorageInformation", + vendorLegIntToggle: "vendorLegIntToggle", +); const Map _expectedData = { 'key1': 'value1', @@ -438,145 +440,147 @@ const _expectedUserLocation = UsercentricsLocation( ); const _expectedServices = [ UsercentricsService( - templateId: "ABC", - version: "1.2.3", - type: "predefined", - dataProcessor: "Google Ads", - dataPurposes: ["Advertising Conversion Tracking"], - processingCompany: "Google Ireland Limited, Google Building Gordon House", - nameOfProcessingCompany: "Google Ireland Limited", - addressOfProcessingCompany: "Google Building Gordon House", - descriptionOfService: "This is a conversion tracking service. ", - languagesAvailable: ["en"], - dataCollectedList: ["IP address"], - dataPurposesList: ["Analytics"], - dataRecipientsList: ["Google Ireland Limited"], - legalBasisList: ["Art. 6 para. 1 s. 1 lit. a GDPR"], - retentionPeriodList: [], - subConsents: [], - language: "en", - linkToDpa: "", - legalGround: "Art. 6 para. 1 s. 1 lit. c GDPR", - optOutUrl: "", - policyOfProcessorUrl: "https://usercentrics.com/de/datenschutzerklarung/", - categorySlug: "essential", - retentionPeriodDescription: - "The consent data (given consent and revocation of consent) are stored for three years. The data will then be deleted immediately or given to the person responsible on request in the form of a data export.", - dataProtectionOfficer: "datenschutz@usercentrics.com", - privacyPolicyURL: "https://usercentrics.com/privacy-policy/", - cookiePolicyURL: "", - locationOfProcessing: "European Union", - dataCollectedDescription: "", - thirdCountryTransfer: "Worldwide", - description: "", - cookieMaxAgeSeconds: null, - usesNonCookieAccess: null, - deviceStorageDisclosureUrl: "", - isDeactivated: false, - disableLegalBasis: false, - isEssential: false, - technologyUsed: ["Cookies", "Pixel Tags"], - deviceStorage: ConsentDisclosureObject( - disclosures: [ - ConsentDisclosure( - identifier: "identifier", - type: ConsentDisclosureType.app, - name: "name", - maxAgeSeconds: 10, - cookieRefresh: false, - purposes: [1, 2, 3], - domain: "domain", - description: "description") - ], - sdks: []), - isHidden: false) + templateId: "ABC", + version: "1.2.3", + type: "predefined", + dataProcessor: "Google Ads", + dataPurposes: ["Advertising Conversion Tracking"], + processingCompany: "Google Ireland Limited, Google Building Gordon House", + nameOfProcessingCompany: "Google Ireland Limited", + addressOfProcessingCompany: "Google Building Gordon House", + descriptionOfService: "This is a conversion tracking service. ", + languagesAvailable: ["en"], + dataCollectedList: ["IP address"], + dataPurposesList: ["Analytics"], + dataRecipientsList: ["Google Ireland Limited"], + legalBasisList: ["Art. 6 para. 1 s. 1 lit. a GDPR"], + retentionPeriodList: [], + subConsents: [], + language: "en", + linkToDpa: "", + legalGround: "Art. 6 para. 1 s. 1 lit. c GDPR", + optOutUrl: "", + policyOfProcessorUrl: "https://usercentrics.com/de/datenschutzerklarung/", + categorySlug: "essential", + retentionPeriodDescription: + "The consent data (given consent and revocation of consent) are stored for three years. The data will then be deleted immediately or given to the person responsible on request in the form of a data export.", + dataProtectionOfficer: "datenschutz@usercentrics.com", + privacyPolicyURL: "https://usercentrics.com/privacy-policy/", + cookiePolicyURL: "", + locationOfProcessing: "European Union", + dataCollectedDescription: "", + thirdCountryTransfer: "Worldwide", + description: "", + cookieMaxAgeSeconds: null, + usesNonCookieAccess: null, + deviceStorageDisclosureUrl: "", + isDeactivated: false, + disableLegalBasis: false, + isEssential: false, + technologyUsed: ["Cookies", "Pixel Tags"], + deviceStorage: ConsentDisclosureObject( + disclosures: [ + ConsentDisclosure( + identifier: "identifier", + type: ConsentDisclosureType.app, + name: "name", + maxAgeSeconds: 10, + cookieRefresh: false, + purposes: [1, 2, 3], + domain: "domain", + description: "description", + ), + ], + sdks: [], + ), + isHidden: false, + ), ]; const _expectedLabels = UsercentricsLabels( - dataPurposes: "Data Purposes", - accepted: "yes", - denied: "no", - history: "History", - btnDeny: "Deny", - technologiesUsed: "Technologies Used", - dataCollectedList: "Data Collected", - processingCompanyTitle: "Processing Company", - legalBasisList: "Legal Basis", - locationOfProcessing: "Location of Processing", - transferToThirdCountries: "Transfer to Third Countries", - optOut: "Click here to opt out from this processor across all domains", - policyOf: "Click here to read the privacy policy of the data processor", - dataCollectedInfo: - "This list represents all (personal) data that is collected by or through the use of this service.", - legalBasisInfo: - "In the following the required legal basis for the processing of data is listed.", - dataRecipientsList: "Data Recipients", - linkToDpaInfo: "Data Processing Agreement", - dataPurposesInfo: - "This list represents the purposes of the data collection and processing.", - technologiesUsedInfo: - "This list represents all technologies this service uses to collect data. Typical technologies are Cookies and Pixels that are placed in the browser.", - btnBannerReadMore: "Read more", - descriptionOfService: "Description of Service", - date: "Date", - minute: "minute", - minutes: "minutes", - hour: "hour", - hours: "hours", - day: "day", - days: "days", - month: "month", - months: "months", - year: "year", - years: "years", - categories: "Categories", - btnSave: "Save Services", - cookiePolicyInfo: - "Click here to read the cookie policy of the data processor", - imprintLinkText: "Imprint", - privacyPolicyLinkText: "Privacy Policy", - btnAcceptAll: "Accept All", - firstLayerTitle: "Privacy Settings", - historyDescription: "", - decision: "Decision", - storageInformation: "Storage Information", - maximumAgeCookieStorage: "Maximum age of cookie storage", - second: "second", - seconds: "seconds", - nonCookieStorage: "Non-cookie storage", - detailedStorageInformation: "Detailed Storage Information", - loadingStorageInformation: "Loading storage information", - identifier: "Identifier", - duration: "Duration", - type: "Type", - domain: "Domain", - informationLoadingNotPossible: - "Sorry, we could not load the required information.", - yes: "yes", - session: "Session", - no: "no", - tryAgain: "Try again?", - anyDomain: "any domain (ex. first party cookie)", - multipleDomains: "multiple subdomains may exist", - storageInformationDescription: - "Below you can see the longest potential duration for storage on a device, as set when using the cookie method of storage and if there are any other methods used.", - secondLayerDescriptionHtml: "Second Layer Description", - secondLayerTitle: "Second Layer Title", - consent: "Consent", - btnMore: "more", - retentionPeriod: "Retention Period", - explicit: "Explicit", - transferToThirdCountriesInfo: "transferToThirdCountriesInfo", - more: "more", - headerModal: "headerModal", - furtherInformationOptOut: "furtherInformationOptOut", - cookiePolicyLinkText: "cookiePolicyLinkText", - noImplicit: "noImplicit", - yesImplicit: "yesImplicit", - readLess: "readLess"); -const _expectedFirstLayer = FirstLayer( - hideButtonDeny: false, + dataPurposes: "Data Purposes", + accepted: "yes", + denied: "no", + history: "History", + btnDeny: "Deny", + technologiesUsed: "Technologies Used", + dataCollectedList: "Data Collected", + processingCompanyTitle: "Processing Company", + legalBasisList: "Legal Basis", + locationOfProcessing: "Location of Processing", + transferToThirdCountries: "Transfer to Third Countries", + optOut: "Click here to opt out from this processor across all domains", + policyOf: "Click here to read the privacy policy of the data processor", + dataCollectedInfo: + "This list represents all (personal) data that is collected by or through the use of this service.", + legalBasisInfo: + "In the following the required legal basis for the processing of data is listed.", + dataRecipientsList: "Data Recipients", + linkToDpaInfo: "Data Processing Agreement", + dataPurposesInfo: + "This list represents the purposes of the data collection and processing.", + technologiesUsedInfo: + "This list represents all technologies this service uses to collect data. Typical technologies are Cookies and Pixels that are placed in the browser.", + btnBannerReadMore: "Read more", + descriptionOfService: "Description of Service", + date: "Date", + minute: "minute", + minutes: "minutes", + hour: "hour", + hours: "hours", + day: "day", + days: "days", + month: "month", + months: "months", + year: "year", + years: "years", + categories: "Categories", + btnSave: "Save Services", + cookiePolicyInfo: + "Click here to read the cookie policy of the data processor", + imprintLinkText: "Imprint", + privacyPolicyLinkText: "Privacy Policy", + btnAcceptAll: "Accept All", + firstLayerTitle: "Privacy Settings", + historyDescription: "", + decision: "Decision", + storageInformation: "Storage Information", + maximumAgeCookieStorage: "Maximum age of cookie storage", + second: "second", + seconds: "seconds", + nonCookieStorage: "Non-cookie storage", + detailedStorageInformation: "Detailed Storage Information", + loadingStorageInformation: "Loading storage information", + identifier: "Identifier", + duration: "Duration", + type: "Type", + domain: "Domain", + informationLoadingNotPossible: + "Sorry, we could not load the required information.", + yes: "yes", + session: "Session", + no: "no", + tryAgain: "Try again?", + anyDomain: "any domain (ex. first party cookie)", + multipleDomains: "multiple subdomains may exist", + storageInformationDescription: + "Below you can see the longest potential duration for storage on a device, as set when using the cookie method of storage and if there are any other methods used.", + secondLayerDescriptionHtml: "Second Layer Description", + secondLayerTitle: "Second Layer Title", + consent: "Consent", + btnMore: "more", + retentionPeriod: "Retention Period", + explicit: "Explicit", + transferToThirdCountriesInfo: "transferToThirdCountriesInfo", + more: "more", + headerModal: "headerModal", + furtherInformationOptOut: "furtherInformationOptOut", + cookiePolicyLinkText: "cookiePolicyLinkText", + noImplicit: "noImplicit", + yesImplicit: "yesImplicit", + readLess: "readLess", ); +const _expectedFirstLayer = FirstLayer(hideButtonDeny: false); const _expectedSecondLayer = SecondLayer( tabsServicesLabel: "Services", @@ -589,71 +593,73 @@ const _expectedSecondLayer = SecondLayer( hideDataProcessingServices: false, ); const _expectedTCF2Settings = TCF2Settings( - togglesSpecialFeaturesToggleOff: "Off", - secondLayerTitle: "Privacy Settings Title", - tabsVendorsLabel: "Vendors", - labelsIabVendors: "Vendors who are part of the IAB TCF", - buttonsDenyAllLabel: "Deny all", - resurfacePeriodEnded: true, - vendorSpecialPurposes: "Special Purposes", - firstLayerAdditionalInfo: "", - resurfaceVendorAdded: true, - disabledSpecialFeatures: [], - resurfacePurposeChanged: true, - firstLayerHideButtonDeny: false, - hideLegitimateInterestToggles: false, - secondLayerHideButtonDeny: false, - secondLayerHideToggles: false, - togglesConsentToggleLabel: "Consent", - labelsFeatures: "Features", - togglesSpecialFeaturesToggleOn: "On", - vendorSpecialFeatures: "Special Features", - appLayerNoteResurface: - "You can change your privacy settings or withdraw your consent at any time by opening the menu point Privacy Settings.", - cmpVersion: 3, - firstLayerDescription: - "We and our third-party vendors use technologies (e.g. cookies) to store and/or access information on user's devices in order to process personal data such as IP addresses or browsing data. You may consent to the processing of your personal data for the listed purposes below. Alternatively you can set your preferences before consenting or refuse to consent. Please note that some vendors may process your personal data based on their legitimate business interest and do not ask for your consent. To exercise your right to object to processing based on legitimate interest please view our vendorlist.", - firstLayerShowDescriptions: false, - labelsPurposes: "Purposes", - firstLayerNoteResurface: - "You can change your privacy settings or withdraw your consent at any time by clicking on our Privacy Button.", - firstLayerTitle: "Privacy Information", - vendorLegitimateInterestPurposes: - "Purposes processed by Legitimate Interest", - selectedStacks: [], - labelsNonIabPurposes: "Non-IAB Purposes", - togglesLegIntToggleLabel: "Legitimate Interest", - vendorPurpose: "Purposes processed by Consent", - labelsNonIabVendors: "Vendors who are not part of the IAB TCF", - purposeOneTreatment: false, - cmpId: 5, - vendorFeatures: "Features", - secondLayerDescription: - "You can access more detailed information below regarding all purposes and third-party vendors implemented on this website. You can adjust your privacy settings based on specific purposes and/or at a vendor level at any time.", - publisherCountryCode: "DE", - buttonsSaveLabel: "Save Settings", - selectedVendorIds: [], - buttonsAcceptAllLabel: "Accept all", - hideNonIabOnFirstLayer: false, - linksManageSettingsLabel: "Manage Settings", - firstLayerHideToggles: false, - gdprApplies: true, - linksVendorListLinkLabel: "Vendorlist", - tabsPurposeLabel: "Purposes", - categoriesOfDataLabel: "Categories of data", - dataRetentionPeriodLabel: "Data Retention Period", - legitimateInterestLabel: "Legitimate Interest at stake", - version: "2.2", - examplesLabel: "Examples", - firstLayerMobileVariant: FirstLayerMobileVariant.full, - showDataSharedOutsideEUText: true, - dataSharedOutsideEUText: "dataSharedOutsideEUText", - vendorIdsOutsideEUList: [1, 2, 3], - scope: TCF2Scope.service, - changedPurposes: - TCF2ChangedPurposes(purposes: [1, 2, 3], legIntPurposes: [1, 2, 3]), - acmV2Enabled: true, - selectedATPIds: [1, 2, 3, 4, 5]); + togglesSpecialFeaturesToggleOff: "Off", + secondLayerTitle: "Privacy Settings Title", + tabsVendorsLabel: "Vendors", + labelsIabVendors: "Vendors who are part of the IAB TCF", + buttonsDenyAllLabel: "Deny all", + resurfacePeriodEnded: true, + vendorSpecialPurposes: "Special Purposes", + firstLayerAdditionalInfo: "", + resurfaceVendorAdded: true, + disabledSpecialFeatures: [], + resurfacePurposeChanged: true, + firstLayerHideButtonDeny: false, + hideLegitimateInterestToggles: false, + secondLayerHideButtonDeny: false, + secondLayerHideToggles: false, + togglesConsentToggleLabel: "Consent", + labelsFeatures: "Features", + togglesSpecialFeaturesToggleOn: "On", + vendorSpecialFeatures: "Special Features", + appLayerNoteResurface: + "You can change your privacy settings or withdraw your consent at any time by opening the menu point Privacy Settings.", + cmpVersion: 3, + firstLayerDescription: + "We and our third-party vendors use technologies (e.g. cookies) to store and/or access information on user's devices in order to process personal data such as IP addresses or browsing data. You may consent to the processing of your personal data for the listed purposes below. Alternatively you can set your preferences before consenting or refuse to consent. Please note that some vendors may process your personal data based on their legitimate business interest and do not ask for your consent. To exercise your right to object to processing based on legitimate interest please view our vendorlist.", + firstLayerShowDescriptions: false, + labelsPurposes: "Purposes", + firstLayerNoteResurface: + "You can change your privacy settings or withdraw your consent at any time by clicking on our Privacy Button.", + firstLayerTitle: "Privacy Information", + vendorLegitimateInterestPurposes: "Purposes processed by Legitimate Interest", + selectedStacks: [], + labelsNonIabPurposes: "Non-IAB Purposes", + togglesLegIntToggleLabel: "Legitimate Interest", + vendorPurpose: "Purposes processed by Consent", + labelsNonIabVendors: "Vendors who are not part of the IAB TCF", + purposeOneTreatment: false, + cmpId: 5, + vendorFeatures: "Features", + secondLayerDescription: + "You can access more detailed information below regarding all purposes and third-party vendors implemented on this website. You can adjust your privacy settings based on specific purposes and/or at a vendor level at any time.", + publisherCountryCode: "DE", + buttonsSaveLabel: "Save Settings", + selectedVendorIds: [], + buttonsAcceptAllLabel: "Accept all", + hideNonIabOnFirstLayer: false, + linksManageSettingsLabel: "Manage Settings", + firstLayerHideToggles: false, + gdprApplies: true, + linksVendorListLinkLabel: "Vendorlist", + tabsPurposeLabel: "Purposes", + categoriesOfDataLabel: "Categories of data", + dataRetentionPeriodLabel: "Data Retention Period", + legitimateInterestLabel: "Legitimate Interest at stake", + version: "2.2", + examplesLabel: "Examples", + firstLayerMobileVariant: FirstLayerMobileVariant.full, + showDataSharedOutsideEUText: true, + dataSharedOutsideEUText: "dataSharedOutsideEUText", + vendorIdsOutsideEUList: [1, 2, 3], + scope: TCF2Scope.service, + changedPurposes: TCF2ChangedPurposes( + purposes: [1, 2, 3], + legIntPurposes: [1, 2, 3], + ), + acmV2Enabled: true, + selectedATPIds: [1, 2, 3, 4, 5], +); const _expectedCCPASettings = CCPASettings( secondLayerHideLanguageSwitch: false, @@ -708,36 +714,38 @@ const _expectedCustomization = UsercentricsCustomization( borderRadiusLayer: null, ); const _expectedSettings = UsercentricsSettings( - labels: _expectedLabels, - showInitialViewForVersionChange: [], - reshowBanner: null, - displayOnlyForEU: false, - secondLayer: _expectedSecondLayer, - cookiePolicyUrl: "", - tcf2: _expectedTCF2Settings, - ccpa: _expectedCCPASettings, - privacyPolicyUrl: "https://usercentrics.com/privacy-policy/", - firstLayer: _expectedFirstLayer, - imprintUrl: "https://usercentrics.com/legal-notice/", - firstLayerDescriptionHtml: "Privacy Settings test description.", - bannerMobileDescriptionIsActive: false, - firstLayerMobileDescriptionHtml: "", - version: "6.0.4", - language: "en", - tcf2Enabled: false, - settingsId: "lQ_Dio7QL", - languagesAvailable: ["en", "de"], - enablePoweredBy: true, - editableLanguages: ["en", "de"], - customization: _expectedCustomization, - variants: VariantsSettings( - enabled: true, - experimentsJson: "experimentsJson", - activateWith: "activateWith"), - dpsDisplayFormat: DpsDisplayFormat.all, - framework: USAFrameworks.cpa, - publishedApps: [ - PublishedApp(bundleId: "bundleId", platform: PublishedAppPlatform.android) - ], - renewConsentsTimestamp: 1000, - consentWebhook: true); + labels: _expectedLabels, + showInitialViewForVersionChange: [], + reshowBanner: null, + displayOnlyForEU: false, + secondLayer: _expectedSecondLayer, + cookiePolicyUrl: "", + tcf2: _expectedTCF2Settings, + ccpa: _expectedCCPASettings, + privacyPolicyUrl: "https://usercentrics.com/privacy-policy/", + firstLayer: _expectedFirstLayer, + imprintUrl: "https://usercentrics.com/legal-notice/", + firstLayerDescriptionHtml: "Privacy Settings test description.", + bannerMobileDescriptionIsActive: false, + firstLayerMobileDescriptionHtml: "", + version: "6.0.4", + language: "en", + tcf2Enabled: false, + settingsId: "lQ_Dio7QL", + languagesAvailable: ["en", "de"], + enablePoweredBy: true, + editableLanguages: ["en", "de"], + customization: _expectedCustomization, + variants: VariantsSettings( + enabled: true, + experimentsJson: "experimentsJson", + activateWith: "activateWith", + ), + dpsDisplayFormat: DpsDisplayFormat.all, + framework: USAFrameworks.cpa, + publishedApps: [ + PublishedApp(bundleId: "bundleId", platform: PublishedAppPlatform.android), + ], + renewConsentsTimestamp: 1000, + consentWebhook: true, +);