diff --git a/android/robot/src/main/java/org/openbot/autopilot/AutopilotFragment.java b/android/robot/src/main/java/org/openbot/autopilot/AutopilotFragment.java index 2754a88d8..f88283d53 100644 --- a/android/robot/src/main/java/org/openbot/autopilot/AutopilotFragment.java +++ b/android/robot/src/main/java/org/openbot/autopilot/AutopilotFragment.java @@ -589,4 +589,3 @@ private void disconnectPhoneController() { binding.controllerContainer.driveMode.setAlpha(1.0f); } } - diff --git a/android/robot/src/main/java/org/openbot/env/SharedPreferencesManager.java b/android/robot/src/main/java/org/openbot/env/SharedPreferencesManager.java index 2d476440d..7eb5e79aa 100644 --- a/android/robot/src/main/java/org/openbot/env/SharedPreferencesManager.java +++ b/android/robot/src/main/java/org/openbot/env/SharedPreferencesManager.java @@ -1,5 +1,6 @@ package org.openbot.env; +import android.app.Fragment; import android.content.Context; import android.content.SharedPreferences; import com.google.common.reflect.TypeToken; @@ -43,6 +44,9 @@ public class SharedPreferencesManager { private static final String DELAY = "DELAY"; private static final String PROJECTS_LIST = "PROJECTS_LIST"; + private static final String FRAGMENT_TYPE = "FRAGMENT_TYPE"; + + private final SharedPreferences preferences; public SharedPreferencesManager(Context context) { @@ -51,6 +55,11 @@ public SharedPreferencesManager(Context context) { .getApplicationContext() .getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE); } + public String getFragment(){return preferences.getString(FRAGMENT_TYPE, "" );} + public void setFragment(String fragment) + { + preferences.edit().putString(FRAGMENT_TYPE, fragment).apply(); + } public int getBaudrate() { return preferences.getInt(BAUD_RATE, DEFAULT_BAUD_RATE); diff --git a/android/robot/src/main/java/org/openbot/env/WebRtcServer.java b/android/robot/src/main/java/org/openbot/env/WebRtcServer.java index e3b0a6fcc..d7339f209 100644 --- a/android/robot/src/main/java/org/openbot/env/WebRtcServer.java +++ b/android/robot/src/main/java/org/openbot/env/WebRtcServer.java @@ -127,6 +127,7 @@ public void startClient() { @Override public void sendServerUrl() { BotToControllerEventBus.emitEvent(ConnectionUtils.createStatus("VIDEO_SERVER_URL", "")); + BotToControllerEventBus.emitEvent(ConnectionUtils.createFragment("")); } @Override @@ -369,7 +370,6 @@ public void onTrack(RtpTransceiver transceiver) {} return factory.createPeerConnection(rtcConfig, pcConstraints, pcObserver); } - private void sendMessage(JSONObject message) { BotToControllerEventBus.emitEvent(ConnectionUtils.createStatus("WEB_RTC_EVENT", message)); } diff --git a/android/robot/src/main/java/org/openbot/logging/LoggerFragment.java b/android/robot/src/main/java/org/openbot/logging/LoggerFragment.java index 1a6741c93..2d54e7627 100644 --- a/android/robot/src/main/java/org/openbot/logging/LoggerFragment.java +++ b/android/robot/src/main/java/org/openbot/logging/LoggerFragment.java @@ -85,6 +85,8 @@ public View onCreateView( @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + preferencesManager.setFragment(Enums.fragmentType.DATACOLLECTION.getFragment()); + BotToControllerEventBus.emitEvent(ConnectionUtils.createFragment(preferencesManager.getFragment())); binding.controllerContainer.speedInfo.setText(getString(R.string.speedInfo, "---,---")); intentSensorService = new Intent(requireActivity(), SensorService.class); diff --git a/android/robot/src/main/java/org/openbot/objectNav/ObjectNavFragment.java b/android/robot/src/main/java/org/openbot/objectNav/ObjectNavFragment.java index 4729cf253..e62c32be9 100644 --- a/android/robot/src/main/java/org/openbot/objectNav/ObjectNavFragment.java +++ b/android/robot/src/main/java/org/openbot/objectNav/ObjectNavFragment.java @@ -33,12 +33,14 @@ import org.openbot.common.CameraFragment; import org.openbot.databinding.FragmentObjectNavBinding; import org.openbot.env.BorderedText; +import org.openbot.env.BotToControllerEventBus; import org.openbot.env.ImageUtils; import org.openbot.tflite.Detector; import org.openbot.tflite.Model; import org.openbot.tflite.Network; import org.openbot.tracking.MultiBoxTracker; import org.openbot.utils.CameraUtils; +import org.openbot.utils.ConnectionUtils; import org.openbot.utils.Constants; import org.openbot.utils.Enums; import org.openbot.utils.MovingAverage; @@ -97,9 +99,9 @@ public View onCreateView( @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - + preferencesManager.setFragment(Enums.fragmentType.OBJECTDETECTION.getFragment()); + BotToControllerEventBus.emitEvent(ConnectionUtils.createFragment(preferencesManager.getFragment())); binding.confidenceValue.setText((int) (MINIMUM_CONFIDENCE_TF_OD_API * 100) + "%"); - binding.plusConfidence.setOnClickListener( v -> { String trimConfValue = binding.confidenceValue.getText().toString().trim(); diff --git a/android/robot/src/main/java/org/openbot/robot/FreeRoamFragment.java b/android/robot/src/main/java/org/openbot/robot/FreeRoamFragment.java index b41667d26..88505c72b 100644 --- a/android/robot/src/main/java/org/openbot/robot/FreeRoamFragment.java +++ b/android/robot/src/main/java/org/openbot/robot/FreeRoamFragment.java @@ -20,7 +20,9 @@ import org.openbot.R; import org.openbot.common.ControlsFragment; import org.openbot.databinding.FragmentFreeRoamBinding; +import org.openbot.env.BotToControllerEventBus; import org.openbot.env.PhoneController; +import org.openbot.utils.ConnectionUtils; import org.openbot.utils.Constants; import org.openbot.utils.Enums; import org.openbot.utils.PermissionUtils; @@ -45,6 +47,10 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat phoneController = PhoneController.getInstance(requireContext()); + preferencesManager.setFragment(Enums.fragmentType.FREEROAM.getFragment()); + + BotToControllerEventBus.emitEvent(ConnectionUtils.createFragment(preferencesManager.getFragment())); + binding.voltageInfo.setText(getString(R.string.voltageInfo, "--.-")); binding.controllerContainer.speedInfo.setText(getString(R.string.speedInfo, "---,---")); binding.sonarInfo.setText(getString(R.string.distanceInfo, "---")); diff --git a/android/robot/src/main/java/org/openbot/utils/ConnectionUtils.java b/android/robot/src/main/java/org/openbot/utils/ConnectionUtils.java index c45d0facf..2f1f62e1d 100644 --- a/android/robot/src/main/java/org/openbot/utils/ConnectionUtils.java +++ b/android/robot/src/main/java/org/openbot/utils/ConnectionUtils.java @@ -24,6 +24,7 @@ public static JSONObject createStatus(String name, String value) { return new JSONObject(); } + public static JSONObject createStatus(String name, JSONObject value) { try { return new JSONObject().put("status", new JSONObject().put(name, value.toString())); @@ -33,6 +34,15 @@ public static JSONObject createStatus(String name, JSONObject value) { return new JSONObject(); } + public static JSONObject createFragment(String value){ + try { + return new JSONObject().put("FRAGMENT_TYPE", value); + } catch (JSONException e) { + e.printStackTrace(); + } + return new JSONObject(); + } + public static JSONObject getStatus( boolean loggingEnabled, boolean noiseEnabled, diff --git a/android/robot/src/main/java/org/openbot/utils/Enums.java b/android/robot/src/main/java/org/openbot/utils/Enums.java index fad69aec3..4de1b4528 100644 --- a/android/robot/src/main/java/org/openbot/utils/Enums.java +++ b/android/robot/src/main/java/org/openbot/utils/Enums.java @@ -29,6 +29,16 @@ public String getSensor() { } } + public enum fragmentType{ + AUTOPILOT("Autopilot"), + OBJECTDETECTION("ObjectDetection"), + DATACOLLECTION("DataCollection"), + FREEROAM("FreeRoam"); + private String fragmentType; + fragmentType(String fragmentType) {this.fragmentType=fragmentType;} + public String getFragment() {return fragmentType;} + } + public enum LogMode { ALL_IMGS(0), CROP_IMG(1), diff --git a/controller/flutter/README.md b/controller/flutter/README.md index 74f9c3e7c..aa801e792 100644 --- a/controller/flutter/README.md +++ b/controller/flutter/README.md @@ -10,7 +10,7 @@ This Controller app serves as a `remote controller` for the [OpenBot](https://www.openbot.org) vehicle similar as a BT controller (e.g. PS3/4 or Xbox). It runs on another Android/iOS device and supports live video/audio streaming in addition to control. - ## Getting Started +## Getting Started Begin by installing [Flutter](https://flutter.dev/) on your system. Choose the appropriate download for your operating system, which includes options for Windows, macOS, Linux, and ChromeOS. Follow the official Flutter installation guide for detailed instructions: [Flutter Installation Guide](https://docs.flutter.dev/get-started/install) ### Using Terminal @@ -22,16 +22,16 @@ Begin by installing [Flutter](https://flutter.dev/) on your system. Choose the a ```bash flutter pub get ``` - Run the project: + Run the project: ```bash flutter run ``` - If you encounter any issues, run the following command: + If you encounter any issues, run the following command: ```bash flutter doctor ``` ### Using Editor -- Follow the official Flutter guide for setting up an editor: [Set up an editor ](https://docs.flutter.dev/tools/android-studio) +- Follow the official Flutter guide for setting up an editor: [Set up an editor ](https://docs.flutter.dev/tools/android-studio) - Ensure that your editor is configured for Flutter development. Install any required plugins or extensions, following the editor-specific instructions in the Flutter documentation for the best development experience. - Once you open your project in the editor after the setup, it will appear as shown in the following image. @@ -46,7 +46,7 @@ Begin by installing [Flutter](https://flutter.dev/) on your system. Choose the a

-## Connection +## Connection When the controller app is started, it immediately tries to connect to the robot and shows the following screen: @@ -89,7 +89,7 @@ above/below the center of the slider. - ``Switch Camera``: switch between the front and back camera modes. - ``Mute``: enable/disable audio transmission. -- ``Mirror view``: mirror the the video feed. +- ``Mirror view``: mirror the the video feed. ### Tilt to drive @@ -112,4 +112,18 @@ Use the `accelerator` and `brake` buttons to move forward/backward. robot will come to a stop. - The robot is steered by tilting the controller phone left or right. +### Controller Settings UI + +Here is a picture of the `Controller Settings` screen: + +- Controller Selection: Switch between different controller types (e.g., mobile, joystick) using the provided icons. + +- Server: Displays the current server status with a dropdown to select or change the server. + +- Noise Toggle : Enable or disable noise simulation through the toggle switch. + +

+ +

+ Here is a [Technical Overview](../../docs/technical/OpenBotController.pdf) of the controller app. diff --git a/controller/flutter/android/build.gradle b/controller/flutter/android/build.gradle index 3cdaac958..6617c1e94 100644 --- a/controller/flutter/android/build.gradle +++ b/controller/flutter/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.6.10' + ext.kotlin_version = '1.7.0' repositories { google() mavenCentral() diff --git a/controller/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/controller/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md index e005bfba8..5ddcaf2b4 100644 --- a/controller/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ b/controller/flutter/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -10,4 +10,4 @@ You can customize the launch screen with your own desired assets by replacing the image files in this directory. -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/controller/flutter/lib/screens/component/onScreenIcon.dart b/controller/flutter/lib/screens/component/onScreenIcon.dart index d3b3cb40f..d304c4d5c 100644 --- a/controller/flutter/lib/screens/component/onScreenIcon.dart +++ b/controller/flutter/lib/screens/component/onScreenIcon.dart @@ -2,15 +2,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; import 'package:openbot_controller/buttonCommands/buttonCommands.dart'; import 'package:openbot_controller/screens/component/blinkingButton.dart'; +import 'package:openbot_controller/globals.dart'; class OnScreenIcon extends StatefulWidget { final dynamic updateMirrorView; final bool indicatorLeft; final bool indicatorRight; final RTCPeerConnection? peerConnection; + final String fragmentType; const OnScreenIcon(this.updateMirrorView, this.indicatorLeft, - this.indicatorRight, this.peerConnection, + this.indicatorRight, this.peerConnection, this.fragmentType, {super.key}); @override @@ -24,6 +26,7 @@ class OnScreenIconState extends State { bool speaker = false; bool leftIndicator = false; bool rightIndicator = false; + String typeOfFragment = ""; @override void didUpdateWidget(covariant OnScreenIcon oldWidget) { @@ -31,6 +34,7 @@ class OnScreenIconState extends State { setState(() { leftIndicator = widget.indicatorLeft; rightIndicator = widget.indicatorRight; + typeOfFragment = widget.fragmentType; }); super.didUpdateWidget(oldWidget); } @@ -186,6 +190,52 @@ class OnScreenIconState extends State { width: 23, ), )), + const SizedBox( + width: 15, + ), + GestureDetector( + onTap: () { + if (typeOfFragment == "DataCollection") { + clientSocket?.writeln("{command: LOGS}"); + } + }, // Image tapped + child: Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(45), + color: typeOfFragment == "DataCollection" + ? Colors.white.withOpacity(0.5) + : Colors.grey.withOpacity(0.5), + ), + child: const Icon( + Icons.file_present, + color: Colors.blue, + ), + )), + const SizedBox( + width: 15, + ), + GestureDetector( + onTap: () { + if (typeOfFragment == "Autopilot" || + typeOfFragment == "ObjectDetection") { + clientSocket?.writeln("{command: NETWORK}"); + } + }, // Image tapped + child: Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(45), + color: typeOfFragment == "Autopilot" || + typeOfFragment == "ObjectDetection" + ? Colors.white.withOpacity(0.5) + : Colors.grey.withOpacity(0.5), + ), + child: const Icon( + Icons.network_check, + color: Colors.blue, + ), + )), ], ), ); diff --git a/controller/flutter/lib/screens/controlSelector.dart b/controller/flutter/lib/screens/controlSelector.dart index f45e11193..e3cee1f07 100644 --- a/controller/flutter/lib/screens/controlSelector.dart +++ b/controller/flutter/lib/screens/controlSelector.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:nsd/nsd.dart'; -import 'package:openbot_controller/globals.dart'; import 'package:openbot_controller/screens/tiltingPhoneMode.dart'; import 'onScreenMode.dart'; @@ -13,9 +11,19 @@ class ControlSelector extends StatefulWidget { final bool indicatorRight; final List networkServices; final RTCPeerConnection? peerConnection; - - const ControlSelector(this.updateMirrorView, this.indicatorLeft, - this.indicatorRight, this.networkServices, this.peerConnection, + final bool isTiltingPhoneMode; + final bool isScreenMode; + final String fragmentType; + + const ControlSelector( + this.updateMirrorView, + this.indicatorLeft, + this.indicatorRight, + this.networkServices, + this.peerConnection, + this.isTiltingPhoneMode, + this.isScreenMode, + this.fragmentType, {super.key}); @override @@ -25,9 +33,6 @@ class ControlSelector extends StatefulWidget { } class ControlSelectorState extends State { - bool isTiltingPhoneMode = false; - bool isScreenMode = false; - // Initial Selected Value String dropDownValue = 'No server'; late List> items = []; @@ -38,359 +43,21 @@ class ControlSelectorState extends State { // items.clear(); } - // Function to generate DropdownMenuItem widgets - List> buildDropdownMenuItems() { - items = [ - DropdownMenuItem( - value: 'No server', - child: Container( - height: 30, - width: 85, - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3)), - color: Color(0xFF0071C5), - ), - alignment: Alignment.center, - child: const Text( - 'No server', - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 13, - color: Color(0xFFffffff), - ), - ), - ), - ), - ]; - items.addAll(widget.networkServices.map((discovery) { - return DropdownMenuItem( - value: discovery.name, - child: Container( - height: 30, - width: 85, - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3)), - color: Color(0xFF0071C5), - ), - alignment: Alignment.center, - child: Text( - discovery.name ?? '', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 13, - color: Color(0xFFffffff), - ), - ), - ), - ); - })); - return items; - } - @override Widget build(BuildContext context) { - if (isTiltingPhoneMode) { + if (widget.isTiltingPhoneMode) { return GestureDetector( - onDoubleTap: () { - setState(() { - isTiltingPhoneMode = false; - }); - }, - child: const TiltingPhoneMode()); - } else if (isScreenMode) { + child: TiltingPhoneMode(fragmentType: widget.fragmentType)); + } else if (widget.isScreenMode) { return GestureDetector( - onDoubleTap: () { - setState(() { - isScreenMode = false; - }); - }, child: OnScreenMode(widget.updateMirrorView, widget.indicatorLeft, - widget.indicatorRight, widget.peerConnection), + widget.indicatorRight, widget.peerConnection, widget.fragmentType), ); } else { - return Scaffold( - backgroundColor: Colors.transparent, - body: Center( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - GestureDetector( - onTap: () { - Fluttertoast.showToast( - msg: "Double tap on screen to get back", - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.BOTTOM, - backgroundColor: Colors.grey, - textColor: Colors.white, - fontSize: 18); - setState(() { - isScreenMode = true; - }); - }, - child: Container( - height: 180, - width: 180, - padding: const EdgeInsets.all(20), - margin: const EdgeInsets.all(20), - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10)), - color: Color(0xFF292929), - boxShadow: [ - BoxShadow( - blurRadius: 0.5, - spreadRadius: 0.1, - color: Color(0xFFffffff), - offset: Offset( - -1, - -1, - ), - ), - BoxShadow( - blurRadius: 1, - spreadRadius: 0.1, - color: Color(0xFF000000), - offset: Offset( - -1, - -1, - ), - ), - ]), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Image.asset( - "images/controller_icon.png", - height: 18, - width: 18, - ), - const SizedBox( - height: 20, - ), - const Text( - "Use On-Screen Controls to Drive", - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w500, - color: Color(0xFFffffff), - ), - ), - const SizedBox( - height: 55, - ), - Container( - alignment: Alignment.bottomRight, - child: Image.asset( - "images/arrow_icon.png", - width: 50, - ), - ), - ]), - ), - ), - GestureDetector( - onTap: () { - Fluttertoast.showToast( - msg: "Double tap on screen to get back", - toastLength: Toast.LENGTH_LONG, - gravity: ToastGravity.BOTTOM, - backgroundColor: Colors.grey, - textColor: Colors.white, - fontSize: 18); - setState(() { - isTiltingPhoneMode = true; - }); - }, - child: Container( - height: 180, - width: 180, - padding: const EdgeInsets.all(20), - margin: const EdgeInsets.all(20), - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10)), - color: Color(0xFF292929), - boxShadow: [ - BoxShadow( - blurRadius: 0.5, - spreadRadius: 0.1, - color: Color(0xFFffffff), - offset: Offset( - -1, - -1, - ), - ), - BoxShadow( - blurRadius: 1, - spreadRadius: 0.1, - color: Color(0xFF000000), - offset: Offset( - -1, - -1, - ), - ), - ]), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Image.asset( - "images/tilting_phone_icon.png", - height: 18, - width: 18, - ), - const SizedBox( - height: 20, - ), - const Text( - "Drive by tilting\nthe phone", - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w500, - color: Color(0xFFffffff), - ), - ), - const SizedBox( - height: 55, - ), - Container( - alignment: Alignment.bottomRight, - child: Image.asset( - "images/arrow_icon.png", - width: 50, - ), - ), - ]), - ), - ), - ], - ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - DropdownButton( - value: dropDownValue, - borderRadius: const BorderRadius.all(Radius.circular(3)), - underline: Container(), - dropdownColor: const Color(0xFF0071C5), - style: const TextStyle( - fontSize: 13, - color: Color(0xFFffffff), - ), - menuMaxHeight: 150, - items: buildDropdownMenuItems(), - onChanged: (String? serverName) { - setState(() { - dropDownValue = serverName!; - }); - if (serverName != "No server") { - clientSocket?.writeln("{server: $serverName}"); - } else { - clientSocket?.writeln("{server: noServerFound}"); - } - }, - ), - GestureDetector( - onTap: () { - clientSocket?.writeln("{command: LOGS}"); - }, - child: Container( - height: 30, - width: 85, - margin: const EdgeInsets.all(20), - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3)), - color: Color(0xFF0071C5), - ), - child: const Center( - child: Text( - "Logs", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 13, - color: Color(0xFFffffff), - ), - ), - ), - )), - GestureDetector( - onTap: () { - clientSocket?.writeln("{command: NOISE}"); - }, - child: Container( - height: 30, - width: 85, - margin: const EdgeInsets.all(20), - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3)), - color: Color(0xFF0071C5), - ), - child: const Center( - child: Text( - "Noise", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 13, - color: Color(0xFFffffff), - ), - ), - ), - )), - GestureDetector( - onTap: () { - clientSocket?.writeln("{command: NETWORK}"); - }, - child: Container( - height: 30, - width: 85, - margin: const EdgeInsets.all(20), - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3)), - color: Color(0xFF0071C5), - ), - child: const Center( - child: Text( - "Network", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 13, - color: Color(0xFFffffff), - ), - ), - ), - )), - GestureDetector( - onTap: () { - clientSocket?.writeln("{command: DRIVE_MODE}"); - }, - child: Container( - height: 30, - width: 85, - margin: const EdgeInsets.all(20), - decoration: const BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(3)), - color: Color(0xFF0071C5), - ), - child: const Center( - child: Text( - "Game", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 13, - color: Color(0xFFffffff), - ), - ), - ), - )), - ], - ) - ], - ))); + return GestureDetector( + child: OnScreenMode(widget.updateMirrorView, widget.indicatorLeft, + widget.indicatorRight, widget.peerConnection, widget.fragmentType), + ); } } -} +} \ No newline at end of file diff --git a/controller/flutter/lib/screens/controller.dart b/controller/flutter/lib/screens/controller.dart index fc07cd040..9ad1a32df 100644 --- a/controller/flutter/lib/screens/controller.dart +++ b/controller/flutter/lib/screens/controller.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'dart:developer'; import 'dart:io'; - import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_webrtc/flutter_webrtc.dart'; @@ -9,7 +8,7 @@ import 'package:fluttertoast/fluttertoast.dart'; import 'package:nsd/nsd.dart'; import 'package:openbot_controller/globals.dart'; import 'package:openbot_controller/screens/controlSelector.dart'; - +import 'package:openbot_controller/screens/settingsDrawer.dart'; import '../utils/constants.dart'; import 'discoveringDevices.dart'; @@ -32,6 +31,10 @@ class ControllerState extends State { bool mirroredVideo = false; bool indicatorLeft = false; bool indicatorRight = false; + bool isSettings = false; + bool isTiltingPhoneMode = false; + bool isScreenMode = false; + String fragmentType = ""; var _nextPort = 56360; int get nextPort => _nextPort++; @@ -194,6 +197,11 @@ class ControllerState extends State { if (msgInObject["status"] != null) { processMessageFromBot(msgInObject["status"]); } + if (msgInObject["FRAGMENT_TYPE"] != null) { + setState(() { + fragmentType = msgInObject["FRAGMENT_TYPE"]; + }); + } } } } catch (e) { @@ -254,7 +262,50 @@ class ControllerState extends State { mirror: mirroredVideo, ), ControlSelector(setMirrorVideo, indicatorLeft, indicatorRight, - services, _peerConnection) + services, _peerConnection, isTiltingPhoneMode, isScreenMode,fragmentType), + Positioned( + left: isTiltingPhoneMode ? 45 : 110, + top: 16.0, // Adjust the top margin as needed + child: Container( + // padding: EdgeInsets.only(left: ), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(45), + color: Colors.transparent, + ), + child: FloatingActionButton( + backgroundColor: Colors.white.withOpacity(0.5), + onPressed: () { + setState(() { + isSettings = true; + }); + }, + child: const Icon(Icons.menu)), + ), + ), + if (isSettings) + Stack( + children: [ + GestureDetector( + onTap: () { + setState(() { + isSettings = false; + }); + }, + child: Container( + color: Colors.transparent, + ), + ), + SettingsDrawer( + services, + (bool newTiltingMode, bool newScreenMode) { + setState(() { + isTiltingPhoneMode = newTiltingMode; + isScreenMode = newScreenMode; + }); + }, + ), + ], + ), ], ), debugShowCheckedModeBanner: false, diff --git a/controller/flutter/lib/screens/onScreenMode.dart b/controller/flutter/lib/screens/onScreenMode.dart index 88d204c6e..72a13ad59 100644 --- a/controller/flutter/lib/screens/onScreenMode.dart +++ b/controller/flutter/lib/screens/onScreenMode.dart @@ -10,9 +10,10 @@ class OnScreenMode extends StatefulWidget { final bool indicatorLeft; final bool indicatorRight; final RTCPeerConnection? peerConnection; + final String fragmentType; const OnScreenMode(this.updateMirrorView, this.indicatorLeft, - this.indicatorRight, this.peerConnection, + this.indicatorRight, this.peerConnection, this.fragmentType, {super.key}); @override @@ -66,7 +67,7 @@ class OnScreenModeState extends State { alignment: AlignmentDirectional.bottomEnd, margin: const EdgeInsets.only(bottom: 20), child: OnScreenIcon(widget.updateMirrorView, widget.indicatorLeft, - widget.indicatorRight, widget.peerConnection), + widget.indicatorRight, widget.peerConnection,widget.fragmentType), ), Container( margin: const EdgeInsets.only(right: 50), @@ -112,15 +113,15 @@ class SquareSliderComponentShape extends SliderComponentShape { @override void paint(PaintingContext context, Offset center, {required Animation activationAnimation, - required Animation enableAnimation, - required bool isDiscrete, - required TextPainter labelPainter, - required RenderBox parentBox, - required SliderThemeData sliderTheme, - required TextDirection textDirection, - required double value, - required double textScaleFactor, - required Size sizeWithOverflow}) { + required Animation enableAnimation, + required bool isDiscrete, + required TextPainter labelPainter, + required RenderBox parentBox, + required SliderThemeData sliderTheme, + required TextDirection textDirection, + required double value, + required double textScaleFactor, + required Size sizeWithOverflow}) { final Canvas canvas = context.canvas; canvas.drawRRect( RRect.fromRectAndRadius( @@ -138,18 +139,18 @@ class MyRoundedRectSliderTrackShape extends SliderTrackShape @override void paint( - PaintingContext context, - Offset offset, { - required RenderBox parentBox, - required SliderThemeData sliderTheme, - required Animation enableAnimation, - required TextDirection textDirection, - required Offset thumbCenter, - Offset? secondaryOffset, - bool isDiscrete = false, - bool isEnabled = false, - double additionalTrackHeight = 30, - }) { + PaintingContext context, + Offset offset, { + required RenderBox parentBox, + required SliderThemeData sliderTheme, + required Animation enableAnimation, + required TextDirection textDirection, + required Offset thumbCenter, + Offset? secondaryOffset, + bool isDiscrete = false, + bool isEnabled = false, + double additionalTrackHeight = 30, + }) { if (sliderTheme.trackHeight == null) { return; } @@ -209,4 +210,4 @@ class MyRoundedRectSliderTrackShape extends SliderTrackShape rightTrackPaint, ); } -} +} \ No newline at end of file diff --git a/controller/flutter/lib/screens/settingsDrawer.dart b/controller/flutter/lib/screens/settingsDrawer.dart new file mode 100644 index 000000000..a51abc561 --- /dev/null +++ b/controller/flutter/lib/screens/settingsDrawer.dart @@ -0,0 +1,202 @@ +import 'package:flutter/material.dart'; +import 'package:nsd/nsd.dart'; +import 'package:openbot_controller/globals.dart'; + +class SettingsDrawer extends StatefulWidget { + final List networkServices; + final Function(bool, bool) onSettingsChanged; + + SettingsDrawer(this.networkServices, this.onSettingsChanged, {super.key}); + + @override + _SettingsDrawerState createState() => _SettingsDrawerState(); +} + +class _SettingsDrawerState extends State { + List isSelected = [false, false]; + String dropDownValue = 'No server'; + late List> items = []; + bool isNoise = false; + bool isNetwork = false; + + // Function to generate DropdownMenuItem widgets + List> buildDropdownMenuItems() { + items = [ + DropdownMenuItem( + value: 'No server', + child: Container( + height: 30, + width: 85, + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(30)), + color: Color(0xFF0071C5), + ), + alignment: Alignment.center, + child: const Text( + 'No server', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 18, + color: Color(0xFFffffff), + ), + ), + ), + ), + ]; + items.addAll(widget.networkServices.map((discovery) { + return DropdownMenuItem( + value: discovery.name, + child: Container( + height: 30, + width: 85, + decoration: const BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(3)), + color: Color(0xFF0071C5), + ), + alignment: Alignment.center, + child: Text( + discovery.name ?? '', + textAlign: TextAlign.center, + style: const TextStyle( + fontSize: 18, + color: Color(0xFFffffff), + ), + ), + ), + ); + })); + return items; + } + + @override + Widget build(BuildContext context) { + return Drawer( + backgroundColor: const Color(0xFF202020), + child: ListView( + padding: EdgeInsets.zero, + children: [ + Padding( + padding: const EdgeInsets.only(left: 30, top: 35), + child: Row(children: [ + const Text( + 'Controller', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + color: Color(0xFF0071C5), + ), + ), + const SizedBox( + width: 30, + ), + ToggleButtons( + borderRadius: BorderRadius.circular(10), + selectedBorderColor: const Color(0xFF0071C5).withOpacity(0.4), + disabledBorderColor: const Color(0xFF0071C5).withOpacity(0.4), + onPressed: (int newIndex) { + setState(() { + for (int index = 0; index < isSelected.length; index++) { + if (index == newIndex) { + isSelected[index] = true; + if (index == 0) { + setState(() { + widget.onSettingsChanged(true, false); + }); + } else { + setState(() { + widget.onSettingsChanged(false, true); + }); + } + } else { + isSelected[index] = false; + } + } + }); + }, + isSelected: isSelected, + children: [ + Image.asset( + "images/tilting_phone_icon.png", + height: 33, + width: 33, + ), + Image.asset( + "images/controller_icon.png", + height: 33, + width: 33, + ) + ], + ), + ])), + Padding( + padding: const EdgeInsets.only(left: 30, top: 35), + child: Row(children: [ + const Text( + 'Server', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + color: Color(0xFF0071C5), + ), + ), + const SizedBox( + width: 54, + ), + DropdownButton( + value: dropDownValue, + borderRadius: const BorderRadius.all(Radius.circular(3)), + underline: Container(), + dropdownColor: const Color(0xFF0071C5), + style: const TextStyle( + fontSize: 18, + color: Color(0xFFffffff), + ), + menuMaxHeight: 150, + items: buildDropdownMenuItems(), + onChanged: (String? serverName) { + setState(() { + dropDownValue = serverName!; + }); + if (serverName != "No server") { + clientSocket?.writeln("{server: $serverName}"); + } else { + clientSocket?.writeln("{server: noServerFound}"); + } + }, + ), + ]), + ), + Padding( + padding: const EdgeInsets.only(left: 30, top: 35), + child: Row(children: [ + const Text( + 'Noise', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + color: Color(0xFF0071C5), + ), + ), + const SizedBox( + width: 54, + ), + + Switch( + value: isNoise, + onChanged: (bool value) { + setState(() { + isNoise = value; + }); + if (isNoise) { + clientSocket?.writeln("{command: NOISE}"); + } + }, + activeColor: const Color(0xFF0071C5), + ) + ]), + ), + ], + ), + ); + } +} diff --git a/controller/flutter/lib/screens/tiltingPhoneMode.dart b/controller/flutter/lib/screens/tiltingPhoneMode.dart index 4479199da..c679436cd 100644 --- a/controller/flutter/lib/screens/tiltingPhoneMode.dart +++ b/controller/flutter/lib/screens/tiltingPhoneMode.dart @@ -4,11 +4,13 @@ import 'package:flutter/material.dart'; import 'package:openbot_controller/utils/forwardSpeed.dart'; import 'package:openbot_controller/utils/phoneSensorToDualDriveConverter.dart'; import 'package:sensors_plus/sensors_plus.dart'; - +import 'package:openbot_controller/globals.dart'; import 'driveCommandReducer.dart'; class TiltingPhoneMode extends StatefulWidget { - const TiltingPhoneMode({super.key}); + final String fragmentType; + + const TiltingPhoneMode({required this.fragmentType, super.key}); @override State createState() { @@ -28,6 +30,7 @@ class TiltingPhoneModeState extends State { PhoneSensorToDualDriveConverter(); double leftSpeedValue = 0; double rightSpeedValue = 0; + String typeOfFragment = ""; @override void initState() { @@ -43,6 +46,15 @@ class TiltingPhoneModeState extends State { super.initState(); } + @override + void didUpdateWidget(covariant TiltingPhoneMode oldWidget) { + // TODO: implement didUpdateWidget + setState(() { + typeOfFragment = widget.fragmentType; + }); + super.didUpdateWidget(oldWidget); + } + @override Widget build(BuildContext context) { return WillPopScope( @@ -111,6 +123,54 @@ class TiltingPhoneModeState extends State { width: 64, ), )), + Container( + alignment: AlignmentDirectional.bottomEnd, + margin: const EdgeInsets.only(bottom: 20), + child: Row(children: [ + GestureDetector( + onTap: () { + if (typeOfFragment == "DataCollection") { + clientSocket?.writeln("{command: LOGS}"); + } + }, // Image tapped + child: Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(45), + color: typeOfFragment == "DataCollection" + ? Colors.white.withOpacity(0.5) + : Colors.grey.withOpacity(0.5), + ), + child: const Icon( + Icons.file_present, + color: Colors.blue, + ), + )), + const SizedBox( + width: 15, + ), + GestureDetector( + onTap: () { + if (typeOfFragment == "Autopilot" || + typeOfFragment == "ObjectDetection") { + clientSocket?.writeln("{command: NETWORK}"); + } + }, // Image tapped + child: Container( + padding: const EdgeInsets.all(15), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(45), + color: typeOfFragment == "Autopilot" || + typeOfFragment == "ObjectDetection" + ? Colors.white.withOpacity(0.5) + : Colors.grey.withOpacity(0.5), + ), + child: const Icon( + Icons.network_check, + color: Colors.blue, + ), + )), + ])), GestureDetector( onTapDown: (details) { setState(() { diff --git a/controller/flutter/pubspec.lock b/controller/flutter/pubspec.lock index eabcf9292..e8c03be3d 100644 --- a/controller/flutter/pubspec.lock +++ b/controller/flutter/pubspec.lock @@ -13,10 +13,10 @@ packages: dependency: "direct main" description: name: blinking_text - sha256: "3f0c300f9f67ff3455e303a7dea7825bd96965d17295e4e831f29040c0379e69" + sha256: b5af1883380ab88ee6a9337a1b44fbba7d0670ba889b810c57c9aa58eb33ad92 url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.4" boolean_selector: dependency: transitive description: @@ -45,42 +45,42 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.18.0" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" csslib: dependency: transitive description: name: csslib - sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "0.17.2" + version: "1.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.8" dart_webrtc: dependency: transitive description: name: dart_webrtc - sha256: "8949301071ac7c3fb8f78ef7dffc48652db16f2ec63d84078b608f2ca27cca38" + sha256: c664ad88d5646735753add421ee2118486c100febef5e92b7f59cdbabf6a51f6 url: "https://pub.dev" source: hosted - version: "1.0.17" + version: "1.4.9" fake_async: dependency: transitive description: @@ -93,18 +93,18 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.0.1" - file: + version: "2.1.3" + fixnum: dependency: transitive description: - name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -114,18 +114,18 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "5.0.0" flutter_speed_dial: dependency: "direct main" description: name: flutter_speed_dial - sha256: aba767df2df60ccb10ff9fecadd197c83e49ef4c3bc80bc55865eb4d023781d6 + sha256: "698a037274a66dbae8697c265440e6acb6ab6cae9ac5f95c749e7944d8f28d41" url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "7.0.0" flutter_test: dependency: "direct dev" description: flutter @@ -140,26 +140,26 @@ packages: dependency: "direct main" description: name: flutter_webrtc - sha256: "4a3194900981ac7a2aa1e68a37903d8910cc3459c7a1ab68ad0407310cea1642" + sha256: "0b69ecab98211504c10d40c1c4cb48eb387e03ea8e732079bd0d2665d8c20d3f" url: "https://pub.dev" source: hosted - version: "0.9.34" + version: "0.12.1+hotfix.1" fluttertoast: dependency: "direct main" description: name: fluttertoast - sha256: "7cc92eabe01e3f1babe1571c5560b135dfc762a34e41e9056881e2196b178ec1" + sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc" url: "https://pub.dev" source: hosted - version: "8.1.2" + version: "8.2.8" html: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.1" + version: "0.15.5" http_parser: dependency: transitive description: @@ -172,42 +172,74 @@ packages: dependency: transitive description: name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "0.6.7" + version: "3.0.1" lints: dependency: transitive description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "5.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" matcher: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.15.0" nested: dependency: transitive description: @@ -220,194 +252,170 @@ packages: dependency: "direct main" description: name: nsd - sha256: "55b1f27a75e427ef3ba20d445b341a1c3666209f8a71559b43233877b8d3af08" + sha256: cae71ee9c23ea7f75d4610efe7ff335b1f575fb93ef7b7f9a5c6183a091cbb74 url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "4.0.3" nsd_android: dependency: transitive description: name: nsd_android - sha256: "7a38d0b2d21f1e578cd3020940b95b22d5260413dc0c8cf30a987a4e410b166d" + sha256: "1309cd47d02c99bd305219f0a226644f9f4a964d341c3d6730cebb906bb1ec78" url: "https://pub.dev" source: hosted - version: "1.2.2" + version: "2.1.2" nsd_ios: dependency: transitive description: name: nsd_ios - sha256: "7034134dd89595362d5e464030081b0d542120a558ab7fe6227df44365df3e8a" + sha256: "562fffe753543a65190344d3acd0ed80d96c571ac1a05bf10780c5584b5055ac" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.0.1" nsd_macos: dependency: transitive description: name: nsd_macos - sha256: "2403b8d599f50fc9179db1420a0ffc25bfa8bbeb814aa31ca0a71f804fc938da" + sha256: "47cd355d84009befe02710c72bf1c1999b24d5f3fb3a3d914f8b77bcaca42542" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.0.1" nsd_platform_interface: dependency: transitive description: name: nsd_platform_interface - sha256: "2f4033fa13cc45375253bf348abdb9712004e656462205543ec9506b43c67bb2" + sha256: "7220c8e0beeacd06c180fefcd6bb708415ed889c76f656e75ac633d09ceaa761" url: "https://pub.dev" source: hosted - version: "1.6.0" + version: "2.1.1" nsd_windows: dependency: transitive description: name: nsd_windows - sha256: "06601efdd3268cbce4b90f8e23ae1dab445c97c661fba417821ce118add722e7" + sha256: "68b4a256b0be258dbbad0ae789f2e8838d0935a353dac86b17c14c1a05df4ecd" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" path: dependency: transitive description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: transitive description: name: path_provider - sha256: "050e8e85e4b7fecdf2bb3682c1c64c4887a183720c802d323de8a5fd76d372dd" + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.0.22" - path_provider_ios: + version: "2.2.12" + path_provider_foundation: dependency: transitive description: - name: path_provider_ios - sha256: "03d639406f5343478352433f00d3c4394d52dac8df3d847869c5e2333e0bbce8" + name: path_provider_foundation + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.0.11" + version: "2.4.0" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 - url: "https://pub.dev" - source: hosted - version: "2.1.7" - path_provider_macos: - dependency: transitive - description: - name: path_provider_macos - sha256: "2a97e7fbb7ae9dcd0dfc1220a78e9ec3e71da691912e617e8715ff2a13086ae8" + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" platform_detect: dependency: transitive description: name: platform_detect - sha256: "14afcb6ffcd93745e39a288db53d1d6522ea25d71f7993c13a367a86c437b54d" + sha256: a62f99417fc4fa2d099ce0ccdbb1bd3977920f2a64292c326271f049d4bc3a4f url: "https://pub.dev" source: hosted - version: "2.0.7" + version: "2.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.3" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" + version: "2.1.8" provider: dependency: "direct main" description: name: provider - sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.0.5" + version: "6.1.2" pub_semver: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" sensors_plus: dependency: "direct main" description: name: sensors_plus - sha256: "362c8f4f001838b90dd5206b898bbad941bc0142479eab9a3415f0f79e622908" + sha256: "44b2297fbbcaa92273c356f7f4f72ad668ba5c0ddd79f890cb1152eaeea40a8b" url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "6.1.0" sensors_plus_platform_interface: dependency: transitive description: name: sensors_plus_platform_interface - sha256: "95f0cc08791b8bf0c41c5fa99c84be2a7d5bf60a811ddc17e1438b1e68caf0d3" + sha256: b6cacfe243cbeb16403ba688cb0d7054ad4dccb946dcd1254bebdf345fe4b187 url: "https://pub.dev" source: hosted - version: "1.1.3" - sensors_plus_web: - dependency: transitive - description: - name: sensors_plus_web - sha256: fca8d7d9ab6233b2a059952666415508e252420be1ef54f092d07884da53ec5e - url: "https://pub.dev" - source: hosted - version: "1.1.2" + version: "2.0.0" shelf: dependency: "direct main" description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" sky_engine: dependency: transitive description: flutter @@ -417,26 +425,34 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "7.0.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -445,6 +461,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" + url: "https://pub.dev" + source: hosted + version: "3.3.0+3" term_glyph: dependency: transitive description: @@ -457,26 +481,26 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.7.2" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" uuid: dependency: "direct main" description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.5.1" vector_math: dependency: transitive description: @@ -489,66 +513,74 @@ packages: dependency: "direct main" description: name: video_player - sha256: "86b4fb9e30613ef4ff7e47367bfec4b080ab17205b7d969cd12bbebde49476b1" + sha256: "4a8c3492d734f7c39c2588a3206707a05ee80cef52e8c7f3b2078d430c84bc17" url: "https://pub.dev" source: hosted - version: "2.4.10" + version: "2.9.2" video_player_android: dependency: transitive description: name: video_player_android - sha256: "984388511230bac63feb53b2911a70e829fe0976b6b2213f5c579c4e0a882db3" + sha256: "391e092ba4abe2f93b3e625bd6b6a6ec7d7414279462c1c0ee42b5ab8d0a0898" url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.7.16" video_player_avfoundation: dependency: transitive description: name: video_player_avfoundation - sha256: d9f7a46d6a77680adb03ec05a381025d6e890ebe636637c6c3014cc3926b97e9 + sha256: "0b146e5d82e886ff43e5a46c6bcbe390761b802864a6e2503eb612d69a405dfa" url: "https://pub.dev" source: hosted - version: "2.3.8" + version: "2.6.3" video_player_platform_interface: dependency: transitive description: name: video_player_platform_interface - sha256: "42bb75de5e9b79e1f20f1d95f688fac0f95beac4d89c6eb2cd421724d4432dae" + sha256: "229d7642ccd9f3dc4aba169609dd6b5f3f443bb4cc15b82f7785fcada5af9bbb" url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.2.3" video_player_web: dependency: transitive description: name: video_player_web - sha256: b649b07b8f8f553bee4a97a0a53d0fe78a70b115eafaf0105b612b32b05ddb99 + sha256: "881b375a934d8ebf868c7fb1423b2bfaa393a0a265fa3f733079a86536064a10" url: "https://pub.dev" source: hosted - version: "2.0.13" - webrtc_interface: + version: "2.3.3" + vm_service: dependency: transitive description: - name: webrtc_interface - sha256: "0ac4693f921c81005edefd2f43b9fe84b0ed54481474fe1ee16b789b0c84a77c" + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "1.0.13" - win32: + version: "1.1.0" + webrtc_interface: dependency: transitive description: - name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + name: webrtc_interface + sha256: abec3ab7956bd5ac539cf34a42fa0c82ea26675847c0966bb85160400eea9388 url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "1.2.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "0.2.0+3" + version: "1.1.0" sdks: - dart: ">=3.0.0-0 <4.0.0" - flutter: ">=3.0.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/controller/flutter/pubspec.yaml b/controller/flutter/pubspec.yaml index c61a16442..9a0b6d0af 100644 --- a/controller/flutter/pubspec.yaml +++ b/controller/flutter/pubspec.yaml @@ -31,19 +31,19 @@ environment: dependencies: flutter: sdk: flutter - sensors_plus: ^1.2.2 + sensors_plus: ^6.1.0 # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - nsd: ^2.3.0 + nsd: ^4.0.3 provider: ^6.0.2 - flutter_speed_dial: ^5.1.0 - uuid: ^3.0.6 + flutter_speed_dial: ^7.0.0 + uuid: ^4.5.1 shelf: ^1.3.0 blinking_text: ^1.0.2 video_player: ^2.4.10 - flutter_webrtc: ^0.9.34 + flutter_webrtc: ^0.12.1+hotfix.1 fluttertoast: ^8.1.2 dev_dependencies: flutter_test: @@ -54,7 +54,7 @@ dev_dependencies: # activated in the `analysis_options.yaml` file located at the root of your # package. See that file for information about deactivating specific lint # rules and activating additional ones. - flutter_lints: ^2.0.0 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/docs/images/app_controller_settings_1.jpg b/docs/images/app_controller_settings_1.jpg new file mode 100644 index 000000000..ce3ecd3bf Binary files /dev/null and b/docs/images/app_controller_settings_1.jpg differ diff --git a/docs/images/app_controller_settings_2.jpg b/docs/images/app_controller_settings_2.jpg new file mode 100644 index 000000000..d78201d5f Binary files /dev/null and b/docs/images/app_controller_settings_2.jpg differ diff --git a/docs/images/flutter_controller_connected.jpg b/docs/images/flutter_controller_connected.jpg index 98426c429..6fa866ff5 100644 Binary files a/docs/images/flutter_controller_connected.jpg and b/docs/images/flutter_controller_connected.jpg differ diff --git a/docs/images/flutter_controller_dual_drive_mode.jpg b/docs/images/flutter_controller_dual_drive_mode.jpg index fd13ad9ee..a18652b42 100644 Binary files a/docs/images/flutter_controller_dual_drive_mode.jpg and b/docs/images/flutter_controller_dual_drive_mode.jpg differ diff --git a/docs/images/flutter_controller_setting.jpg b/docs/images/flutter_controller_setting.jpg new file mode 100644 index 000000000..509a71dde Binary files /dev/null and b/docs/images/flutter_controller_setting.jpg differ diff --git a/docs/images/flutter_controller_tilt_mode.jpg b/docs/images/flutter_controller_tilt_mode.jpg index 8c660848e..3f1545a23 100644 Binary files a/docs/images/flutter_controller_tilt_mode.jpg and b/docs/images/flutter_controller_tilt_mode.jpg differ