diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index f29a9bb..89740e6 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -23,7 +23,7 @@ concurrency: env: # The version of Flutter to use should use the minimum Dart SDK version supported by the package. # Current minimum (N-1 logic) - FLUTTER_VERSION_MINIMUM_DEFAULT: "3.41.6" + FLUTTER_VERSION_MINIMUM_DEFAULT: "3.38.10" # Latest 3.x stable FLUTTER_VERSION_LATEST_STABLE_CHANNEL_DEFAULT: "3.x" # Beta channel support diff --git a/wakelock_plus/android/src/main/kotlin/dev/fluttercommunity/plus/wakelock/WakelockPlusMessages.g.kt b/wakelock_plus/android/src/main/kotlin/dev/fluttercommunity/plus/wakelock/WakelockPlusMessages.g.kt index 2d4b1d0..d9e23a4 100644 --- a/wakelock_plus/android/src/main/kotlin/dev/fluttercommunity/plus/wakelock/WakelockPlusMessages.g.kt +++ b/wakelock_plus/android/src/main/kotlin/dev/fluttercommunity/plus/wakelock/WakelockPlusMessages.g.kt @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon @file:Suppress("UNCHECKED_CAST", "ArrayInDataClass") @@ -33,36 +33,150 @@ private object WakelockPlusMessagesPigeonUtils { ) } } + fun doubleEquals(a: Double, b: Double): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0) 0.0 else a) == (if (b == 0.0) 0.0 else b) || (a.isNaN() && b.isNaN()) + } + + fun floatEquals(a: Float, b: Float): Boolean { + // Normalize -0.0 to 0.0 and handle NaN equality. + return (if (a == 0.0f) 0.0f else a) == (if (b == 0.0f) 0.0f else b) || (a.isNaN() && b.isNaN()) + } + + fun doubleHash(d: Double): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (d == 0.0) 0.0 else d + val bits = java.lang.Double.doubleToLongBits(normalized) + return (bits xor (bits ushr 32)).toInt() + } + + fun floatHash(f: Float): Int { + // Normalize -0.0 to 0.0 and handle NaN to ensure consistent hash codes. + val normalized = if (f == 0.0f) 0.0f else f + return java.lang.Float.floatToIntBits(normalized) + } + fun deepEquals(a: Any?, b: Any?): Boolean { + if (a === b) { + return true + } + if (a == null || b == null) { + return false + } if (a is ByteArray && b is ByteArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is IntArray && b is IntArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is LongArray && b is LongArray) { - return a.contentEquals(b) + return a.contentEquals(b) } if (a is DoubleArray && b is DoubleArray) { - return a.contentEquals(b) + if (a.size != b.size) return false + for (i in a.indices) { + if (!doubleEquals(a[i], b[i])) return false + } + return true + } + if (a is FloatArray && b is FloatArray) { + if (a.size != b.size) return false + for (i in a.indices) { + if (!floatEquals(a[i], b[i])) return false + } + return true } if (a is Array<*> && b is Array<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + for (i in a.indices) { + if (!deepEquals(a[i], b[i])) return false + } + return true } if (a is List<*> && b is List<*>) { - return a.size == b.size && - a.indices.all{ deepEquals(a[it], b[it]) } + if (a.size != b.size) return false + val iterA = a.iterator() + val iterB = b.iterator() + while (iterA.hasNext() && iterB.hasNext()) { + if (!deepEquals(iterA.next(), iterB.next())) return false + } + return true } if (a is Map<*, *> && b is Map<*, *>) { - return a.size == b.size && a.all { - (b as Map).contains(it.key) && - deepEquals(it.value, b[it.key]) + if (a.size != b.size) return false + for (entry in a) { + val key = entry.key + var found = false + for (bEntry in b) { + if (deepEquals(key, bEntry.key)) { + if (deepEquals(entry.value, bEntry.value)) { + found = true + break + } else { + return false + } + } + } + if (!found) return false } + return true + } + if (a is Double && b is Double) { + return doubleEquals(a, b) + } + if (a is Float && b is Float) { + return floatEquals(a, b) } return a == b } - + + fun deepHash(value: Any?): Int { + return when (value) { + null -> 0 + is ByteArray -> value.contentHashCode() + is IntArray -> value.contentHashCode() + is LongArray -> value.contentHashCode() + is DoubleArray -> { + var result = 1 + for (item in value) { + result = 31 * result + doubleHash(item) + } + result + } + is FloatArray -> { + var result = 1 + for (item in value) { + result = 31 * result + floatHash(item) + } + result + } + is Array<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is List<*> -> { + var result = 1 + for (item in value) { + result = 31 * result + deepHash(item) + } + result + } + is Map<*, *> -> { + var result = 0 + for (entry in value) { + result += ((deepHash(entry.key) * 31) xor deepHash(entry.value)) + } + result + } + is Double -> doubleHash(value) + is Float -> floatHash(value) + else -> value.hashCode() + } + } + } /** @@ -75,7 +189,7 @@ class WakelockPlusFlutterError ( val code: String, override val message: String? = null, val details: Any? = null -) : Throwable() +) : RuntimeException() /** * Message for toggling the wakelock on the platform side. @@ -98,15 +212,21 @@ data class ToggleMessage ( ) } override fun equals(other: Any?): Boolean { - if (other !is ToggleMessage) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return WakelockPlusMessagesPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as ToggleMessage + return WakelockPlusMessagesPigeonUtils.deepEquals(this.enable, other.enable) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + WakelockPlusMessagesPigeonUtils.deepHash(this.enable) + return result + } } /** @@ -130,15 +250,21 @@ data class IsEnabledMessage ( ) } override fun equals(other: Any?): Boolean { - if (other !is IsEnabledMessage) { + if (other == null || other.javaClass != javaClass) { return false } if (this === other) { return true } - return WakelockPlusMessagesPigeonUtils.deepEquals(toList(), other.toList()) } + val other = other as IsEnabledMessage + return WakelockPlusMessagesPigeonUtils.deepEquals(this.enabled, other.enabled) + } - override fun hashCode(): Int = toList().hashCode() + override fun hashCode(): Int { + var result = javaClass.hashCode() + result = 31 * result + WakelockPlusMessagesPigeonUtils.deepHash(this.enabled) + return result + } } private open class WakelockPlusMessagesPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { diff --git a/wakelock_plus/example/pubspec.yaml b/wakelock_plus/example/pubspec.yaml index e1db1da..9ef7d7c 100644 --- a/wakelock_plus/example/pubspec.yaml +++ b/wakelock_plus/example/pubspec.yaml @@ -5,8 +5,8 @@ description: Demonstrates how to use the wakelock_plus plugin. publish_to: 'none' # Remove this line if you wish to publish to pub.dev environment: - sdk: '>=3.11.0 <4.0.0' - flutter: ">=3.41.0" + sdk: '>=3.10.0 <4.0.0' + flutter: ">=3.38.0" # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions diff --git a/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/include/wakelock_plus/messages.g.h b/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/include/wakelock_plus/messages.g.h index eea50a3..a1e0e85 100644 --- a/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/include/wakelock_plus/messages.g.h +++ b/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/include/wakelock_plus/messages.g.h @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon @import Foundation; diff --git a/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/messages.g.m b/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/messages.g.m index 911784b..2ad18f9 100644 --- a/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/messages.g.m +++ b/wakelock_plus/ios/wakelock_plus/Sources/wakelock_plus/messages.g.m @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon #import "./include/wakelock_plus/messages.g.h" @@ -9,6 +9,96 @@ @import Flutter; #endif +static BOOL __attribute__((unused)) FLTPigeonDeepEquals(id _Nullable a, id _Nullable b) { + if (a == b) { + return YES; + } + if (a == nil) { + return b == [NSNull null]; + } + if (b == nil) { + return a == [NSNull null]; + } + if ([a isKindOfClass:[NSNumber class]] && [b isKindOfClass:[NSNumber class]]) { + return [a isEqual:b] || (isnan([(NSNumber *)a doubleValue]) && isnan([(NSNumber *)b doubleValue])); + } + if ([a isKindOfClass:[NSArray class]] && [b isKindOfClass:[NSArray class]]) { + NSArray *arrayA = (NSArray *)a; + NSArray *arrayB = (NSArray *)b; + if (arrayA.count != arrayB.count) { + return NO; + } + for (NSUInteger i = 0; i < arrayA.count; i++) { + if (!FLTPigeonDeepEquals(arrayA[i], arrayB[i])) { + return NO; + } + } + return YES; + } + if ([a isKindOfClass:[NSDictionary class]] && [b isKindOfClass:[NSDictionary class]]) { + NSDictionary *dictA = (NSDictionary *)a; + NSDictionary *dictB = (NSDictionary *)b; + if (dictA.count != dictB.count) { + return NO; + } + for (id keyA in dictA) { + id valueA = dictA[keyA]; + BOOL found = NO; + for (id keyB in dictB) { + if (FLTPigeonDeepEquals(keyA, keyB)) { + id valueB = dictB[keyB]; + if (FLTPigeonDeepEquals(valueA, valueB)) { + found = YES; + break; + } else { + return NO; + } + } + } + if (!found) { + return NO; + } + } + return YES; + } + return [a isEqual:b]; +} + +static NSUInteger __attribute__((unused)) FLTPigeonDeepHash(id _Nullable value) { + if (value == nil || value == (id)[NSNull null]) { + return 0; + } + if ([value isKindOfClass:[NSNumber class]]) { + NSNumber *n = (NSNumber *)value; + double d = n.doubleValue; + if (isnan(d)) { + // Normalize NaN to a consistent hash. + return (NSUInteger)0x7FF8000000000000; + } + if (d == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + d = 0.0; + } + return @(d).hash; + } + if ([value isKindOfClass:[NSArray class]]) { + NSUInteger result = 1; + for (id item in (NSArray *)value) { + result = result * 31 + FLTPigeonDeepHash(item); + } + return result; + } + if ([value isKindOfClass:[NSDictionary class]]) { + NSUInteger result = 0; + NSDictionary *dict = (NSDictionary *)value; + for (id key in dict) { + result += ((FLTPigeonDeepHash(key) * 31) ^ FLTPigeonDeepHash(dict[key])); + } + return result; + } + return [value hash]; +} + static NSArray *wrapResult(id result, FlutterError *error) { if (error) { return @[ @@ -54,6 +144,22 @@ + (nullable WAKELOCKPLUSToggleMessage *)nullableFromList:(NSArray *)list { self.enable ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + WAKELOCKPLUSToggleMessage *other = (WAKELOCKPLUSToggleMessage *)object; + return FLTPigeonDeepEquals(self.enable, other.enable); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.enable); + return result; +} @end @implementation WAKELOCKPLUSIsEnabledMessage @@ -75,6 +181,22 @@ + (nullable WAKELOCKPLUSIsEnabledMessage *)nullableFromList:(NSArray *)list self.enabled ?: [NSNull null], ]; } +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[self class]]) { + return NO; + } + WAKELOCKPLUSIsEnabledMessage *other = (WAKELOCKPLUSIsEnabledMessage *)object; + return FLTPigeonDeepEquals(self.enabled, other.enabled); +} + +- (NSUInteger)hash { + NSUInteger result = [self class].hash; + result = result * 31 + FLTPigeonDeepHash(self.enabled); + return result; +} @end @interface WAKELOCKPLUSMessagesPigeonCodecReader : FlutterStandardReader diff --git a/wakelock_plus/pubspec.yaml b/wakelock_plus/pubspec.yaml index 3cf4703..c4ee5b8 100644 --- a/wakelock_plus/pubspec.yaml +++ b/wakelock_plus/pubspec.yaml @@ -6,8 +6,8 @@ version: 1.6.0 repository: https://github.com/fluttercommunity/wakelock_plus/tree/main/wakelock_plus environment: - sdk: '>=3.11.0 <4.0.0' - flutter: ">=3.41.0" + sdk: '>=3.10.0 <4.0.0' + flutter: ">=3.38.0" dependencies: flutter: @@ -18,11 +18,11 @@ dependencies: wakelock_plus_platform_interface: ^1.5.0 # Windows dependencies - win32: ">=6.0.0 <7.0.0" + win32: ">=6.0.1 <7.0.0" # Linux dependencies dbus: ^0.7.12 - package_info_plus: ">=10.0.0 <11.0.0" + package_info_plus: ">=10.1.0 <11.0.0" # Web dependencies web: ">=0.5.1 <2.0.0" @@ -31,7 +31,7 @@ dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^6.0.0 - pigeon: ^26.2.3 # dart run pigeon --input "pigeons/messages.dart" + pigeon: ^26.3.4 # dart run pigeon --input "pigeons/messages.dart" mocktail: ^1.0.5 # For information on the generic Dart part of this file, see the diff --git a/wakelock_plus_platform_interface/lib/messages.g.dart b/wakelock_plus_platform_interface/lib/messages.g.dart index 6a2e4de..9f51230 100644 --- a/wakelock_plus_platform_interface/lib/messages.g.dart +++ b/wakelock_plus_platform_interface/lib/messages.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: unused_import, unused_shown_name // ignore_for_file: type=lint @@ -49,6 +49,15 @@ List wrapResponse({ } bool _deepEquals(Object? a, Object? b) { + if (identical(a, b)) { + return true; + } + if (a is double && b is double) { + if (a.isNaN && b.isNaN) { + return true; + } + return a == b; + } if (a is List && b is List) { return a.length == b.length && a.indexed.every( @@ -56,16 +65,52 @@ bool _deepEquals(Object? a, Object? b) { ); } if (a is Map && b is Map) { - return a.length == b.length && - a.entries.every( - (MapEntry entry) => - (b as Map).containsKey(entry.key) && - _deepEquals(entry.value, b[entry.key]), - ); + if (a.length != b.length) { + return false; + } + for (final MapEntry entryA in a.entries) { + bool found = false; + for (final MapEntry entryB in b.entries) { + if (_deepEquals(entryA.key, entryB.key)) { + if (_deepEquals(entryA.value, entryB.value)) { + found = true; + break; + } else { + return false; + } + } + } + if (!found) { + return false; + } + } + return true; } return a == b; } +int _deepHash(Object? value) { + if (value is List) { + return Object.hashAll(value.map(_deepHash)); + } + if (value is Map) { + int result = 0; + for (final MapEntry entry in value.entries) { + result += (_deepHash(entry.key) * 31) ^ _deepHash(entry.value); + } + return result; + } + if (value is double && value.isNaN) { + // Normalize NaN to a consistent hash. + return 0x7FF8000000000000.hashCode; + } + if (value is double && value == 0.0) { + // Normalize -0.0 to 0.0 so they have the same hash code. + return 0.0.hashCode; + } + return value.hashCode; +} + /// Message for toggling the wakelock on the platform side. class ToggleMessage { ToggleMessage({this.enable}); @@ -94,12 +139,12 @@ class ToggleMessage { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(enable, other.enable); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } /// Message for reporting the wakelock state from the platform side. @@ -130,12 +175,12 @@ class IsEnabledMessage { if (identical(this, other)) { return true; } - return _deepEquals(encode(), other.encode()); + return _deepEquals(enabled, other.enabled); } @override // ignore: avoid_equals_and_hash_code_on_mutable_classes - int get hashCode => Object.hashAll(_toList()); + int get hashCode => _deepHash([runtimeType, ..._toList()]); } class _PigeonCodec extends StandardMessageCodec { diff --git a/wakelock_plus_platform_interface/pubspec.yaml b/wakelock_plus_platform_interface/pubspec.yaml index 16e131e..861185d 100644 --- a/wakelock_plus_platform_interface/pubspec.yaml +++ b/wakelock_plus_platform_interface/pubspec.yaml @@ -7,8 +7,8 @@ repository: >-2 https://github.com/fluttercommunity/wakelock_plus/tree/main/wakelock_plus_platform_interface environment: - sdk: '>=3.11.0 <4.0.0' - flutter: ">=3.41.0" + sdk: '>=3.10.0 <4.0.0' + flutter: ">=3.38.0" dependencies: flutter: diff --git a/wakelock_plus_platform_interface/test/messages.g.dart b/wakelock_plus_platform_interface/test/messages.g.dart index 8fb3d3b..67ffead 100644 --- a/wakelock_plus_platform_interface/test/messages.g.dart +++ b/wakelock_plus_platform_interface/test/messages.g.dart @@ -1,4 +1,4 @@ -// Autogenerated from Pigeon (v26.2.3), do not edit directly. +// Autogenerated from Pigeon (v26.3.4), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers, omit_obvious_local_variable_types // ignore_for_file: avoid_relative_lib_imports