Commit 8ca91c8
Changed files (10)
app
android
app
macos
test
bluetooth
health_data_store
app/android/app/src/main/AndroidManifest.xml
@@ -7,7 +7,23 @@
</intent>
</queries>
- <application
+ <!-- Tell Google Play Store that your app uses Bluetooth LE
+ Set android:required="true" if bluetooth is necessary -->
+ <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" />
+
+ <!-- New Bluetooth permissions in Android 12
+ https://developer.android.com/about/versions/12/features/bluetooth-permissions -->
+ <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
+ <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+
+ <!-- legacy for Android 11 or lower -->
+ <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
+ <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30"/>
+
+ <!-- legacy for Android 9 or lower -->
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="28" />
+ <application
android:label="blood pressure app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
app/android/app/proguard-rules.pro
@@ -0,0 +1,1 @@
+-keep class com.lib.flutter_blue_plus.* { *; }
\ No newline at end of file
app/lib/bluetooth/bluetooth_cubit.dart
@@ -0,0 +1,78 @@
+import 'dart:async';
+import 'dart:io';
+
+import 'package:blood_pressure_app/bluetooth/flutter_blue_plus_mockable.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+import 'package:permission_handler/permission_handler.dart';
+
+part 'bluetooth_state.dart';
+
+/// Availability of the devices bluetooth adapter.
+///
+/// The only state that allows using the adapter is [BluetoothReady].
+class BluetoothCubit extends Cubit<BluetoothState> {
+ /// Create a cubit connecting to the bluetooth module for availability.
+ ///
+ /// [flutterBluePlus] may be provided for testing purposes.
+ BluetoothCubit({
+ FlutterBluePlusMockable? flutterBluePlus
+ }): _flutterBluePlus = flutterBluePlus ?? FlutterBluePlusMockable(),
+ super(BluetoothInitial()) {
+ _adapterStateStateSubscription = _flutterBluePlus.adapterState.listen(_onAdapterStateChanged);
+ }
+
+ FlutterBluePlusMockable _flutterBluePlus;
+
+ BluetoothAdapterState _adapterState = BluetoothAdapterState.unknown;
+
+ late StreamSubscription<BluetoothAdapterState> _adapterStateStateSubscription;
+
+ @override
+ Future<void> close() async {
+ await _adapterStateStateSubscription.cancel();
+ await super.close();
+ }
+
+ void _onAdapterStateChanged(BluetoothAdapterState state) {
+ _adapterState = state;
+ switch (_adapterState) {
+ case BluetoothAdapterState.unavailable:
+ emit(BluetoothUnfeasible());
+ case BluetoothAdapterState.unauthorized:
+ emit(BluetoothUnauthorized());
+ case BluetoothAdapterState.on:
+ emit(BluetoothReady());
+ case BluetoothAdapterState.off:
+ case BluetoothAdapterState.turningOff:
+ case BluetoothAdapterState.turningOn:
+ emit(BluetoothDisabled());
+ case BluetoothAdapterState.unknown:
+ emit(BluetoothInitial());
+ }
+
+ /// Request the permission to connect to bluetooth devices.
+ Future<bool> requestPermission() async {
+ assert(_adapterState == BluetoothAdapterState.unauthorized, 'No need to '
+ 'request permission when device unavailable or already authorized.');
+ assert(await Permission.bluetoothConnect.isGranted, 'Permissions handler'
+ 'should report the same as blue_plus');
+ final permission = await Permission.bluetoothConnect.request();
+ return permission.isGranted;
+ }
+
+ /// Request to enable bluetooth on the device
+ Future<bool> enableBluetooth() async {
+ assert(state is BluetoothDisabled, 'No need to enable bluetooth when '
+ 'already enabled or not known to be disabled.');
+ if (!Platform.isAndroid) return false;
+ try {
+ await _flutterBluePlus.turnOn();
+ return true;
+ } on FlutterBluePlusException {
+ return false;
+ }
+ }
+ }
+}
app/lib/bluetooth/bluetooth_state.dart
@@ -0,0 +1,25 @@
+part of 'bluetooth_cubit.dart';
+
+/// State of the devices bluetooth module.
+@immutable
+abstract class BluetoothState {}
+
+/// No information on whether bluetooth is available.
+///
+/// Options relating to bluetooth should only be shown where they don't disturb.
+class BluetoothInitial extends BluetoothState {}
+
+/// There is no way bluetooth will work (e.g. no sensor).
+///
+/// Options relating to bluetooth should not be shown.
+class BluetoothUnfeasible extends BluetoothState {}
+
+/// There is a bluetooth sensor but the app has no permission.
+class BluetoothUnauthorized extends BluetoothState {}
+
+/// The device has Bluetooth and the app has permissions, but it is disabled in
+/// the device settings.
+class BluetoothDisabled extends BluetoothState {}
+
+/// Bluetooth is ready for use by the app.
+class BluetoothReady extends BluetoothState {}
app/lib/bluetooth/flutter_blue_plus_mockable.dart
@@ -0,0 +1,139 @@
+import 'dart:async';
+
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+
+/// Wrapper for FlutterBluePlus in order to easily mock it
+/// Wraps all calls for testing purposes
+class FlutterBluePlusMockable {
+ LogLevel get logLevel => FlutterBluePlus.logLevel;
+
+ /// Checks whether the hardware supports Bluetooth
+ Future<bool> get isSupported => FlutterBluePlus.isSupported;
+
+ /// The current adapter state
+ BluetoothAdapterState get adapterStateNow => FlutterBluePlus.adapterStateNow;
+
+ /// Return the friendly Bluetooth name of the local Bluetooth adapter
+ Future<String> get adapterName => FlutterBluePlus.adapterName;
+
+ /// returns whether we are scanning as a stream
+ Stream<bool> get isScanning => FlutterBluePlus.isScanning;
+
+ /// are we scanning right now?
+ bool get isScanningNow => FlutterBluePlus.isScanningNow;
+
+ /// the most recent scan results
+ List<ScanResult> get lastScanResults => FlutterBluePlus.lastScanResults;
+
+ /// a stream of scan results
+ /// - if you re-listen to the stream it re-emits the previous results
+ /// - the list contains all the results since the scan started
+ /// - the returned stream is never closed.
+ Stream<List<ScanResult>> get scanResults => FlutterBluePlus.scanResults;
+
+ /// This is the same as scanResults, except:
+ /// - it *does not* re-emit previous results after scanning stops.
+ Stream<List<ScanResult>> get onScanResults => FlutterBluePlus.onScanResults;
+
+ /// Get access to all device event streams
+ BluetoothEvents get events => FlutterBluePlus.events;
+
+ /// Gets the current state of the Bluetooth module
+ Stream<BluetoothAdapterState> get adapterState =>
+ FlutterBluePlus.adapterState;
+
+ /// Retrieve a list of devices currently connected to your app
+ List<BluetoothDevice> get connectedDevices =>
+ FlutterBluePlus.connectedDevices;
+
+ /// Retrieve a list of devices currently connected to the system
+ /// - The list includes devices connected to by *any* app
+ /// - You must still call device.connect() to connect them to *your app*
+ Future<List<BluetoothDevice>> get systemDevices =>
+ FlutterBluePlus.systemDevices;
+
+ /// Retrieve a list of bonded devices (Android only)
+ Future<List<BluetoothDevice>> get bondedDevices =>
+ FlutterBluePlus.bondedDevices;
+
+ /// Set configurable options
+ /// - [showPowerAlert] Whether to show the power alert (iOS & MacOS only). i.e. CBCentralManagerOptionShowPowerAlertKey
+ /// To set this option you must call this method before any other method in this package.
+ /// See: https://developer.apple.com/documentation/corebluetooth/cbcentralmanageroptionshowpoweralertkey
+ /// This option has no effect on Android.
+ Future<void> setOptions({
+ bool showPowerAlert = true,
+ }) => FlutterBluePlus.setOptions(showPowerAlert: showPowerAlert);
+
+ /// Turn on Bluetooth (Android only),
+ Future<void> turnOn({int timeout = 60}) =>
+ FlutterBluePlus.turnOn(timeout: timeout);
+
+ /// Start a scan, and return a stream of results
+ /// Note: scan filters use an "or" behavior. i.e. if you set `withServices` & `withNames` we
+ /// return all the advertisments that match any of the specified services *or* any of the specified names.
+ /// - [withServices] filter by advertised services
+ /// - [withRemoteIds] filter for known remoteIds (iOS: 128-bit guid, android: 48-bit mac address)
+ /// - [withNames] filter by advertised names (exact match)
+ /// - [withKeywords] filter by advertised names (matches any substring)
+ /// - [withMsd] filter by manfacture specific data
+ /// - [withServiceData] filter by service data
+ /// - [timeout] calls stopScan after a specified duration
+ /// - [removeIfGone] if true, remove devices after they've stopped advertising for X duration
+ /// - [continuousUpdates] If `true`, we continually update 'lastSeen' & 'rssi' by processing
+ /// duplicate advertisements. This takes more power. You typically should not use this option.
+ /// - [continuousDivisor] Useful to help performance. If divisor is 3, then two-thirds of advertisements are
+ /// ignored, and one-third are processed. This reduces main-thread usage caused by the platform channel.
+ /// The scan counting is per-device so you always get the 1st advertisement from each device.
+ /// If divisor is 1, all advertisements are returned. This argument only matters for `continuousUpdates` mode.
+ /// - [oneByOne] if `true`, we will stream every advertistment one by one, possibly including duplicates.
+ /// If `false`, we deduplicate the advertisements, and return a list of devices.
+ /// - [androidScanMode] choose the android scan mode to use when scanning
+ /// - [androidUsesFineLocation] request `ACCESS_FINE_LOCATION` permission at runtime
+ Future<void> startScan({
+ List<Guid> withServices = const [],
+ List<String> withRemoteIds = const [],
+ List<String> withNames = const [],
+ List<String> withKeywords = const [],
+ List<MsdFilter> withMsd = const [],
+ List<ServiceDataFilter> withServiceData = const [],
+ Duration? timeout,
+ Duration? removeIfGone,
+ bool continuousUpdates = false,
+ int continuousDivisor = 1,
+ bool oneByOne = false,
+ AndroidScanMode androidScanMode = AndroidScanMode.lowLatency,
+ bool androidUsesFineLocation = false,
+ }) => FlutterBluePlus.startScan(
+ withServices: withServices,
+ withRemoteIds: withRemoteIds,
+ withNames: withNames,
+ withKeywords: withKeywords,
+ withMsd: withMsd,
+ withServiceData: withServiceData,
+ timeout: timeout,
+ removeIfGone: removeIfGone,
+ continuousUpdates: continuousUpdates,
+ continuousDivisor: continuousDivisor,
+ oneByOne: oneByOne,
+ androidScanMode: androidScanMode,
+ androidUsesFineLocation: androidUsesFineLocation,
+ );
+
+ /// Stops a scan for Bluetooth Low Energy devices
+ Future<void> stopScan() => FlutterBluePlus.stopScan();
+
+ /// Register a subscription to be canceled when scanning is complete.
+ /// This function simplifies cleanup, to prevent creating duplicate stream subscriptions.
+ /// - this is an optional convenience function
+ /// - prevents accidentally creating duplicate subscriptions before each scan
+ void cancelWhenScanComplete(StreamSubscription subscription) =>
+ FlutterBluePlus.cancelWhenScanComplete(subscription);
+
+ /// Sets the internal FlutterBlue log level
+ Future<void> setLogLevel(LogLevel level, {bool color = true}) =>
+ FlutterBluePlus.setLogLevel(level, color: color);
+
+ /// Request Bluetooth PHY support
+ Future<PhySupport> getPhySupport() => FlutterBluePlus.getPhySupport();
+}
\ No newline at end of file
app/macos/Flutter/GeneratedPluginRegistrant.swift
@@ -5,12 +5,14 @@
import FlutterMacOS
import Foundation
+import flutter_blue_plus
import package_info_plus
import shared_preferences_foundation
import sqflite
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+ FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin"))
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
app/test/bluetooth/bluetooth_cubit_test.dart
@@ -0,0 +1,42 @@
+import 'dart:async';
+
+import 'package:blood_pressure_app/bluetooth/bluetooth_cubit.dart';
+import 'package:blood_pressure_app/bluetooth/flutter_blue_plus_mockable.dart';
+import 'package:flutter_blue_plus/flutter_blue_plus.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:mockito/annotations.dart';
+import 'package:mockito/mockito.dart';
+
+@GenerateNiceMocks([MockSpec<FlutterBluePlusMockable>()])
+import 'bluetooth_cubit_test.mocks.dart';
+
+void main() {
+ test('should translate adapter stream to state', () async {
+ final bluePlus = MockFlutterBluePlusMockable();
+ when(bluePlus.adapterState).thenAnswer((_) =>
+ Stream.fromIterable([
+ BluetoothAdapterState.unknown,
+ BluetoothAdapterState.unavailable,
+ BluetoothAdapterState.turningOff,
+ BluetoothAdapterState.off,
+ BluetoothAdapterState.unauthorized,
+ BluetoothAdapterState.turningOn,
+ BluetoothAdapterState.on,
+ ]));
+ final cubit = BluetoothCubit(flutterBluePlus: bluePlus);
+ expect(cubit.state, isA<BluetoothInitial>());
+
+ await expectLater(cubit.stream, emitsInOrder([
+ isA<BluetoothInitial>(),
+ isA<BluetoothUnfeasible>(),
+ isA<BluetoothDisabled>(),
+ isA<BluetoothDisabled>(),
+ isA<BluetoothUnauthorized>(),
+ isA<BluetoothDisabled>(),
+ isA<BluetoothReady>(),
+ ]));
+ });
+ // TODO: integration tests ?
+ test('should request permissions', () async {});
+ test('should enable bluetooth', () async {});
+}
app/pubspec.lock
@@ -5,18 +5,18 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
- sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7"
+ sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051
url: "https://pub.dev"
source: hosted
- version: "67.0.0"
+ version: "64.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
- sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d"
+ sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893"
url: "https://pub.dev"
source: hosted
- version: "6.4.1"
+ version: "6.2.0"
archive:
dependency: transitive
description:
@@ -81,6 +81,46 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.1"
+ build_config:
+ dependency: transitive
+ description:
+ name: build_config
+ sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.1.1"
+ build_daemon:
+ dependency: transitive
+ description:
+ name: build_daemon
+ sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.1"
+ build_resolvers:
+ dependency: transitive
+ description:
+ name: build_resolvers
+ sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.2"
+ build_runner:
+ dependency: "direct dev"
+ description:
+ name: build_runner
+ sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.9"
+ build_runner_core:
+ dependency: transitive
+ description:
+ name: build_runner_core
+ sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799"
+ url: "https://pub.dev"
+ source: hosted
+ version: "7.3.0"
built_collection:
dependency: transitive
description:
@@ -113,6 +153,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.1"
+ checked_yaml:
+ dependency: transitive
+ description:
+ name: checked_yaml
+ sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.0.3"
clock:
dependency: transitive
description:
@@ -138,7 +186,7 @@ packages:
source: hosted
version: "1.18.0"
convert:
- dependency: transitive
+ dependency: "direct main"
description:
name: convert
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
@@ -189,10 +237,10 @@ packages:
dependency: transitive
description:
name: ffi
- sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
+ sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev"
source: hosted
- version: "2.1.2"
+ version: "2.1.0"
file:
dependency: "direct dev"
description:
@@ -238,6 +286,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.1.4"
+ flutter_blue_plus:
+ dependency: "direct main"
+ description:
+ name: flutter_blue_plus
+ sha256: "9419ca515ddcbe19a87fa2c45df97833d258c939b0e39ee2f38688a6c1fdbfde"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.32.4"
flutter_lints:
dependency: "direct dev"
description:
@@ -255,10 +311,10 @@ packages:
dependency: "direct main"
description:
name: flutter_markdown
- sha256: cb44f7831b23a6bdd0f501718b0d2e8045cbc625a15f668af37ddb80314821db
+ sha256: "5b24061317f850af858ef7151dadbb6eb77c1c449c954c7bb064e8a5e0e7d81f"
url: "https://pub.dev"
source: hosted
- version: "0.6.21"
+ version: "0.6.20"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
@@ -267,14 +323,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.17"
- flutter_reactive_ble:
- dependency: "direct main"
- description:
- name: flutter_reactive_ble
- sha256: "247e2efa76de203d1ba11335c13754b5b9d0504b5423e5b0c93a600f016b24e0"
- url: "https://pub.dev"
- source: hosted
- version: "5.3.1"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -301,6 +349,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.4.1"
+ frontend_server_client:
+ dependency: transitive
+ description:
+ name: frontend_server_client
+ sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.0"
function_tree:
dependency: "direct main"
description:
@@ -309,14 +365,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.9.1"
- functional_data:
- dependency: transitive
- description:
- name: functional_data
- sha256: aefdec4365452283b2a7cf420a3169654d51d3e9553069a22d76680d7a9d7c3d
- url: "https://pub.dev"
- source: hosted
- version: "1.1.1"
glob:
dependency: transitive
description:
@@ -325,6 +373,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.2"
+ graphs:
+ dependency: transitive
+ description:
+ name: graphs
+ sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.3.1"
health_data_store:
dependency: "direct main"
description:
@@ -336,10 +392,18 @@ packages:
dependency: transitive
description:
name: http
- sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
+ sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
url: "https://pub.dev"
source: hosted
- version: "1.2.1"
+ version: "1.2.0"
+ http_multi_server:
+ dependency: transitive
+ description:
+ name: http_multi_server
+ sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "3.2.1"
http_parser:
dependency: transitive
description:
@@ -364,6 +428,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.18.1"
+ io:
+ dependency: transitive
+ description:
+ name: io
+ sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
js:
dependency: transitive
description:
@@ -388,30 +460,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.8.1"
- leak_tracker:
- dependency: transitive
- description:
- name: leak_tracker
- sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
- url: "https://pub.dev"
- source: hosted
- version: "10.0.4"
- leak_tracker_flutter_testing:
- dependency: transitive
- description:
- name: leak_tracker_flutter_testing
- sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.3"
- leak_tracker_testing:
- dependency: transitive
- description:
- name: leak_tracker_testing
- sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
- url: "https://pub.dev"
- source: hosted
- version: "3.0.1"
lints:
dependency: transitive
description:
@@ -440,26 +488,34 @@ packages:
dependency: transitive
description:
name: matcher
- sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
+ sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
- version: "0.12.16+1"
+ version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
- sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
+ sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
- version: "0.8.0"
+ version: "0.5.0"
meta:
dependency: transitive
description:
name: meta
- sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
+ sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev"
source: hosted
- version: "1.12.0"
+ version: "1.10.0"
+ mime:
+ dependency: transitive
+ description:
+ name: mime
+ sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.5"
mockito:
dependency: "direct dev"
description:
@@ -504,10 +560,10 @@ packages:
dependency: "direct main"
description:
name: path
- sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+ sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
url: "https://pub.dev"
source: hosted
- version: "1.9.0"
+ version: "1.8.3"
path_parsing:
dependency: transitive
description:
@@ -628,14 +684,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.7.4"
- protobuf:
+ pool:
dependency: transitive
description:
- name: protobuf
- sha256: "01dd9bd0fa02548bf2ceee13545d4a0ec6046459d847b6b061d8a27237108a08"
+ name: pool
+ sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
- version: "2.1.0"
+ version: "1.5.1"
provider:
dependency: "direct main"
description:
@@ -652,30 +708,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
- qr:
+ pubspec_parse:
dependency: transitive
description:
- name: qr
- sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
+ name: pubspec_parse
+ sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367
url: "https://pub.dev"
source: hosted
- version: "3.0.1"
- reactive_ble_mobile:
- dependency: transitive
- description:
- name: reactive_ble_mobile
- sha256: "9ec2b4c9c725e439950838d551579750060258fbccd5536d0543b4d07d225798"
- url: "https://pub.dev"
- source: hosted
- version: "5.3.1"
- reactive_ble_platform_interface:
+ version: "1.2.3"
+ qr:
dependency: transitive
description:
- name: reactive_ble_platform_interface
- sha256: "632c92401a2d69c9b94bd48f8fd47488a7013f3d1f9b291884350291a4a81813"
+ name: qr
+ sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
url: "https://pub.dev"
source: hosted
- version: "5.3.1"
+ version: "3.0.1"
restart_app:
dependency: "direct main"
description:
@@ -728,10 +776,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
- sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
+ sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
url: "https://pub.dev"
source: hosted
- version: "2.3.0"
+ version: "2.2.2"
shared_preferences_windows:
dependency: transitive
description:
@@ -740,6 +788,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.3.2"
+ shelf:
+ dependency: transitive
+ description:
+ name: shelf
+ sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.4.1"
+ shelf_web_socket:
+ dependency: transitive
+ description:
+ name: shelf_web_socket
+ sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.4"
sky_engine:
dependency: transitive
description: flutter
@@ -817,6 +881,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.2"
+ stream_transform:
+ dependency: transitive
+ description:
+ name: stream_transform
+ sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.1.0"
string_scanner:
dependency: transitive
description:
@@ -845,10 +917,18 @@ packages:
dependency: transitive
description:
name: test_api
- sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
+ sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
- version: "0.7.0"
+ version: "0.6.1"
+ timing:
+ dependency: transitive
+ description:
+ name: timing
+ sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.1"
translations_cleaner:
dependency: "direct dev"
description:
@@ -885,10 +965,10 @@ packages:
dependency: transitive
description:
name: url_launcher_ios
- sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5"
+ sha256: "75bb6fe3f60070407704282a2d295630cab232991eb52542b18347a8a941df03"
url: "https://pub.dev"
source: hosted
- version: "6.2.5"
+ version: "6.2.4"
url_launcher_linux:
dependency: transitive
description:
@@ -917,10 +997,10 @@ packages:
dependency: transitive
description:
name: url_launcher_web
- sha256: "3692a459204a33e04bc94f5fb91158faf4f2c8903281ddd82915adecdb1a901d"
+ sha256: fff0932192afeedf63cdd50ecbb1bc825d31aed259f02bb8dba0f3b729a5e88b
url: "https://pub.dev"
source: hosted
- version: "2.3.0"
+ version: "2.2.3"
url_launcher_windows:
dependency: transitive
description:
@@ -937,14 +1017,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.4"
- vm_service:
- dependency: transitive
- description:
- name: vm_service
- sha256: a2662fb1f114f4296cf3f5a50786a2d888268d7776cf681aa17d660ffa23b246
- url: "https://pub.dev"
- source: hosted
- version: "14.0.0"
watcher:
dependency: transitive
description:
@@ -957,18 +1029,26 @@ packages:
dependency: transitive
description:
name: web
- sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
+ sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
- version: "0.5.1"
+ version: "0.3.0"
+ web_socket_channel:
+ dependency: transitive
+ description:
+ name: web_socket_channel
+ sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b
+ url: "https://pub.dev"
+ source: hosted
+ version: "2.4.0"
win32:
dependency: transitive
description:
name: win32
- sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
+ sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8"
url: "https://pub.dev"
source: hosted
- version: "5.3.0"
+ version: "5.2.0"
xdg_directories:
dependency: transitive
description:
@@ -994,5 +1074,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
- dart: ">=3.3.0 <4.0.0"
- flutter: ">=3.19.0"
+ dart: ">=3.2.0 <4.0.0"
+ flutter: ">=3.16.0"
app/pubspec.yaml
@@ -29,8 +29,9 @@ dependencies:
path: ../health_data_store/
sqlparser: ^0.34.1
flutter_bloc: ^8.1.4
- flutter_reactive_ble: ^5.3.1
permission_handler: ^11.3.1
+ convert: ^3.1.1
+ flutter_blue_plus: ^1.32.4
# can become one custom dependency
file_picker: ^5.2.11 # MIT
@@ -46,6 +47,7 @@ dev_dependencies:
mockito: ^5.4.1
sqflite_common_ffi: ^2.3.0
translations_cleaner: ^0.0.5
+ build_runner: ^2.4.9
flutter:
uses-material-design: true
health_data_store/pubspec.yaml
@@ -4,7 +4,7 @@ version: 0.1.0+1
publish_to: none
environment:
- sdk: "^3.3.0"
+ sdk: '>=3.0.2 <4.0.0'
dependencies:
freezed_annotation: ^2.4.1