diff --git a/lib/Backend/Bluetooth/bluetooth_manager_plus.dart b/lib/Backend/Bluetooth/bluetooth_manager_plus.dart index 6a538578..3c7f3c24 100644 --- a/lib/Backend/Bluetooth/bluetooth_manager_plus.dart +++ b/lib/Backend/Bluetooth/bluetooth_manager_plus.dart @@ -14,6 +14,7 @@ import 'package:tail_app/Backend/Definitions/Device/device_definition.dart'; import 'package:tail_app/Backend/device_registry.dart'; import 'package:wakelock_plus/wakelock_plus.dart'; +import '../../Frontend/utils.dart'; import '../../constants.dart'; import '../sensors.dart'; import 'bluetooth_manager.dart'; @@ -208,7 +209,7 @@ Future initFlutterBluePlus(InitFlutterBluePlusRef ref) async { statefulDevice.messageHistory.add(MessageHistoryEntry(type: MessageHistoryType.receive, message: value)); // Firmware Version if (value.startsWith("VER")) { - statefulDevice.fwVersion.value = value.substring(value.indexOf(" ")); + statefulDevice.fwVersion.value = getVersionSemVer(value.substring(value.indexOf(" "))); // Sent after VER message } else if (value.startsWith("GLOWTIP")) { statefulDevice.hasGlowtip.value = "TRUE" == value.substring(value.indexOf(" ")); diff --git a/lib/Backend/Definitions/Device/device_definition.dart b/lib/Backend/Definitions/Device/device_definition.dart index 28d6507f..5d1e157d 100644 --- a/lib/Backend/Definitions/Device/device_definition.dart +++ b/lib/Backend/Definitions/Device/device_definition.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:hive/hive.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:tail_app/Backend/Bluetooth/bluetooth_manager.dart'; import 'package:tail_app/Backend/Bluetooth/bluetooth_manager_plus.dart'; @@ -67,8 +68,10 @@ class BaseDeviceDefinition { final String bleTxCharacteristic; final DeviceType deviceType; final String fwURL; + final Version? minVersion; + final bool unsupported; - const BaseDeviceDefinition(this.uuid, this.btName, this.bleDeviceService, this.bleRxCharacteristic, this.bleTxCharacteristic, this.deviceType, this.fwURL); + const BaseDeviceDefinition({required this.uuid, required this.btName, required this.bleDeviceService, required this.bleRxCharacteristic, required this.bleTxCharacteristic, required this.deviceType, this.fwURL = "", this.minVersion, this.unsupported = false}); @override String toString() { @@ -85,7 +88,7 @@ class BaseStatefulDevice extends ChangeNotifier { final ValueNotifier batteryLow = ValueNotifier(false); final ValueNotifier gearReturnedError = ValueNotifier(false); - final ValueNotifier fwVersion = ValueNotifier(""); + final ValueNotifier fwVersion = ValueNotifier(Version.none); final ValueNotifier hwVersion = ValueNotifier(""); final ValueNotifier hasGlowtip = ValueNotifier(false); final ValueNotifier deviceState = ValueNotifier(DeviceState.standby); @@ -102,7 +105,7 @@ class BaseStatefulDevice extends ChangeNotifier { Stopwatch stopWatch = Stopwatch(); bool disableAutoConnect = false; bool forgetOnDisconnect = false; - + ValueNotifier mandatoryOtaRequired = ValueNotifier(false); final CircularBuffer messageHistory = CircularBuffer(50); BaseStatefulDevice(this.baseDeviceDefinition, this.baseStoredDevice, this.ref) { @@ -116,7 +119,7 @@ class BaseStatefulDevice extends ChangeNotifier { reset(); } else if (deviceConnectionState.value == ConnectivityState.connected) { // Add initial commands to the queue - Future.delayed(const Duration(seconds: 5), () { + Future.delayed(const Duration(seconds: 2), () { commandQueue.addCommand(BluetoothMessage(message: "VER", device: this, priority: Priority.low, type: Type.system, responseMSG: "VER ")); commandQueue.addCommand(BluetoothMessage(message: "HWVER", device: this, priority: Priority.low, type: Type.system, responseMSG: "HWVER ")); }); @@ -127,11 +130,19 @@ class BaseStatefulDevice extends ChangeNotifier { batteryLow.value = batteryLevel.value < 20; }); fwInfo.addListener(() { - if (fwInfo.value != null && fwVersion.value.isNotEmpty) { - if (fwInfo.value?.version.split(" ")[1] != fwVersion.value) { - hasUpdate.value = true; + if (fwInfo.value != null && fwVersion.value.compareTo(Version.none) > 0 && fwVersion.value.compareTo(Version.parse(fwInfo.value!.version)) < 0) { + hasUpdate.value = true; + } + }); + fwVersion.addListener(() { + if (baseDeviceDefinition.minVersion != null) { + if (baseDeviceDefinition.minVersion!.compareTo(fwVersion.value) < 0) { + mandatoryOtaRequired.value = true; } } + if (fwInfo.value != null && fwVersion.value.compareTo(Version.none) > 0 && fwVersion.value.compareTo(getVersionSemVer(fwInfo.value!.version)) < 0) { + hasUpdate.value = true; + } }); getFirmwareInfo(); } @@ -148,11 +159,6 @@ class BaseStatefulDevice extends ChangeNotifier { (value) { if (value.statusCode == 200) { fwInfo.value = FWInfo.fromJson(const JsonDecoder().convert(value.data.toString())); - if (fwVersion.value != "") { - if (fwInfo.value?.version.split(" ")[1] != fwVersion.value) { - hasUpdate.value = true; - } - } } }, ).onError((error, stackTrace) { @@ -172,6 +178,7 @@ class BaseStatefulDevice extends ChangeNotifier { batlevels = []; stopWatch.reset(); mtu.value = -1; + mandatoryOtaRequired.value = false; } } diff --git a/lib/Backend/device_registry.dart b/lib/Backend/device_registry.dart index 4b73e2a4..045bbad7 100644 --- a/lib/Backend/device_registry.dart +++ b/lib/Backend/device_registry.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:logging/logging.dart' as log; +import 'package:pub_semver/pub_semver.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:tail_app/Backend/Bluetooth/bluetooth_manager.dart'; import 'package:tail_app/Backend/Definitions/Action/base_action.dart'; @@ -12,60 +13,61 @@ final deviceRegistryLogger = log.Logger('DeviceRegistry'); @immutable class DeviceRegistry { static Set allDevices = { + BaseDeviceDefinition( + uuid: "798e1528-2832-4a87-93d7-4d1b25a2f418", + btName: "MiTail", + bleDeviceService: "3af2108b-d066-42da-a7d4-55648fa0a9b6", + bleRxCharacteristic: "c6612b64-0087-4974-939e-68968ef294b0", + bleTxCharacteristic: "5bfd6484-ddee-4723-bfe6-b653372bbfd6", + deviceType: DeviceType.tail, + fwURL: "https://thetailcompany.com/fw/mitail", + minVersion: Version(5, 0, 0)), const BaseDeviceDefinition( - "798e1528-2832-4a87-93d7-4d1b25a2f418", - "MiTail", - "3af2108b-d066-42da-a7d4-55648fa0a9b6", - "c6612b64-0087-4974-939e-68968ef294b0", - "5bfd6484-ddee-4723-bfe6-b653372bbfd6", - DeviceType.tail, - "https://thetailcompany.com/fw/mitail", + uuid: "9c5f3692-1c6e-4d46-b607-4f6f4a6e28ee", + btName: "(!)Tail1", + bleDeviceService: "3af2108b-d066-42da-a7d4-55648fa0a9b6", + bleRxCharacteristic: "c6612b64-0087-4974-939e-68968ef294b0", + bleTxCharacteristic: "5bfd6484-ddee-4723-bfe6-b653372bbfd6", + deviceType: DeviceType.tail, + unsupported: true), + BaseDeviceDefinition( + uuid: "5fb21175-fef4-448a-a38b-c472d935abab", + btName: "minitail", + bleDeviceService: "3af2108b-d066-42da-a7d4-55648fa0a9b6", + bleRxCharacteristic: "c6612b64-0087-4974-939e-68968ef294b0", + bleTxCharacteristic: "5bfd6484-ddee-4723-bfe6-b653372bbfd6", + deviceType: DeviceType.tail, + fwURL: "https://thetailcompany.com/fw/mini", + minVersion: Version(5, 0, 0), ), - const BaseDeviceDefinition( - "9c5f3692-1c6e-4d46-b607-4f6f4a6e28ee", - "(!)Tail1", - "3af2108b-d066-42da-a7d4-55648fa0a9b6", - "c6612b64-0087-4974-939e-68968ef294b0", - "5bfd6484-ddee-4723-bfe6-b653372bbfd6", - DeviceType.tail, - "", - ), - const BaseDeviceDefinition( - "5fb21175-fef4-448a-a38b-c472d935abab", - "minitail", - "3af2108b-d066-42da-a7d4-55648fa0a9b6", - "c6612b64-0087-4974-939e-68968ef294b0", - "5bfd6484-ddee-4723-bfe6-b653372bbfd6", - DeviceType.tail, - "https://thetailcompany.com/fw/mini", + BaseDeviceDefinition( + uuid: "e790f509-f95b-4eb4-b649-5b43ee1eee9c", + btName: "flutter", + bleDeviceService: "3af2108b-d066-42da-a7d4-55648fa0a9b6", + bleRxCharacteristic: "c6612b64-0087-4974-939e-68968ef294b0", + bleTxCharacteristic: "5bfd6484-ddee-4723-bfe6-b653372bbfd6", + deviceType: DeviceType.wings, + fwURL: "https://thetailcompany.com/fw/flutter", + minVersion: Version(5, 0, 0), ), const BaseDeviceDefinition( - "e790f509-f95b-4eb4-b649-5b43ee1eee9c", - "flutter", - "3af2108b-d066-42da-a7d4-55648fa0a9b6", - "c6612b64-0087-4974-939e-68968ef294b0", - "5bfd6484-ddee-4723-bfe6-b653372bbfd6", - DeviceType.wings, - "https://thetailcompany.com/fw/flutter", + uuid: "927dee04-ddd4-4582-8e42-69dc9fbfae66", + btName: "EG2", + bleDeviceService: "927dee04-ddd4-4582-8e42-69dc9fbfae66", + bleRxCharacteristic: "0b646a19-371e-4327-b169-9632d56c0e84", + bleTxCharacteristic: "05e026d8-b395-4416-9f8a-c00d6c3781b9", + deviceType: DeviceType.ears, + fwURL: "https://thetailcompany.com/fw/eg", ), const BaseDeviceDefinition( - "927dee04-ddd4-4582-8e42-69dc9fbfae66", - "EG2", - "927dee04-ddd4-4582-8e42-69dc9fbfae66", - "0b646a19-371e-4327-b169-9632d56c0e84", - "05e026d8-b395-4416-9f8a-c00d6c3781b9", - DeviceType.ears, - "https://thetailcompany.com/fw/eg", - ), - const BaseDeviceDefinition( - "ba2f2b00-8f65-4cc3-afad-58ba1fccd62d", - "EarGear", - "927dee04-ddd4-4582-8e42-69dc9fbfae66", - "0b646a19-371e-4327-b169-9632d56c0e84", - "05e026d8-b395-4416-9f8a-c00d6c3781b9", - DeviceType.ears, - "", - ), + uuid: "ba2f2b00-8f65-4cc3-afad-58ba1fccd62d", + btName: "EarGear", + bleDeviceService: "927dee04-ddd4-4582-8e42-69dc9fbfae66", + bleRxCharacteristic: "0b646a19-371e-4327-b169-9632d56c0e84", + bleTxCharacteristic: "05e026d8-b395-4416-9f8a-c00d6c3781b9", + deviceType: DeviceType.ears, + unsupported: true, + ) }; static BaseDeviceDefinition getByUUID(String uuid) { diff --git a/lib/Frontend/Widgets/base_card.dart b/lib/Frontend/Widgets/base_card.dart new file mode 100644 index 00000000..94176dc5 --- /dev/null +++ b/lib/Frontend/Widgets/base_card.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class BaseCard extends StatelessWidget { + const BaseCard({super.key, required this.child, this.elevation = 1, this.color}); + + final double elevation; + final Widget child; + final Color? color; + + @override + Widget build(BuildContext context) { + return Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Card( + color: color, + elevation: elevation, + child: child, + ), + ), + ); + } +} diff --git a/lib/Frontend/Widgets/known_gear.dart b/lib/Frontend/Widgets/known_gear.dart index 29571840..53c1ee8c 100644 --- a/lib/Frontend/Widgets/known_gear.dart +++ b/lib/Frontend/Widgets/known_gear.dart @@ -21,7 +21,10 @@ class KnownGear extends ConsumerStatefulWidget { class _KnownGearState extends ConsumerState { @override Widget build(BuildContext context) { - List knownDevices = ref.watch(knownDevicesProvider).values.toList(); + List knownDevices = ref + .watch(knownDevicesProvider) + .values + .toList(); return Row( children: [ ...knownDevices.map((BaseStatefulDevice baseStatefulDevice) => KnownGearCard(baseStatefulDevice: baseStatefulDevice)), @@ -45,7 +48,10 @@ class ScanForNewGearButton extends ConsumerWidget { padding: const EdgeInsets.all(8.0), child: SizedBox( height: 50 * MediaQuery.textScalerOf(context).scale(1), - width: ref.watch(knownDevicesProvider).values.length > 1 ? 100 * MediaQuery.textScalerOf(context).scale(1) : 200 * MediaQuery.textScalerOf(context).scale(1), + width: ref + .watch(knownDevicesProvider) + .values + .length > 1 ? 100 * MediaQuery.textScalerOf(context).scale(1) : 200 * MediaQuery.textScalerOf(context).scale(1), child: Center( child: Text( scanDevicesTitle(), @@ -72,7 +78,10 @@ class ScanForNewGearButton extends ConsumerWidget { ListTile( title: Text( scanDevicesTitle(), - style: Theme.of(context).textTheme.titleLarge, + style: Theme + .of(context) + .textTheme + .titleLarge, ), ), Expanded( @@ -116,7 +125,9 @@ class _KnownGearCardState extends ConsumerState { return Badge( isLabelVisible: value, largeSize: 35, - backgroundColor: Theme.of(context).primaryColor, + backgroundColor: Theme + .of(context) + .primaryColor, label: const Icon(Icons.system_update), child: child, ); @@ -190,6 +201,12 @@ class _KnownGearCardState extends ConsumerState { ); }, ), + AnimatedCrossFade( + firstChild: const Icon(Icons.warning), + secondChild: Container(), + crossFadeState: widget.baseStatefulDevice.baseDeviceDefinition.unsupported ? CrossFadeState.showFirst : CrossFadeState.showSecond, + duration: animationTransitionDuration, + ), ValueListenableBuilder( valueListenable: widget.baseStatefulDevice.rssi, builder: (BuildContext context, value, Widget? child) { @@ -215,7 +232,9 @@ class _KnownGearCardState extends ConsumerState { builder: (BuildContext context, double value, Widget? child) { return Card( clipBehavior: Clip.antiAlias, - color: Color.lerp(Theme.of(context).cardColor, Color(widget.baseStatefulDevice.baseStoredDevice.color), value), + color: Color.lerp(Theme + .of(context) + .cardColor, Color(widget.baseStatefulDevice.baseStoredDevice.color), value), child: child, ); }, diff --git a/lib/Frontend/intn_defs.dart b/lib/Frontend/intn_defs.dart index 5fbf8e4f..93d8a080 100644 --- a/lib/Frontend/intn_defs.dart +++ b/lib/Frontend/intn_defs.dart @@ -312,3 +312,5 @@ String onboardingDoneButtonLabel() => Intl.message("Done", name: 'onboardingDone String onboardingCompletedTitle() => Intl.message("Happy Wagging!", name: 'onboardingCompletedTitle', desc: 'Title of the final page of the onboarding screen'); String doubleBackToClose() => Intl.message("Press again to exit ", name: 'doubleBackToClose', desc: 'Snackbar message which appears when the back button is pressed at the main screen'); + +String noLongerSupported() => Intl.message("This gear is no longer supported.", name: 'noLongerSupported', desc: 'Warning message which appears for unsupported gear on the manage gear page'); diff --git a/lib/Frontend/pages/home.dart b/lib/Frontend/pages/home.dart index dc98787f..f8102bd6 100644 --- a/lib/Frontend/pages/home.dart +++ b/lib/Frontend/pages/home.dart @@ -7,6 +7,7 @@ import 'package:logging/logging.dart' as log; import 'package:sentry_hive/sentry_hive.dart'; import 'package:tail_app/Backend/Bluetooth/bluetooth_manager.dart'; import 'package:tail_app/Backend/Bluetooth/bluetooth_manager_plus.dart'; +import 'package:tail_app/Frontend/Widgets/base_card.dart'; import 'package:tail_app/constants.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -78,67 +79,57 @@ class _HomeState extends ConsumerState { ), ), ), - Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Card( - child: Column( - mainAxisSize: MainAxisSize.min, + BaseCard( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.waving_hand), + title: Text(homeWelcomeMessageTitle()), + subtitle: Text(homeWelcomeMessage()), + ), + ButtonBar( children: [ - ListTile( - leading: const Icon(Icons.waving_hand), - title: Text(homeWelcomeMessageTitle()), - subtitle: Text(homeWelcomeMessage()), + TextButton( + onPressed: () async { + context.push('/more/viewMarkdown/', extra: MarkdownInfo(content: await rootBundle.loadString('CHANGELOG.md'), title: homeChangelogLinkTitle())); + }, + child: Text(homeChangelogLinkTitle()), ), - ButtonBar( - children: [ - TextButton( - onPressed: () async { - context.push('/more/viewMarkdown/', extra: MarkdownInfo(content: await rootBundle.loadString('CHANGELOG.md'), title: homeChangelogLinkTitle())); - }, - child: Text(homeChangelogLinkTitle()), - ), - TextButton( - onPressed: () async { - await launchUrl(Uri.parse('https://thetailcompany.com?utm_source=Tail_App')); - }, - child: const Text('Tail Company Store'), - ), - ], + TextButton( + onPressed: () async { + await launchUrl(Uri.parse('https://thetailcompany.com?utm_source=Tail_App')); + }, + child: const Text('Tail Company Store'), ), ], ), - ), + ], ), ), AnimatedCrossFade( - firstChild: Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Card( - child: Column( - mainAxisSize: MainAxisSize.min, + firstChild: BaseCard( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const ListTile( + leading: Icon(Icons.bluetooth_disabled), + title: Text('Bluetooth is Unavailable'), + subtitle: Text('Bluetooth is required to connect to Gear'), + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, children: [ - const ListTile( - leading: Icon(Icons.bluetooth_disabled), - title: Text('Bluetooth is Unavailable'), - subtitle: Text('Bluetooth is required to connect to Gear'), - ), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton( - onPressed: () async { - AppSettings.openAppSettings(type: AppSettingsType.bluetooth); - }, - child: const Text('Open Settings'), - ), - const SizedBox(width: 8), - ], + TextButton( + onPressed: () async { + AppSettings.openAppSettings(type: AppSettingsType.bluetooth); + }, + child: const Text('Open Settings'), ), + const SizedBox(width: 8), ], ), - ), + ], ), ), secondChild: Container(), diff --git a/lib/Frontend/pages/shell.dart b/lib/Frontend/pages/shell.dart index 326e5a06..e3a3b806 100644 --- a/lib/Frontend/pages/shell.dart +++ b/lib/Frontend/pages/shell.dart @@ -18,6 +18,7 @@ import 'package:upgrader/upgrader.dart'; import '../../constants.dart'; import '../../main.dart'; +import '../Widgets/base_card.dart'; import '../Widgets/known_gear.dart'; import '../intn_defs.dart'; @@ -172,6 +173,27 @@ class _ManageGearState extends ConsumerState { shrinkWrap: true, controller: widget.controller, children: [ + if (widget.device.baseDeviceDefinition.unsupported) ...[ + BaseCard( + elevation: 3, + color: Colors.red, + child: ListTile( + leading: const Icon( + Icons.warning, + color: Colors.white, + ), + trailing: const Icon( + Icons.warning, + color: Colors.white, + ), + title: Text( + noLongerSupported(), + style: Theme.of(context).textTheme.titleMedium?.copyWith(color: Colors.white), + textAlign: TextAlign.center, + ), + ), + ) + ], ValueListenableBuilder( valueListenable: widget.device.batteryLevel, builder: (BuildContext context, double value, Widget? child) { diff --git a/lib/Frontend/utils.dart b/lib/Frontend/utils.dart index 416f13f8..d04f0201 100644 --- a/lib/Frontend/utils.dart +++ b/lib/Frontend/utils.dart @@ -4,6 +4,7 @@ import 'package:dio/dio.dart'; import 'package:logging/logging.dart'; import 'package:native_dio_adapter/native_dio_adapter.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:pub_semver/pub_semver.dart'; import 'package:sentry_dio/sentry_dio.dart'; import 'package:wordpress_client/wordpress_client.dart'; @@ -49,3 +50,20 @@ Dio initDio({skipSentry = false}) { WordpressClient getWordpressClient() { return WordpressClient.fromDioInstance(baseUrl: Uri.parse('https://thetailcompany.com/wp-json/wp/v2'), instance: initDio()); } + +Version getVersionSemVer(String input) { + String major = "0"; + String minor = "0"; + String patch = "0"; + List split = input.split("."); + if (split.isNotEmpty && int.tryParse(split[0]) != null) { + major = split[0]; + } + if (split.length > 1 && int.tryParse(split[1]) != null) { + minor = split[1]; + } + if (split.length > 2 && int.tryParse(split[2]) != null) { + patch = split[2]; + } + return Version(int.parse(major), int.parse(minor), int.parse(patch)); +} diff --git a/pubspec.lock b/pubspec.lock index e8270715..d03e4780 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -58,10 +58,10 @@ packages: dependency: transitive description: name: archive - sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 + sha256: "6bd38d335f0954f5fad9c79e614604fbf03a0e5b975923dd001b6ea965ef5b4b" url: "https://pub.dev" source: hosted - version: "3.5.1" + version: "3.6.0" args: dependency: transitive description: @@ -619,10 +619,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: aa073287b8f43553678e6fa9e8bb9c83212ff76e09542129a8099bbc8db4df65 + sha256: "6ad5662b014c06c20fa46ab78715c96b2222a7fe4f87bf77e0289592c2539e86" url: "https://pub.dev" source: hosted - version: "14.1.2" + version: "14.1.3" graphs: dependency: transitive description: @@ -691,10 +691,10 @@ packages: dependency: transitive description: name: image - sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" url: "https://pub.dev" source: hosted - version: "4.1.7" + version: "4.2.0" in_app_review: dependency: "direct main" description: @@ -1091,7 +1091,7 @@ packages: source: git version: "1.3.1" pub_semver: - dependency: transitive + dependency: "direct main" description: name: pub_semver sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" diff --git a/pubspec.yaml b/pubspec.yaml index 60c163d9..bd97d809 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: sdk: flutter cross_platform: ^3.0.1 logging: ^1.2.0 - go_router: ^14.1.2 + go_router: ^14.1.3 vector_math: ^2.1.4 # used for joystick collection: ^1.18.0 # Priority Queue intl: #pinned to flutter version? @@ -26,6 +26,7 @@ dependencies: #tivy: ^0.1.1 circular_buffer: ^0.11.0 # Used for serial console wordpress_client: ^8.4.8 + pub_semver: ^2.1.4 # Platform Interfaces device_info_plus: ^10.1.0 @@ -113,7 +114,7 @@ dependencies: dev_dependencies: build_runner: # Required for build flutter_lints: # Dryer Lint - riverpod_generator: ^2.4.0 + riverpod_generator: ^2.4.2 flutter_native_splash: ^2.4.0 json_serializable: ^6.8.0 # required for @JsonSerializable annotations hive_generator: ^2.0.1 # required for @HiveType annotations