Commit 6bb99f1

derdilla <82763757+NobodyForNothing@users.noreply.github.com>
2024-03-31 21:35:11
polish ble input
Signed-off-by: derdilla <82763757+NobodyForNothing@users.noreply.github.com>
1 parent 4fa74eb
Changed files (4)
app/lib/components/ble_input/ble_input.dart
@@ -6,94 +6,112 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
 
+/// An interactive way to add measurements over bluetooth.
 class BleInput extends StatelessWidget{
-  final bloc = BleInputBloc();
-
+  /// Create an interactive bluetooth measurement adder.
   BleInput({super.key});
 
+  final _bloc = BleInputBloc();
+
   @override
-  Widget build(BuildContext context) => BlocBuilder<BleInputBloc, BleInputState>(
-    bloc: bloc,
-    builder: (BuildContext context, BleInputState state) {
-      final localizations = AppLocalizations.of(context)!;
-      return switch (state) {
-        BleInputClosed() => IconButton(
-          icon: const Icon(Icons.bluetooth),
-          onPressed: () => bloc.add(BleInputOpened()),
-        ),
-        BleInputLoadInProgress() => _buildTwoElementCard(context,
-          const CircularProgressIndicator(),
-          Text(localizations.scanningDevices),
-        ),
-        BleInputLoadFailure() => _buildTwoElementCard(context,
-          const Icon(Icons.bluetooth_disabled),
-           Text('Failed loading input devices. Ensure the app has all neccessary permissions.'),
-          onTap: () => bloc.add(BleInputOpened()),
-        ),
-        BleInputLoadSuccess() => state.availableDevices.isEmpty // TODO: card
-          ? Text('No compatible BLE GATT devices found.')
-          : ListView.builder(
+  Widget build(BuildContext context) => SizeChangedLayoutNotifier(
+    child: BlocBuilder<BleInputBloc, BleInputState>(
+      bloc: _bloc,
+      builder: (BuildContext context, BleInputState state) {
+        final localizations = AppLocalizations.of(context)!;
+        return switch (state) {
+          BleInputClosed() => IconButton(
+            icon: const Icon(Icons.bluetooth),
+            onPressed: () => _bloc.add(OpenBleInput()),
+          ),
+          BleInputLoadInProgress() => _buildTwoElementCard(context,
+            const CircularProgressIndicator(),
+            Text(localizations.scanningDevices),
+          ),
+          BleInputLoadFailure() => _buildTwoElementCard(context,
+            const Icon(Icons.bluetooth_disabled),
+            Text(localizations.errBleCantOpen),
+            onTap: () => _bloc.add(OpenBleInput()),
+          ),
+          BleInputLoadSuccess() => state.availableDevices.isEmpty
+              ? _buildTwoElementCard(context,
+            const Icon(Icons.info),
+            Text(localizations.errBleNoDev),
+            onTap: () => _bloc.add(OpenBleInput()),
+          ) : _buildMainCard(context, ListView.builder(
             itemCount: state.availableDevices.length,
             itemBuilder: (context, idx) => ListTile(
               title: Text(state.availableDevices[idx].name),
               trailing: state.availableDevices[idx].connectable == Connectable.available
-                ? Icon(Icons.bluetooth_audio)
-                : Icon(Icons.bluetooth_disabled),
-              onTap: () => bloc.add(BleInputDeviceSelected(state.availableDevices[idx])),
+                  ? const Icon(Icons.bluetooth_audio)
+                  : const Icon(Icons.bluetooth_disabled),
+              onTap: () => _bloc.add(BleInputDeviceSelected(state.availableDevices[idx])),
             ),
+          ),),
+          BleInputPermissionFailure() => _buildTwoElementCard(context,
+            const Icon(Icons.bluetooth_disabled),
+            Text(localizations.errBleNoPerms),
+            onTap: () => _bloc.add(OpenBleInput()),
           ),
-        BleInputPermissionFailure() => _buildTwoElementCard(context,
-          const Icon(Icons.bluetooth_disabled),
-          Text('Permissions error. Please allow all bluetooth permissions.'
-              ' You also need the location permission on pre-Android 12 devices.'),
-          onTap: () => bloc.add(BleInputOpened()),
-        ),
-        BleConnectInProgress() => _buildTwoElementCard(context,
-          const CircularProgressIndicator(),
-          Text('Connecting to bluetooth device'),
-        ),
-        BleConnectFailed() => _buildTwoElementCard(context,
-          const Icon(Icons.bluetooth_disabled),
-          Text('Connection to bluetooth device failed :('),
-          onTap: () => bloc.add(BleInputOpened()),
-        ),
-        BleConnectSuccess() => _buildTwoElementCard(context,
-          const Icon(Icons.bluetooth_connected),
-          Text('Connected to device, waiting for measurement'),
-        ),
-        BleMeasurementInProgress() => _buildTwoElementCard(context,
-          const CircularProgressIndicator(),
-          Text('Handeling incomming measurement'),
-        ),
-        BleMeasurementSuccess() => _buildTwoElementCard(context,
-          const Icon(Icons.done, color: Colors.lightGreen,),
-          Text('Recieved measurement:'
-              '\n${state.record}'
-              '\nCuff loose: ${state.cuffLoose}'
-              '\nIrregular pulse: ${state.irregularPulse}'
-              '\nBody moved: ${state.bodyMoved}'
-              '\nWrong measurement position: ${state.improperMeasurementPosition}'
-              '\nMeasurement status: ${state.measurementStatus}'
+          BleConnectInProgress() => _buildTwoElementCard(context,
+            const CircularProgressIndicator(),
+            Text(localizations.bleConnecting),
           ),
-        ),
-      };
-    },
+          BleConnectFailed() => _buildTwoElementCard(context,
+            const Icon(Icons.bluetooth_disabled),
+            Text(localizations.errBleCouldNotConnect),
+            onTap: () => _bloc.add(OpenBleInput()),
+          ),
+          BleConnectSuccess() => _buildTwoElementCard(context,
+            const Icon(Icons.bluetooth_connected),
+            Text(localizations.bleConnected),
+          ),
+          BleMeasurementInProgress() => _buildTwoElementCard(context,
+            const CircularProgressIndicator(),
+            Text(localizations.bleProcessing),
+          ),
+          BleMeasurementSuccess() => _buildTwoElementCard(context,
+            const Icon(Icons.done, color: Colors.lightGreen,),
+            Text('Received measurement:' // TODO: rework this process
+                '\n${state.record}'
+                '\nCuff loose: ${state.cuffLoose}'
+                '\nIrregular pulse: ${state.irregularPulse}'
+                '\nBody moved: ${state.bodyMoved}'
+                '\nWrong measurement position: ${state.improperMeasurementPosition}'
+                '\nMeasurement status: ${state.measurementStatus}'
+            ),
+          ),
+        };
+      },
+    ),
   );
-  // TODO: add method for quitting
 
-  /// Wrap open connection menu in card.
-  Widget _buildMainCard(BuildContext context, Widget child) => Container(
-    decoration: BoxDecoration(
-      color: Theme.of(context).cardColor,
-      borderRadius: BorderRadius.circular(24),
-    ),
-    width: MediaQuery.of(context).size.width,
-    height: MediaQuery.of(context).size.width,
-    padding: const EdgeInsets.all(24),
+  /// Builds the container used when input is open.
+  Widget _buildMainCard(BuildContext context, Widget child) => Card.outlined(
+    color: Theme.of(context).cardColor,
+    // borderRadius: BorderRadius.circular(24),
+    // width: MediaQuery.of(context).size.width,
+    // height: MediaQuery.of(context).size.width,
+    // padding: const EdgeInsets.all(24),
     margin: const EdgeInsets.all(8),
-    child: child,
+    child: Stack(
+      children: [
+        Padding( // content
+          padding: const EdgeInsets.all(24),
+          child: child,
+        ),
+        Align(
+          alignment: Alignment.topRight,
+          child: IconButton(
+            icon: const Icon(Icons.close),
+            onPressed: () => _bloc.add(CloseBleInput()),
+          ),
+        ),
+      ],
+    ),
   );
 
+  /// Builds the full card but with two centered elements.
   Widget _buildTwoElementCard(
     BuildContext context,
     Widget top,
@@ -106,6 +124,6 @@ class BleInput extends StatelessWidget{
         mainAxisAlignment: MainAxisAlignment.center,
         children: [top, const SizedBox(height: 8,), bottom,],
       ),
-    )),
+    ),),
   );
 }
app/lib/components/ble_input/ble_input_bloc.dart
@@ -19,7 +19,12 @@ class BleInputBloc extends Bloc<BleInputEvent, BleInputState> {
   // TODO: use repo
 
   BleInputBloc(): super(BleInputClosed()) {
-    on<BleInputOpened>((event, emit) async {
+    on<CloseBleInput>((event, emit) async {
+      emit(BleInputClosed());
+      // TODO: perform needed cleanup
+    });
+
+    on<OpenBleInput>((event, emit) async {
       /* testing widget
       emit(BleMeasurementSuccess(BloodPressureRecord(DateTime.now(), 123, 456, 578, 'test'),
         bodyMoved: null,
app/lib/components/ble_input/ble_input_events.dart
@@ -3,7 +3,11 @@ import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
 
 sealed class BleInputEvent {}
 
-class BleInputOpened extends BleInputEvent {}
+/// Request expanding the input field.
+class OpenBleInput extends BleInputEvent {}
+
+/// Request closing the input field.
+class CloseBleInput extends BleInputEvent {}
 
 class BleInputDeviceSelected extends BleInputEvent {
   BleInputDeviceSelected(this.device);
app/lib/l10n/app_en.arb
@@ -508,5 +508,19 @@
   "preferredPressureUnit": "Preferred pressure unit",
   "@preferredPressureUnit": {},
   "scanningDevices": "Scanning for devices...",
-  "@scanningDevices": {}
+  "@scanningDevices": {},
+  "errBleCantOpen": "Failed loading input devices. Ensure the app has all necessary permissions and report this issue in case it persists.",
+  "@errBleCantOpen": {},
+  "errBleNoDev": "No compatible BLE GATT devices found. Tap to refresh!",
+  "@errBleNoDev": {},
+  "errBleNoPerms": "Permissions error. Please allow all bluetooth permissions. On pre-Android 12 devices the location permission is required.",
+  "@errBleNoPerms": {},
+  "errBleCouldNotConnect": "Connection to bluetooth device failed. Tap to restart.",
+  "@errBleCouldNotConnect": {},
+  "bleConnecting": "Connecting to bluetooth device...",
+  "@bleConnecting": {},
+  "bleConnected": "Connected to device. Waiting for measurement...",
+  "@bleConnected": {},
+  "bleProcessing": "Processing incoming measurement...",
+  "@bleProcessing": {}
 }