From 5184c63f665f6b3b561b62ed9cbd8d02466867fd Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 7 Feb 2023 00:26:09 +0500 Subject: [PATCH] feat: add `bluetooth controlled` robot operations --- lib/screens/remote/cubit/remote_cubit.dart | 63 ++++------ lib/screens/remote/cubit/remote_state.dart | 16 +-- lib/screens/remote/remote_screen.dart | 136 ++++++++++++++------- 3 files changed, 121 insertions(+), 94 deletions(-) diff --git a/lib/screens/remote/cubit/remote_cubit.dart b/lib/screens/remote/cubit/remote_cubit.dart index 8a73d8e..a1537bd 100644 --- a/lib/screens/remote/cubit/remote_cubit.dart +++ b/lib/screens/remote/cubit/remote_cubit.dart @@ -1,3 +1,5 @@ +// ignore_for_file: constant_identifier_names + import 'dart:convert'; import 'package:bloc/bloc.dart'; import 'package:flutter/foundation.dart'; @@ -6,52 +8,39 @@ import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; part 'remote_state.dart'; class RemoteCubit extends Cubit { - RemoteCubit() : super(OffSignal()); + RemoteCubit() : super(Initial(status: false, message: 'WAITING')); + + static const String FORWARD = 'F'; + static const String BACKWARD = 'B'; + static const String LEFT = 'L'; + static const String RIGHT = 'R'; BluetoothDevice? device; + BluetoothConnection? _connection; - Future onMessage(BluetoothDevice device) async { + Future connect(BluetoothDevice device) async { emit(Loading()); + _connection = await BluetoothConnection.toAddress(device.address); + emit(Initial(status: _connection!.isConnected, message: 'WAITING')); + } + void moveForward() { + _connection!.output.add(Uint8List.fromList(utf8.encode(FORWARD))); + emit(Initial(status: _connection!.isConnected, message: FORWARD)); + } - /** - * Wrote test cases, have tested - * on real devices. Wrote an external server script to - * this library and even did some changes to library's - * java source code for testing purpose. Still no luck... :( - * - * Culprit code is below that establishes connection - * between devices... - */ - BluetoothConnection con = - await BluetoothConnection.toAddress(device.address); - - - - con.output.add(Uint8List.fromList(utf8.encode('Hello'))); - con.dispose(); - listenResponse(device); - emit(OnSignal()); + void moveBackward() { + _connection!.output.add(Uint8List.fromList(utf8.encode(BACKWARD))); + emit(Initial(status: _connection!.isConnected, message: BACKWARD)); } - Future offMessage(BluetoothDevice device) async { - emit(Loading()); - BluetoothConnection con = - await BluetoothConnection.toAddress(device.address); - con.output.add(Uint8List.fromList(utf8.encode('World'))); - con.dispose(); - emit(OffSignal()); + void moveLeft() { + _connection!.output.add(Uint8List.fromList(utf8.encode(LEFT))); + emit(Initial(status: _connection!.isConnected, message: LEFT)); } - Future listenResponse(BluetoothDevice device) async { - emit(Loading()); - BluetoothConnection con = - await BluetoothConnection.toAddress(device.address); - con.input!.listen((event) { - ascii.decode(event); - }).onDone(() { - con.dispose(); - emit(OffSignal()); - }); + void moveRight() { + _connection!.output.add(Uint8List.fromList(utf8.encode(RIGHT))); + emit(Initial(status: _connection!.isConnected, message: RIGHT)); } } diff --git a/lib/screens/remote/cubit/remote_state.dart b/lib/screens/remote/cubit/remote_state.dart index 9c99d4f..d57b5fb 100644 --- a/lib/screens/remote/cubit/remote_state.dart +++ b/lib/screens/remote/cubit/remote_state.dart @@ -2,16 +2,10 @@ part of 'remote_cubit.dart'; abstract class RemoteState {} -class Initial extends RemoteState {} +class Initial extends RemoteState { + final bool? status; + final String? message; + Initial({this.status, this.message}); +} class Loading extends RemoteState {} - -class OnSignal extends RemoteState {} - -class OffSignal extends RemoteState {} - -class ListenResponse extends RemoteState { - final String message; - - ListenResponse(this.message); -} diff --git a/lib/screens/remote/remote_screen.dart b/lib/screens/remote/remote_screen.dart index 3f050d2..9ba7d99 100644 --- a/lib/screens/remote/remote_screen.dart +++ b/lib/screens/remote/remote_screen.dart @@ -1,22 +1,35 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; import 'package:remo_tooth/screens/remote/cubit/remote_cubit.dart'; -class RemoteScreen extends StatelessWidget { +class RemoteScreen extends StatefulWidget { final BluetoothDevice device; const RemoteScreen({super.key, required this.device}); + @override + State createState() => _RemoteScreenState(); +} + +class _RemoteScreenState extends State { + @override + void initState() { + () async { + await BlocProvider.of(context).connect(widget.device); + }(); + super.initState(); + } + @override Widget build(BuildContext context) { var event = BlocProvider.of(context); var mediaQuery = MediaQuery.of(context); var theme = Theme.of(context); - var message = '0'; return Scaffold( appBar: AppBar( - title: Text(device.name!), + title: Text(widget.device.name!), actions: [ PopupMenuButton( itemBuilder: (context) { @@ -35,35 +48,50 @@ class RemoteScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - BlocConsumer( - listener: (context, state) { - if (state is ListenResponse) { - message = state.message; - } - }, - builder: (context, state) { - if (state is Loading) { - return FloatingActionButton.large( - child: const CircularProgressIndicator(), - onPressed: () => event.onMessage(device), - ); - } else if (state is OnSignal) { - return FloatingActionButton.large( - foregroundColor: - const Color.fromARGB(255, 131, 78, 255), - child: const Icon(Icons.power_settings_new_rounded), - onPressed: () => event.offMessage(device), - ); - } else if (state is OffSignal) { - return FloatingActionButton.large( - child: const Icon(Icons.power_settings_new_rounded), - onPressed: () => event.onMessage(device), - ); - } else { - return Container(); - } - }, - ) + Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + OutlinedButton( + style: ButtonStyle( + overlayColor: MaterialStateProperty.all(Colors.blue), + ), + child: const Icon(Icons.arrow_circle_up_rounded), + onPressed: () async { + event.moveForward(); + await HapticFeedback.heavyImpact(); + }, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + OutlinedButton( + style: ButtonStyle( + overlayColor: + MaterialStateProperty.all(Colors.blue), + ), + child: const Icon(Icons.arrow_circle_left_outlined), + onPressed: () => event.moveLeft(), + ), + OutlinedButton( + style: ButtonStyle( + overlayColor: + MaterialStateProperty.all(Colors.blue), + ), + child: + const Icon(Icons.arrow_circle_right_outlined), + onPressed: () => event.moveRight(), + ), + ], + ), + OutlinedButton( + style: ButtonStyle( + overlayColor: MaterialStateProperty.all(Colors.blue), + ), + child: const Icon(Icons.arrow_circle_down_rounded), + onPressed: () => event.moveBackward(), + ), + ], + ), ], ), ), @@ -82,20 +110,36 @@ class RemoteScreen extends StatelessWidget { ), ), child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('Console Log:', style: theme.textTheme.labelLarge), - SizedBox(height: mediaQuery.size.height / 150), - Text('Device: ${device.name}', - style: theme.textTheme.labelMedium), - Text('Connected: ${device.isConnected}', - style: theme.textTheme.labelMedium), - Text('MAC: ${device.address}', - style: theme.textTheme.labelMedium), - Text('Signal Status: $message', - style: theme.textTheme.labelSmall), - ], + child: BlocBuilder( + builder: (context, state) { + if (state is Loading) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + children: const [ + LinearProgressIndicator(), + ], + ); + } else if (state is Initial) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Console Log:', + style: theme.textTheme.labelLarge), + SizedBox(height: mediaQuery.size.height / 150), + Text('Device: ${widget.device.name}', + style: theme.textTheme.labelMedium), + Text('Connected: ${state.status}', + style: theme.textTheme.labelMedium), + Text('MAC: ${widget.device.address}', + style: theme.textTheme.labelMedium), + Text('Operation Status: ${state.message}', + style: theme.textTheme.labelSmall), + ], + ); + } + + return Container(); + }, ), ), ),