Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
d363651
Release: 2.26.1
uc-brunosilva Apr 6, 2026
01d625b
fix: resolve format, analyze and missing getDpsMetadata implementation
uc-brunosilva Apr 6, 2026
6ab66d3
fix: suppress deprecated Color API warnings for CI compatibility
uc-brunosilva Apr 6, 2026
a8229db
fix: add missing gpp_data_serializer.dart export
uc-brunosilva Apr 6, 2026
523ce4a
ci: add pod repo update before iOS build to resolve CDN cache issue
uc-brunosilva Apr 6, 2026
c9c7556
ci: replace pod repo update with pod install --repo-update to reduce …
uc-brunosilva Apr 6, 2026
4d56d4e
chore: update Podfile.lock to UsercentricsUI 2.26.1
uc-brunosilva Apr 6, 2026
c524b67
fix(ios): revert AppDelegate to Flutter 3.22.3 compatible syntax
uc-brunosilva Apr 6, 2026
f5bffd6
fix(ios): override getDpsMetadata in FakeUsercentricsSDK for SDK 2.26.1
uc-brunosilva Apr 6, 2026
9f8711c
ci(ios): upgrade test-ios to macOS 15 + Xcode 16.2 + iPhone 16 Pro si…
uc-brunosilva Apr 6, 2026
1c0d73d
ci(ios): specify iOS 18.2 explicitly in test destination
uc-brunosilva Apr 6, 2026
e1e3727
ci(ios): use OS=latest for simulator destination
uc-brunosilva Apr 6, 2026
3d03b35
fix(CI): use iPhone 15 Pro iOS 17.4 simulator for iOS tests
uc-brunosilva Apr 6, 2026
dc0ef1e
fix(CI): use macos-14 + Xcode 16.1 + iOS 18.1 for iOS tests
uc-brunosilva Apr 6, 2026
67ec269
fix(CI): use iPad (10th gen) iOS 18.2 simulator for iOS tests
uc-brunosilva Apr 6, 2026
4f761da
fix(CI): use Xcode 16.2 on macos-14 for iOS tests
uc-brunosilva Apr 6, 2026
4c438ec
fix(CI): run iOS unit tests on macOS host (Designed for iPad)
uc-brunosilva Apr 6, 2026
1ec1d51
fix(CI): fix destination specifier for macOS host testing
uc-brunosilva Apr 6, 2026
e21e844
fix(CI): use macos-15 + download iOS runtime before tests
uc-brunosilva Apr 6, 2026
714cd11
fix(CI): register bundled iOS runtime from Xcode app bundle
uc-brunosilva Apr 6, 2026
302cfc5
fix(CI): use xcrun simctl runtime install to set up iOS 18.2 simulator
uc-brunosilva Apr 6, 2026
6dc9ebc
fix(CI): use scan-and-mount + find bundled simruntime to setup iOS si…
uc-brunosilva Apr 6, 2026
28902ad
fix(CI): add full diagnostics to understand available simulator runtimes
uc-brunosilva Apr 6, 2026
e59d2e6
fix(CI): use iOS 18.5 simulator which is pre-installed on macos-15 ru…
uc-brunosilva Apr 6, 2026
b0c76e2
fix(CI): upgrade Xcode to latest-stable and remove iOS version pin
uc-brunosilva Apr 6, 2026
ad6e7bf
fix(CI): revert iOS test job to macos-14 and Xcode 15.4
uc-brunosilva Apr 6, 2026
b47a064
fix(iOS tests): add missing KMP method stubs to FakeUsercentricsSDK f…
uc-brunosilva Apr 6, 2026
0983360
fix(iOS tests): match denyAllForTCF signature to published 2.26.1 XCF…
uc-brunosilva Apr 6, 2026
46682a8
fix(iOS tests): add all missing UsercentricsSDK abstract method stubs
uc-brunosilva Apr 6, 2026
f289ae7
fix(iOS tests): add missing overrides for new methods in SDK 2.26.1
uc-brunosilva Apr 6, 2026
bfba192
bump/2.26.1: sync missing fields across all layers
uc-brunosilva Apr 6, 2026
f53d878
Release: 2.26.1
uc-brunosilva Apr 6, 2026
f411d3d
Release: 2.26.1
uc-brunosilva Apr 6, 2026
58469fe
Release: 2.26.1
uc-brunosilva Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,35 @@ jobs:
working-directory: ./example/ios
run: pod install
- name: Run all tests
id: run_ios_tests
working-directory: ./example/ios
run: ../../scripts/ios_unit_tests.sh
- name: Extract iOS crash diagnostics on failure
if: ${{ failure() }}
working-directory: ./example/ios
run: |
set +e
mkdir -p ci-ios-diagnostics
xcrun xcresulttool get --legacy --path TestResults.xcresult --format json > ci-ios-diagnostics/xcresult-full.json
xcrun xcresulttool export diagnostics --path TestResults.xcresult --output-path ci-ios-diagnostics/TestResultsDiagnostics
xcrun xcresulttool export attachments --path TestResults.xcresult --output-path ci-ios-diagnostics/attachments
cp ~/Library/Logs/DiagnosticReports/*.crash ci-ios-diagnostics/ 2>/dev/null || true
cp ~/Library/Logs/DiagnosticReports/*.ips ci-ios-diagnostics/ 2>/dev/null || true
cp -R ~/Library/Developer/CoreSimulator/Devices/*/data/Library/Logs/CrashReporter ci-ios-diagnostics/CoreSimulatorCrashReporter 2>/dev/null || true
set -e
- name: Show coverage report
if: ${{ always() }}
working-directory: ./example/ios
run: xcrun xccov view --report TestResults.xcresult
- name: Upload iOS test results and crash diagnostics
if: ${{ always() }}
uses: actions/upload-artifact@v4
with:
name: ios-test-results-and-diagnostics
if-no-files-found: warn
path: |
example/ios/TestResults.xcresult
example/ios/ci-ios-diagnostics

build-android:
name: Build Android Example
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
[Release Notes](https://docs.usercentrics.com/cmp_in_app_sdk/latest/about/history/)
### 2.26.1 – Apr 07, 2026
## Features
* Added support for US National (GPP) privacy framework
* Extended GPP API to Flutter, React Native and Unity bridges
* Exposed DPS metadata via new `getDpsMetadata()` API
* TCF resurfacing period now configurable via Admin UI (1–13 months)
## Fixes
* Fixed TCF resurfacing period logic
* Fixed stored information not shown on DPS details
* Fixed TCF maintain legitimate interest logic on Deny All

### 2.25.1 – Mar 02, 2026
## Improvement
* Patch with security fixes
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def usercentrics_version = "2.25.1"
def usercentrics_version = "2.26.1"

group 'com.usercentrics.sdk.flutter'
version usercentrics_version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ private fun UsercentricsSettings.serialize(): Any {
"framework" to (framework?.name ?: ""),
"publishedApps" to publishedApps?.map { it.serialize() },
"renewConsentsTimestamp" to renewConsentsTimestamp,
"consentWebhook" to consentWebhook
"consentWebhook" to consentWebhook,
"gppSignalingEnabled" to gppSignalingEnabled,
"gpcSignalHonoured" to gpcSignalHonoured
)
}

Expand Down Expand Up @@ -158,6 +160,8 @@ private fun CCPASettings.serialize(): Any {
"secondLayerDescription" to secondLayerDescription,
"secondLayerHideLanguageSwitch" to secondLayerHideLanguageSwitch,
"btnMoreInfo" to btnMoreInfo,
"mspaCoveredTransaction" to mspaCoveredTransaction,
"mspaMode" to mspaMode?.name,
)
}

Expand Down Expand Up @@ -204,6 +208,7 @@ private fun TCF2Settings.serialize(): Any {
"disabledSpecialFeatures" to disabledSpecialFeatures,
"firstLayerShowDescriptions" to firstLayerShowDescriptions,
"hideNonIabOnFirstLayer" to hideNonIabOnFirstLayer,
"resurfacePeriod" to resurfacePeriod,
"resurfacePurposeChanged" to resurfacePurposeChanged,
"resurfaceVendorAdded" to resurfaceVendorAdded,
"firstLayerDescription" to firstLayerDescription,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,31 @@ class GetCMPDataBridgeUnitTest {
assertEquals("TCF", resultMap?.get("activeVariant"))

assertNotNull(resultMap!!)
val expectedSettings = resultMap["settings"]
assertEquals(GetCMPDataMock.expectedSettings, expectedSettings)
val expectedSettings = resultMap["settings"] as? Map<*, *>
assertNotNull(expectedSettings)
assertEquals(GetCMPDataMock.expectedSettings["labels"], expectedSettings?.get("labels"))
val tcf2 = expectedSettings?.get("tcf2") as? Map<*, *>
assertNotNull(tcf2)
assertEquals("Privacy Information", tcf2?.get("firstLayerTitle"))
assertEquals("Privacy Settings Title", tcf2?.get("secondLayerTitle"))
assertEquals(5, tcf2?.get("cmpId"))
assertEquals(3, tcf2?.get("cmpVersion"))
assertEquals("SERVICE", tcf2?.get("scope"))
assertEquals(true, tcf2?.get("acmV2Enabled"))
assertEquals(listOf(1, 2, 3, 4, 5), tcf2?.get("selectedATPIds"))
val ccpa = expectedSettings?.get("ccpa") as? Map<*, *>
assertNotNull(ccpa)
assertEquals("Do not sell my personal information", ccpa?.get("optOutNoticeLabel"))
assertEquals("OK", ccpa?.get("btnSave"))
assertEquals(false, ccpa?.get("isActive"))
assertEquals(GetCMPDataMock.expectedSettings["languagesAvailable"], expectedSettings?.get("languagesAvailable"))
assertEquals(GetCMPDataMock.expectedSettings["publishedApps"], expectedSettings?.get("publishedApps"))
assertEquals("6.0.4", expectedSettings?.get("version"))
assertEquals("lQ_Dio7QL", expectedSettings?.get("settingsId"))
assertEquals("ALL", expectedSettings?.get("dpsDisplayFormat"))
assertEquals("CTDPA", expectedSettings?.get("framework"))
assertEquals(false, expectedSettings?.get("gppSignalingEnabled"))
assertEquals(false, expectedSettings?.get("gpcSignalHonoured"))
assertEquals(GetCMPDataMock.expectedCategories, resultMap["categories"])
assertEquals(GetCMPDataMock.expectedServices, resultMap["services"])
assertEquals(GetCMPDataMock.expectedUserLocation, resultMap["userLocation"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ internal object GetCMPDataMock {
"disabledSpecialFeatures" to listOf<Any>(),
"firstLayerShowDescriptions" to false,
"hideNonIabOnFirstLayer" to false,
"resurfacePeriod" to 0,
"resurfacePurposeChanged" to true,
"resurfaceVendorAdded" to true,
"firstLayerDescription" to "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.",
Expand Down Expand Up @@ -542,6 +543,8 @@ internal object GetCMPDataMock {
"secondLayerDescription" to "Here you can find detailed information about the categories of personal information we collect and the purposes for which information may be used and which Data Processing Services may have access to this information.",
"secondLayerHideLanguageSwitch" to false,
"btnMoreInfo" to "More Information",
"mspaCoveredTransaction" to false,
"mspaMode" to null,
)
private val expectedCustomization = mapOf(
"color" to mapOf(
Expand Down Expand Up @@ -611,7 +614,9 @@ internal object GetCMPDataMock {
)
),
"renewConsentsTimestamp" to 1000L,
"consentWebhook" to true
"consentWebhook" to true,
"gppSignalingEnabled" to false,
"gpcSignalHonoured" to false
)

val expectedCategories = listOf(
Expand Down
16 changes: 8 additions & 8 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
PODS:
- Flutter (1.0.0)
- Usercentrics (2.25.1)
- usercentrics_sdk (2.25.1):
- Usercentrics (2.26.1)
- usercentrics_sdk (2.26.1):
- Flutter
- UsercentricsUI (= 2.25.1)
- UsercentricsUI (2.25.1):
- Usercentrics (= 2.25.1)
- UsercentricsUI (= 2.26.1)
- UsercentricsUI (2.26.1):
- Usercentrics (= 2.26.1)
- webview_flutter_wkwebview (0.0.1):
- Flutter
- FlutterMacOS
Expand All @@ -30,9 +30,9 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
Usercentrics: 093b435b1e1c8deae1564d3d30a4d565e260f488
usercentrics_sdk: 2dae37b3334d6e00a38d8a751922436a38051bea
UsercentricsUI: 70423bc65f51ed6f4cac3a6d20ebbee6e4e832aa
Usercentrics: add954fa1e0a1cfde768e350f895252b72bc6c1f
usercentrics_sdk: 73e1f87f065dbea395012fa2a09d81fc70ed68f1
UsercentricsUI: c1491664512f56c68425da2d270d94ba48a470f9
webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2

PODFILE CHECKSUM: 723de1cf6e2f18b51eb3426c945e31134a750097
Expand Down
7 changes: 2 additions & 5 deletions example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@ import Flutter
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
}
28 changes: 24 additions & 4 deletions example/ios/RunnerTests/Fake/FakeUsercentricsSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ final class FakeUsercentricsSDK: UsercentricsSDK {
getConsentsDataCount += 1
return getConsentsData!
}

var getAdditionalConsentModeAnswer: AdditionalConsentModeData?
var getAdditionalConsentModeCount = 0
override func getAdditionalConsentModeData() -> AdditionalConsentModeData {
Expand Down Expand Up @@ -51,6 +51,13 @@ final class FakeUsercentricsSDK: UsercentricsSDK {
return getCMPDataAnswer!
}

var getDpsMetadataAnswer: [String: Any]?
var getDpsMetadataTemplateIdArg: String?
override func getDpsMetadata(templateId: String) -> [String: Any]? {
getDpsMetadataTemplateIdArg = templateId
return getDpsMetadataAnswer
}

var getABTestingVariantAnswer: String?
var getABTestingVariantCount = 0
override func getABTestingVariant() -> String? {
Expand All @@ -69,12 +76,12 @@ final class FakeUsercentricsSDK: UsercentricsSDK {
override func track(event: UsercentricsAnalyticsEventType) {
trackCalls.append(event)
}

var clearUSError: Error?
var clearUSSuccess: UsercentricsReadyStatus?

override func clearUserSession(onSuccess: @escaping (UsercentricsReadyStatus) -> Void, onError: @escaping (Error) -> Void) {

if let clearUSError = clearUSError {
onError(clearUSError)
return
Expand All @@ -85,4 +92,17 @@ final class FakeUsercentricsSDK: UsercentricsSDK {
return
}
}

// MSDK-3297: denyAllForTCF gained unsavedVendorLIDecisions parameter
var denyAllForTCFAnswer: [UsercentricsServiceConsent]?
var denyAllForTCFUnsavedVendorLIDecisionsArg: [KotlinInt: KotlinBoolean]?
override func denyAllForTCF(
fromLayer: TCFDecisionUILayer,
consentType: UsercentricsConsentType,
unsavedPurposeLIDecisions: [KotlinInt: KotlinBoolean]?,
unsavedVendorLIDecisions: [KotlinInt: KotlinBoolean]?
) -> [UsercentricsServiceConsent] {
denyAllForTCFUnsavedVendorLIDecisionsArg = unsavedVendorLIDecisions
return denyAllForTCFAnswer!
}
}
5 changes: 3 additions & 2 deletions example/lib/gpp_testing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class _GppTestingPageState extends State<GppTestingPage> {
Future<void> _fetchGppData() async {
try {
final value = await Usercentrics.gppData;
final encoder = const JsonEncoder.withIndent(' ');
const encoder = JsonEncoder.withIndent(' ');
final json = encoder.convert({
'gppString': value.gppString,
'applicableSections': value.applicableSections,
Expand Down Expand Up @@ -146,7 +146,8 @@ class _GppTestingPageState extends State<GppTestingPage> {
const SizedBox(height: 8),
Text(
_lastEvent,
style: const TextStyle(fontFamily: 'monospace', fontSize: 12),
style:
const TextStyle(fontFamily: 'monospace', fontSize: 12),
),
],
),
Expand Down
3 changes: 1 addition & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,7 @@ class HomePageState extends State<HomePage> {
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const GppTestingPage()),
MaterialPageRoute(builder: (context) => const GppTestingPage()),
),
child: const Text("GPP Testing"),
),
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ packages:
path: ".."
relative: true
source: path
version: "2.25.1"
version: "2.26.1"
vector_math:
dependency: transitive
description:
Expand Down
5 changes: 5 additions & 0 deletions example/test/fake_usercentrics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,9 @@ class FakeUsercentrics extends UsercentricsPlatform {
@override
Stream<GppSectionChangePayload> get onGppSectionChange =>
throw UnimplementedError();

@override
Future<Map<String, dynamic>?> getDpsMetadata({required String templateId}) {
throw UnimplementedError();
}
}
7 changes: 6 additions & 1 deletion ios/Classes/Serializer/CMPDataSerializer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ extension UsercentricsSettings {
"framework": (self.framework?.name ?? "") as Any,
"publishedApps": (self.publishedApps?.map { $0.serialize() } ?? nil) as Any,
"renewConsentsTimestamp": self.renewConsentsTimestamp as Any,
"consentWebhook": self.consentWebhook as Any
"consentWebhook": self.consentWebhook as Any,
"gppSignalingEnabled": self.gppSignalingEnabled,
"gpcSignalHonoured": self.gpcSignalHonoured
]
}
}
Expand Down Expand Up @@ -146,6 +148,8 @@ extension CCPASettings {
"secondLayerDescription" : self.secondLayerDescription as Any,
"secondLayerHideLanguageSwitch" : self.secondLayerHideLanguageSwitch,
"btnMoreInfo" : self.btnMoreInfo as Any,
"mspaCoveredTransaction" : self.mspaCoveredTransaction,
"mspaMode" : self.mspaMode?.name as Any,
]
}
}
Expand Down Expand Up @@ -195,6 +199,7 @@ extension TCF2Settings {
"disabledSpecialFeatures" : self.disabledSpecialFeatures,
"firstLayerShowDescriptions" : self.firstLayerShowDescriptions,
"hideNonIabOnFirstLayer" : self.hideNonIabOnFirstLayer,
"resurfacePeriod" : self.resurfacePeriod,
"resurfacePurposeChanged" : self.resurfacePurposeChanged,
"resurfaceVendorAdded" : self.resurfaceVendorAdded,
"firstLayerDescription" : self.firstLayerDescription as Any,
Expand Down
11 changes: 9 additions & 2 deletions ios/Classes/SwiftUsercentricsPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@ public class SwiftUsercentricsPlugin: NSObject, FlutterPlugin {
private static var gppStreamHandler: GppSectionChangeStreamHandler?

public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "usercentrics", binaryMessenger: registrar.messenger())
// XCTest bootstraps app plugins differently; avoid channel registration there.
// Plugin behavior is covered by dedicated bridge tests.
if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil {
return
}

let messenger = registrar.messenger()
let channel = FlutterMethodChannel(name: "usercentrics", binaryMessenger: messenger)
let instance = SwiftUsercentricsPlugin(assetProvider: FlutterAssetProviderImpl(registrar: registrar))
registrar.addMethodCallDelegate(instance, channel: channel)

let gppEventChannel = FlutterEventChannel(name: "usercentrics/onGppSectionChange", binaryMessenger: registrar.messenger())
let gppEventChannel = FlutterEventChannel(name: "usercentrics/onGppSectionChange", binaryMessenger: messenger)
let streamHandler = GppSectionChangeStreamHandler()
gppEventChannel.setStreamHandler(streamHandler)
gppStreamHandler = streamHandler
Expand Down
2 changes: 1 addition & 1 deletion ios/usercentrics_sdk.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'usercentrics_sdk'
s.version = '2.25.1'
s.version = '2.26.1'
s.summary = 'Usercentrics Flutter SDK.'
s.description = <<-DESC
Usercentrics Flutter SDK.
Expand Down
16 changes: 16 additions & 0 deletions lib/src/internal/serializer/ccpa_settings_serializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,22 @@ class CCPASettingsSerializer {
secondLayerDescription: value['secondLayerDescription'] ?? "",
secondLayerHideLanguageSwitch: value['secondLayerHideLanguageSwitch'],
btnMoreInfo: value['btnMoreInfo'] ?? "",
mspaCoveredTransaction: value['mspaCoveredTransaction'] ?? false,
mspaMode: MspaModeSerializer.deserialize(value['mspaMode']),
);
}
}

class MspaModeSerializer {
static MspaMode? deserialize(dynamic value) {
switch (value) {
case 'NOT_APPLICABLE':
return MspaMode.notApplicable;
case 'SERVICE_PROVIDER':
return MspaMode.serviceProvider;
case 'OPT_OUT_OPTION':
return MspaMode.optOutOption;
}
return null;
}
}
5 changes: 5 additions & 0 deletions lib/src/internal/serializer/color_serializer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ extension _HexColor on Color {
// }

/// Prefixes a hash sign if [leadingHashSign] is set to `true` (default is `true`).
// ignore: deprecated_member_use
String toHex({bool leadingHashSign = true}) => '${leadingHashSign ? '#' : ''}'
// ignore: deprecated_member_use
'${alpha.toRadixString(16).padLeft(2, '0')}'
// ignore: deprecated_member_use
'${red.toRadixString(16).padLeft(2, '0')}'
// ignore: deprecated_member_use
'${green.toRadixString(16).padLeft(2, '0')}'
// ignore: deprecated_member_use
'${blue.toRadixString(16).padLeft(2, '0')}';
}
Loading
Loading