├── .gitignore ├── .metadata ├── README.md ├── Screenshot_20200824-180154.jpg ├── Screenshot_20200824-180256.jpg ├── Screenshot_20200825-152025.jpg ├── Screenshot_20200825-152332.jpg ├── Screenshot_20200825-155059.jpg ├── Screenshot_20200825-155200.jpg ├── Screenshot_20200825-155355.jpg ├── Screenshot_20200825-155431.jpg ├── android ├── .gitignore ├── app │ ├── build.gradle │ └── src │ │ ├── debug │ │ └── AndroidManifest.xml │ │ ├── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── pawelfranitza │ │ │ │ ├── chat_app │ │ │ │ └── MainActivity.kt │ │ │ │ └── chatapp │ │ │ │ └── MainActivity.kt │ │ └── res │ │ │ ├── drawable │ │ │ └── launch_background.xml │ │ │ ├── mipmap-hdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxxhdpi │ │ │ └── ic_launcher.png │ │ │ └── values │ │ │ └── styles.xml │ │ └── profile │ │ └── AndroidManifest.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties └── settings.gradle ├── assets └── template.txt ├── ios ├── .gitignore ├── Flutter │ ├── AppFrameworkInfo.plist │ ├── Debug.xcconfig │ └── Release.xcconfig ├── Runner.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── Runner.xcscheme ├── Runner.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings └── Runner │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-App-1024x1024@1x.png │ │ ├── Icon-App-20x20@1x.png │ │ ├── Icon-App-20x20@2x.png │ │ ├── Icon-App-20x20@3x.png │ │ ├── Icon-App-29x29@1x.png │ │ ├── Icon-App-29x29@2x.png │ │ ├── Icon-App-29x29@3x.png │ │ ├── Icon-App-40x40@1x.png │ │ ├── Icon-App-40x40@2x.png │ │ ├── Icon-App-40x40@3x.png │ │ ├── Icon-App-60x60@2x.png │ │ ├── Icon-App-60x60@3x.png │ │ ├── Icon-App-76x76@1x.png │ │ ├── Icon-App-76x76@2x.png │ │ └── Icon-App-83.5x83.5@2x.png │ └── LaunchImage.imageset │ │ ├── Contents.json │ │ ├── LaunchImage.png │ │ ├── LaunchImage@2x.png │ │ ├── LaunchImage@3x.png │ │ └── README.md │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ └── Runner-Bridging-Header.h ├── lib ├── generated │ ├── intl │ │ ├── messages_all.dart │ │ ├── messages_en.dart │ │ └── messages_pl.dart │ └── l10n.dart ├── l10n │ ├── intl_en.arb │ └── intl_pl.arb ├── main.dart ├── models │ ├── ListExtension.dart │ ├── Message.dart │ ├── NavMsgsOccupancyGridExtension.dart │ ├── StringExtension.dart │ └── Waypoint.dart ├── providers │ ├── AppStateProvider.dart │ ├── AudioProvider.dart │ ├── ChatInfoProvider.dart │ ├── DialogflowProvider.dart │ ├── RosProvider.dart │ └── SettingsProvider.dart ├── screens │ ├── ChatPage.dart │ ├── ControllerPage.dart │ ├── MainPage.dart │ ├── MapPage.dart │ ├── SettingsPage.dart │ └── SettingsPageNew.dart └── widgets │ ├── BubbleMessage.dart │ ├── ChatBar.dart │ ├── ColorPickerCustom.dart │ ├── FavoriteShelf.dart │ ├── MapPainter.dart │ ├── MapShelfButtons.dart │ ├── MessagesList.dart │ ├── RainbowCircularIndicator.dart │ ├── RainbowLinearIndicator.dart │ ├── RoomShelf.dart │ ├── RoundedCornersContainer.dart │ ├── ShadowLine.dart │ ├── StatusInfo.dart │ ├── WaypointDialog.dart │ ├── WaypointShelf.dart │ └── WirtualController.dart ├── pubspec.lock ├── pubspec.yaml ├── test └── widget_test.dart └── web ├── favicon.png ├── icons ├── Icon-192.png └── Icon-512.png ├── index.html └── manifest.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | .vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | /build/ 32 | 33 | # Web related 34 | lib/generated_plugin_registrant.dart 35 | 36 | # Exceptions to above rules. 37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 38 | 39 | # Api keys 40 | /assets/api/* 41 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: f139b11009aeb8ed2a3a3aa8b0066e482709dde3 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ros_command_app 2 | Application for controlling ROS robot with voice commands, sending goals on map or remote controll with virtual joystick 3 | 29.03.2020 4 | 5 | Please note that I made this app as a beginner (~29.03.2020), there are some mistakes and bad practices that should be changed, architecture / state management is also not great. It serves as a demo and the starter point for anyone interested in ROS + Flutter, please keep in mind that it is unlikely that the repository will be updated and / or activelly updated. Sorry for the inconvenience and unresolved issues. 6 | 7 | Check out youtube video showcasing app (PL + ENG subtitles): 8 | 9 | [![YouTube video here](https://img.youtube.com/vi/RIz-qJ3_qvo/hqdefault.jpg)](https://www.youtube.com/watch?v=RIz-qJ3_qvo "YouTube video here") 10 | 11 | ### Map page 12 | You can move robot between points which are created fter clicking on the fab. 13 | 14 | https://github.com/Rongix/ros_navigation_command_app 15 | 16 | 17 | 18 | ### Controller page 19 | 20 | 21 | ### Chat page 22 | Chat page provides communication with Dialogflow Agent. 23 | 24 | 25 | 26 | ### Internatiolization & language support 27 | ~~This app is not internationalized, there are some UI hardcoded strings in polish, sorry for any inconvenience! It uses polish dialogflow intents so it may be tricky to get it running flawlessly~~. 28 | This app has english and polish versions (no dialogflow agent included) 29 | 30 | ## Getting started: 31 | You need to have ROS installed. App was tested with Turtlebot3 Waffle Pi in the simulation environment, althought it can work with any robot. You can quickly set topics and configurate ROS in the app settings. 32 | 33 | This project is a Flutter application. 34 | 35 | A few resources to get you started if this is your first Flutter project: 36 | 37 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 38 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 39 | 40 | For help getting started with Flutter, view our 41 | [online documentation](https://flutter.dev/docs), which offers tutorials, 42 | samples, guidance on mobile development, and a full API reference. 43 | 44 | ## Getting Started 45 | 46 | A few resources to get you started if this is your first Flutter project: 47 | 48 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 49 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 50 | 51 | For help getting started with Flutter, view our 52 | [online documentation](https://flutter.dev/docs), which offers tutorials, 53 | samples, guidance on mobile development, and a full API reference. 54 | 55 | ## Prerequisites 56 | 57 | - You don't need real robot to run app and navigate. 58 | - [ROS Melodic](http://wiki.ros.org/melodic) - Ubuntu 18.04 / [ROS Kinetic](http://wiki.ros.org/kinetic) - Ubuntu 16.04) 59 | - [Flutter](https://flutter.dev/docs/get-started/install). 60 | - [Node.js](https://nodejs.org/en/) for interactive map. 61 | 62 | ## Installation 63 | ### Installation of ROS 64 | 65 | ROS kinetic: [please follow instruction](http://emanual.robotis.com/docs/en/platform/turtlebot3/pc_setup/) 66 | ROS Melodic: Instruction for Ubuntu 18.04 below: 67 | 68 | 1. Following step will update your system and install ROS-Melodic-dekstop-full version. It will also create few aliases and source ROS-melodic environment in your .bashrc, and create catkin_ws folder in your root directory. 69 | ``` 70 | sudo apt update 71 | sudo apt upgrade -y 72 | wget https://raw.githubusercontent.com/ROBOTIS-GIT/robotis_tools/master/install_ros_melodic.sh && chmod 755 ./install_ros_melodic.sh && bash ./install_ros_melodic.sh 73 | ``` 74 | 2. Install dependencies. 75 | ``` 76 | sudo apt install ros-melodic-joy ros-melodic-teleop-twist-joy ros-melodic-teleop-twist-keyboard ros-melodic-laser-proc ros-melodic-rgbd-launch ros-melodic-depthimage-to-laserscan ros-melodic-rosserial-arduino ros-melodic-rosserial-python ros-melodic-rosserial-server ros-melodic-rosserial-client ros-melodic-rosserial-msgs ros-melodic-amcl ros-melodic-map-server ros-melodic-move-base ros-melodic-urdf ros-melodic-xacro ros-melodic-compressed-image-transport ros-melodic-rqt-image-view ros-melodic-gmapping ros-melodic-navigation ros-melodic-interactive-markers 77 | ``` 78 | 3. Install packages for Turtlebot3 (it contains node for simulation). 79 | ``` 80 | cd ~/catkin_ws/src/ 81 | git clone https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git 82 | git clone https://github.com/ROBOTIS-GIT/turtlebot3.git 83 | git clone https://github.com/ROBOTIS-GIT/turtlebot3_simulations.git 84 | cd ~/catkin_ws && catkin_make 85 | ``` 86 | 4. In the next steps you should configure your network. 87 | ``` 88 | sudo nano ~/.bashrc 89 | // EDIT FIELDS: Replace with your ip adress. Please not that you should not use http://localhost:11311 because it won't work. 90 | // Get your ip with: hostname -I 91 | // EXAMPLE: export ROS_MASTER_URI=http://192.221.1.11:11311 92 | // EXAMPLE: export ROS_HOSTNAME=192.221.1.11 93 | // REPLACE: 192.221.1.11 with your ip. 94 | ``` 95 | 5. Install camera package. 96 | ``` 97 | cd ~/catkin_ws/src/ 98 | git clone https://github.com/OTL/cv_camera.git 99 | cd ~/catkin_ws && catkin_make 100 | 101 | // EXAMPLE of use: rosparam set cv_camera/device_id 001 102 | // EXAMPLE of use: rosrun cv_camera cv_camera_node 103 | ``` 104 | 6. Export ROS parameters; simulated robot model. I use waffle_pi. Add appropriete line to your bashrc. 105 | ``` 106 | export TURTLEBOT3_MODEL=waffle_pi 107 | ``` 108 | 109 | ## Running ROS with application. 110 | Refer [ROBOTIS e-Manual for more information.](http://emanual.robotis.com/docs/en/platform/turtlebot3/overview/#overview) 111 | 112 | ### Launch ROS 113 | Read instruction how to use launch nodes and fake node in [simulation chapter](http://emanual.robotis.com/docs/en/platform/turtlebot3/simulation/#simulation). 114 | ``` 115 | roscore 116 | roslaunch turtlebot3_fake turtlebot3_fake.launch 117 | roslaunch turtlebot3_gazebo turtlebot3_house.launch 118 | roslaunch turtlebot3_slam turtlebot3_slam.launch slam_methods:=gmapping 119 | roslaunch turtlebot3_navigation turtlebot3_navigation.launch 120 | //NOTE: This is example, adjust paths to launch files. 121 | roslaunch '/home/rongix/catkin_ws/src/turtlebot3/turtlebot3_navigation/launch/move_base.launch' 122 | ``` 123 | ### Configure ROS params in mobile app settings 124 | 125 | ### Voice commands 126 | To use voice commands you have to configure your own dialogflow agent 127 | -------------------------------------------------------------------------------- /Screenshot_20200824-180154.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200824-180154.jpg -------------------------------------------------------------------------------- /Screenshot_20200824-180256.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200824-180256.jpg -------------------------------------------------------------------------------- /Screenshot_20200825-152025.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200825-152025.jpg -------------------------------------------------------------------------------- /Screenshot_20200825-152332.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200825-152332.jpg -------------------------------------------------------------------------------- /Screenshot_20200825-155059.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200825-155059.jpg -------------------------------------------------------------------------------- /Screenshot_20200825-155200.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200825-155200.jpg -------------------------------------------------------------------------------- /Screenshot_20200825-155355.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200825-155355.jpg -------------------------------------------------------------------------------- /Screenshot_20200825-155431.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/Screenshot_20200825-155431.jpg -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | -------------------------------------------------------------------------------- /android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 28 30 | 31 | sourceSets { 32 | main.java.srcDirs += 'src/main/kotlin' 33 | } 34 | 35 | lintOptions { 36 | disable 'InvalidPackage' 37 | } 38 | 39 | defaultConfig { 40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 41 | applicationId "com.pawelfranitza.chatapp" 42 | minSdkVersion 16 43 | targetSdkVersion 28 44 | versionCode flutterVersionCode.toInteger() 45 | versionName flutterVersionName 46 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 47 | } 48 | 49 | buildTypes { 50 | release { 51 | // TODO: Add your own signing config for the release build. 52 | // Signing with the debug keys for now, so `flutter run --release` works. 53 | signingConfig signingConfigs.debug 54 | } 55 | } 56 | } 57 | 58 | flutter { 59 | source '../..' 60 | } 61 | 62 | dependencies { 63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 64 | testImplementation 'junit:junit:4.12' 65 | androidTestImplementation 'androidx.test:runner:1.1.1' 66 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' 67 | } 68 | -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/pawelfranitza/chat_app/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.pawelfranitza.chat_app 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /android/app/src/main/kotlin/com/pawelfranitza/chatapp/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.pawelfranitza.chatapp 2 | 3 | import androidx.annotation.NonNull; 4 | import io.flutter.embedding.android.FlutterActivity 5 | import io.flutter.embedding.engine.FlutterEngine 6 | import io.flutter.plugins.GeneratedPluginRegistrant 7 | 8 | class MainActivity: FlutterActivity() { 9 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { 10 | GeneratedPluginRegistrant.registerWith(flutterEngine); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 3 | repositories { 4 | google() 5 | jcenter() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:3.5.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | jcenter() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip 7 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /assets/template.txt: -------------------------------------------------------------------------------- 1 | /api/dialogflowapi.json 2 | { 3 | "type": "service_account", 4 | "project_id": "XXXXXXXXXXXX", 5 | "private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 6 | "private_key": "-----BEGIN PRIVATE KEY-----\nXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n-----END PRIVATE KEY-----\n", 7 | "client_email": "XXXXXXXXXXXXXXXXX", 8 | "client_id": "XXXXXXXXXXXX", 9 | "auth_uri": "XXXXXXXXXXXXXXXXXXXXXXX", 10 | "token_uri": "XXXXXXXXXXXXXXXXXXXXXXXX", 11 | "auth_provider_x509_cert_url": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 12 | "client_x509_cert_url": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" 13 | } 14 | -------------------------------------------------------------------------------- /ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/app.flx 22 | Flutter/app.zip 23 | Flutter/flutter_assets/ 24 | Flutter/flutter_export_environment.sh 25 | ServiceDefinitions.json 26 | Runner/GeneratedPluginRegistrant.* 27 | 28 | # Exceptions to above rules. 29 | !default.mode1v3 30 | !default.mode2v3 31 | !default.pbxuser 32 | !default.perspectivev3 33 | -------------------------------------------------------------------------------- /ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | 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. -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | chatapp 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" -------------------------------------------------------------------------------- /lib/generated/intl/messages_all.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that looks up messages for specific locales by 3 | // delegating to the appropriate library. 4 | 5 | // Ignore issues from commonly used lints in this file. 6 | // ignore_for_file:implementation_imports, file_names, unnecessary_new 7 | // ignore_for_file:unnecessary_brace_in_string_interps, directives_ordering 8 | // ignore_for_file:argument_type_not_assignable, invalid_assignment 9 | // ignore_for_file:prefer_single_quotes, prefer_generic_function_type_aliases 10 | // ignore_for_file:comment_references 11 | 12 | import 'dart:async'; 13 | 14 | import 'package:intl/intl.dart'; 15 | import 'package:intl/message_lookup_by_library.dart'; 16 | import 'package:intl/src/intl_helpers.dart'; 17 | 18 | import 'messages_en.dart' as messages_en; 19 | import 'messages_pl.dart' as messages_pl; 20 | 21 | typedef Future LibraryLoader(); 22 | Map _deferredLibraries = { 23 | 'en': () => new Future.value(null), 24 | 'pl': () => new Future.value(null), 25 | }; 26 | 27 | MessageLookupByLibrary _findExact(String localeName) { 28 | switch (localeName) { 29 | case 'en': 30 | return messages_en.messages; 31 | case 'pl': 32 | return messages_pl.messages; 33 | default: 34 | return null; 35 | } 36 | } 37 | 38 | /// User programs should call this before using [localeName] for messages. 39 | Future initializeMessages(String localeName) async { 40 | var availableLocale = Intl.verifiedLocale( 41 | localeName, 42 | (locale) => _deferredLibraries[locale] != null, 43 | onFailure: (_) => null); 44 | if (availableLocale == null) { 45 | return new Future.value(false); 46 | } 47 | var lib = _deferredLibraries[availableLocale]; 48 | await (lib == null ? new Future.value(false) : lib()); 49 | initializeInternalMessageLookup(() => new CompositeMessageLookup()); 50 | messageLookup.addLocale(availableLocale, _findGeneratedMessagesFor); 51 | return new Future.value(true); 52 | } 53 | 54 | bool _messagesExistFor(String locale) { 55 | try { 56 | return _findExact(locale) != null; 57 | } catch (e) { 58 | return false; 59 | } 60 | } 61 | 62 | MessageLookupByLibrary _findGeneratedMessagesFor(String locale) { 63 | var actualLocale = Intl.verifiedLocale(locale, _messagesExistFor, 64 | onFailure: (_) => null); 65 | if (actualLocale == null) return null; 66 | return _findExact(actualLocale); 67 | } 68 | -------------------------------------------------------------------------------- /lib/generated/intl/messages_en.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a en locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | // Ignore issues from commonly used lints in this file. 7 | // ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new 8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering 9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases 10 | // ignore_for_file:unused_import, file_names 11 | 12 | import 'package:intl/intl.dart'; 13 | import 'package:intl/message_lookup_by_library.dart'; 14 | 15 | final messages = new MessageLookup(); 16 | 17 | typedef String MessageIfAbsent(String messageStr, List args); 18 | 19 | class MessageLookup extends MessageLookupByLibrary { 20 | String get localeName => 'en'; 21 | 22 | static m0(type) => "${Intl.select(type, {'title': 'Limit animations', 'desc': 'Changes how lists and messages animate', })}"; 23 | 24 | static m1(type) => "${Intl.select(type, {'title': 'Button labels', 'desc': 'Show additional labels under buttons', })}"; 25 | 26 | static m2(type) => "${Intl.select(type, {'title': 'App settings', 'desc': 'General settings & accessibility', })}"; 27 | 28 | static m3(type) => "${Intl.select(type, {'title': 'Ros configuration', 'desc': 'Ros web config of main and current device', })}"; 29 | 30 | static m4(theme) => "${Intl.select(theme, {'light': 'Light theme', 'dark': 'Dark theme', 'system': 'System theme', })}"; 31 | 32 | final messages = _notInlinedMessages(_notInlinedMessages); 33 | static _notInlinedMessages(_) => { 34 | "creatorAddNew" : MessageLookupByLibrary.simpleMessage("Add new marker"), 35 | "creatorEdit" : MessageLookupByLibrary.simpleMessage("Edit marker"), 36 | "creatorHue" : MessageLookupByLibrary.simpleMessage("Hue"), 37 | "creatorName" : MessageLookupByLibrary.simpleMessage("Name"), 38 | "pageChatIntroAction1" : MessageLookupByLibrary.simpleMessage("Click text icon or order field"), 39 | "pageChatIntroAction2" : MessageLookupByLibrary.simpleMessage("Hold mic icon"), 40 | "pageChatIntroBody" : MessageLookupByLibrary.simpleMessage("Try to talk with voice assistant to issue commands. To begin:"), 41 | "pageChatIntroTitle" : MessageLookupByLibrary.simpleMessage("Hello"), 42 | "pageChatRecording" : MessageLookupByLibrary.simpleMessage("Recording"), 43 | "pageChatTexting" : MessageLookupByLibrary.simpleMessage("Order"), 44 | "pageChatTitle" : MessageLookupByLibrary.simpleMessage("Chat"), 45 | "pageControllerInfoTitle" : MessageLookupByLibrary.simpleMessage("Waiting for cammera topic"), 46 | "pageControllerTitle" : MessageLookupByLibrary.simpleMessage("Controller"), 47 | "pageMapButtonFloating" : MessageLookupByLibrary.simpleMessage("Add new map marker"), 48 | "pageMapButtonGrid" : MessageLookupByLibrary.simpleMessage("Show / hide grid"), 49 | "pageMapInfoTitle" : MessageLookupByLibrary.simpleMessage("Waiting for map topic"), 50 | "pageMapTitle" : MessageLookupByLibrary.simpleMessage("Map"), 51 | "pageSettingsAbout" : MessageLookupByLibrary.simpleMessage("About"), 52 | "pageSettingsAnimations" : m0, 53 | "pageSettingsButtonsDesc" : m1, 54 | "pageSettingsGeneral" : m2, 55 | "pageSettingsRos" : m3, 56 | "pageSettingsRosBattery" : MessageLookupByLibrary.simpleMessage("Battery"), 57 | "pageSettingsRosCamera" : MessageLookupByLibrary.simpleMessage("Camera"), 58 | "pageSettingsRosChatter" : MessageLookupByLibrary.simpleMessage("Chatter"), 59 | "pageSettingsRosDevice" : MessageLookupByLibrary.simpleMessage("This device (ip)"), 60 | "pageSettingsRosMain" : MessageLookupByLibrary.simpleMessage("Main server (ip)"), 61 | "pageSettingsRosMap" : MessageLookupByLibrary.simpleMessage("Map"), 62 | "pageSettingsRosNavigation" : MessageLookupByLibrary.simpleMessage("Navigation / Goal"), 63 | "pageSettingsRosOdom" : MessageLookupByLibrary.simpleMessage("Odometry"), 64 | "pageSettingsRosVelocity" : MessageLookupByLibrary.simpleMessage("Linear / angular velocity"), 65 | "pageSettingsThemes" : m4, 66 | "pageSettingsTitle" : MessageLookupByLibrary.simpleMessage("Settings"), 67 | "tooltipChatMode" : MessageLookupByLibrary.simpleMessage("Text input"), 68 | "tooltipChatStar" : MessageLookupByLibrary.simpleMessage("Quick Replies"), 69 | "tooltipCoordinates" : MessageLookupByLibrary.simpleMessage("Coordinates"), 70 | "tooltipCurrentLocation" : MessageLookupByLibrary.simpleMessage("Current robot location"), 71 | "tooltipRandom" : MessageLookupByLibrary.simpleMessage("Random name"), 72 | "tooltipRefreshConnection" : MessageLookupByLibrary.simpleMessage("Refresh connection"), 73 | "tooltipSettings" : MessageLookupByLibrary.simpleMessage("Settings"), 74 | "tooltipStopActions" : MessageLookupByLibrary.simpleMessage("Stop actions") 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /lib/generated/intl/messages_pl.dart: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT. This is code generated via package:intl/generate_localized.dart 2 | // This is a library that provides messages for a pl locale. All the 3 | // messages from the main program should be duplicated here with the same 4 | // function name. 5 | 6 | // Ignore issues from commonly used lints in this file. 7 | // ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new 8 | // ignore_for_file:prefer_single_quotes,comment_references, directives_ordering 9 | // ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases 10 | // ignore_for_file:unused_import, file_names 11 | 12 | import 'package:intl/intl.dart'; 13 | import 'package:intl/message_lookup_by_library.dart'; 14 | 15 | final messages = new MessageLookup(); 16 | 17 | typedef String MessageIfAbsent(String messageStr, List args); 18 | 19 | class MessageLookup extends MessageLookupByLibrary { 20 | String get localeName => 'pl'; 21 | 22 | static m0(type) => "${Intl.select(type, {'title': 'Ogranicz animacje', 'desc': 'Zmienia zachowanie list, wiadomości', })}"; 23 | 24 | static m1(type) => "${Intl.select(type, {'title': 'Podpisy przycisków', 'desc': 'Dodaje podpisy pod przyciskami nawigacji', })}"; 25 | 26 | static m2(type) => "${Intl.select(type, {'title': 'Ustawienia aplikacji', 'desc': 'Ogólne ustawienia i opcje dostępu', })}"; 27 | 28 | static m3(type) => "${Intl.select(type, {'title': 'Konfiguracja ROS', 'desc': 'Konfiguracja sieciowa ROS, należy wprowadzić adres urządzenia roscore i adres ip aktualnego urządzenia', })}"; 29 | 30 | static m4(theme) => "${Intl.select(theme, {'light': 'Jasny motyw', 'dark': 'Ciemny motyw', 'system': 'Systemowy motyw', })}"; 31 | 32 | final messages = _notInlinedMessages(_notInlinedMessages); 33 | static _notInlinedMessages(_) => { 34 | "creatorAddNew" : MessageLookupByLibrary.simpleMessage("Dodaj nowy znacznik"), 35 | "creatorEdit" : MessageLookupByLibrary.simpleMessage("Edytuj znacznik"), 36 | "creatorHue" : MessageLookupByLibrary.simpleMessage("Barwa"), 37 | "creatorName" : MessageLookupByLibrary.simpleMessage("Nazwa"), 38 | "pageChatIntroAction1" : MessageLookupByLibrary.simpleMessage("Click text icon or order field"), 39 | "pageChatIntroAction2" : MessageLookupByLibrary.simpleMessage("Hold mic icon"), 40 | "pageChatIntroBody" : MessageLookupByLibrary.simpleMessage("Try to talk with voice assistant to issue commands. To begin:"), 41 | "pageChatIntroTitle" : MessageLookupByLibrary.simpleMessage("Hello"), 42 | "pageChatRecording" : MessageLookupByLibrary.simpleMessage("Nagrywam..."), 43 | "pageChatTexting" : MessageLookupByLibrary.simpleMessage("Polecenie"), 44 | "pageChatTitle" : MessageLookupByLibrary.simpleMessage("Chat"), 45 | "pageControllerInfoTitle" : MessageLookupByLibrary.simpleMessage("Czekam na obraz z kamery"), 46 | "pageControllerTitle" : MessageLookupByLibrary.simpleMessage("Controller"), 47 | "pageMapButtonFloating" : MessageLookupByLibrary.simpleMessage("Utwórz nowy znacznik lokalizacyjny"), 48 | "pageMapButtonGrid" : MessageLookupByLibrary.simpleMessage("Pokaż / ukryj siatkę"), 49 | "pageMapInfoTitle" : MessageLookupByLibrary.simpleMessage("Czekam na obraz mapy"), 50 | "pageMapTitle" : MessageLookupByLibrary.simpleMessage("Mapa"), 51 | "pageSettingsAbout" : MessageLookupByLibrary.simpleMessage("O aplikacji"), 52 | "pageSettingsAnimations" : m0, 53 | "pageSettingsButtonsDesc" : m1, 54 | "pageSettingsGeneral" : m2, 55 | "pageSettingsRos" : m3, 56 | "pageSettingsRosBattery" : MessageLookupByLibrary.simpleMessage("Bateria"), 57 | "pageSettingsRosCamera" : MessageLookupByLibrary.simpleMessage("Kamera"), 58 | "pageSettingsRosChatter" : MessageLookupByLibrary.simpleMessage("Chatter"), 59 | "pageSettingsRosDevice" : MessageLookupByLibrary.simpleMessage("To urządzenie (ip)"), 60 | "pageSettingsRosMain" : MessageLookupByLibrary.simpleMessage("Główny serwer (ip)"), 61 | "pageSettingsRosMap" : MessageLookupByLibrary.simpleMessage("Mapa"), 62 | "pageSettingsRosNavigation" : MessageLookupByLibrary.simpleMessage("Nawigacja / Cel"), 63 | "pageSettingsRosOdom" : MessageLookupByLibrary.simpleMessage("Odometria robota"), 64 | "pageSettingsRosVelocity" : MessageLookupByLibrary.simpleMessage("Prędkość liniowa / kątowa silników"), 65 | "pageSettingsThemes" : m4, 66 | "pageSettingsTitle" : MessageLookupByLibrary.simpleMessage("Ustawienia"), 67 | "tooltipChatMode" : MessageLookupByLibrary.simpleMessage("Polecenie tekstowe"), 68 | "tooltipChatStar" : MessageLookupByLibrary.simpleMessage("Szybkie odpowiedzi"), 69 | "tooltipCoordinates" : MessageLookupByLibrary.simpleMessage("Ręczne koordynaty"), 70 | "tooltipCurrentLocation" : MessageLookupByLibrary.simpleMessage("Aktualne położenie robota"), 71 | "tooltipRandom" : MessageLookupByLibrary.simpleMessage("Wylosuj nazwę"), 72 | "tooltipRefreshConnection" : MessageLookupByLibrary.simpleMessage("Odśwież połączenie"), 73 | "tooltipSettings" : MessageLookupByLibrary.simpleMessage("Ustawienia"), 74 | "tooltipStopActions" : MessageLookupByLibrary.simpleMessage("Zatrzymaj akcje robota") 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /lib/generated/l10n.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | import 'package:flutter/material.dart'; 3 | import 'package:intl/intl.dart'; 4 | import 'intl/messages_all.dart'; 5 | 6 | // ************************************************************************** 7 | // Generator: Flutter Intl IDE plugin 8 | // Made by Localizely 9 | // ************************************************************************** 10 | 11 | // ignore_for_file: non_constant_identifier_names, lines_longer_than_80_chars 12 | // ignore_for_file: join_return_with_assignment, prefer_final_in_for_each 13 | // ignore_for_file: avoid_redundant_argument_values 14 | 15 | class S { 16 | S(); 17 | 18 | static S current; 19 | 20 | static const AppLocalizationDelegate delegate = 21 | AppLocalizationDelegate(); 22 | 23 | static Future load(Locale locale) { 24 | final name = (locale.countryCode?.isEmpty ?? false) ? locale.languageCode : locale.toString(); 25 | final localeName = Intl.canonicalizedLocale(name); 26 | return initializeMessages(localeName).then((_) { 27 | Intl.defaultLocale = localeName; 28 | S.current = S(); 29 | 30 | return S.current; 31 | }); 32 | } 33 | 34 | static S of(BuildContext context) { 35 | return Localizations.of(context, S); 36 | } 37 | 38 | /// `Stop actions` 39 | String get tooltipStopActions { 40 | return Intl.message( 41 | 'Stop actions', 42 | name: 'tooltipStopActions', 43 | desc: '', 44 | args: [], 45 | ); 46 | } 47 | 48 | /// `Refresh connection` 49 | String get tooltipRefreshConnection { 50 | return Intl.message( 51 | 'Refresh connection', 52 | name: 'tooltipRefreshConnection', 53 | desc: '', 54 | args: [], 55 | ); 56 | } 57 | 58 | /// `Settings` 59 | String get tooltipSettings { 60 | return Intl.message( 61 | 'Settings', 62 | name: 'tooltipSettings', 63 | desc: '', 64 | args: [], 65 | ); 66 | } 67 | 68 | /// `Text input` 69 | String get tooltipChatMode { 70 | return Intl.message( 71 | 'Text input', 72 | name: 'tooltipChatMode', 73 | desc: '', 74 | args: [], 75 | ); 76 | } 77 | 78 | /// `Quick Replies` 79 | String get tooltipChatStar { 80 | return Intl.message( 81 | 'Quick Replies', 82 | name: 'tooltipChatStar', 83 | desc: '', 84 | args: [], 85 | ); 86 | } 87 | 88 | /// `Random name` 89 | String get tooltipRandom { 90 | return Intl.message( 91 | 'Random name', 92 | name: 'tooltipRandom', 93 | desc: '', 94 | args: [], 95 | ); 96 | } 97 | 98 | /// `Current robot location` 99 | String get tooltipCurrentLocation { 100 | return Intl.message( 101 | 'Current robot location', 102 | name: 'tooltipCurrentLocation', 103 | desc: '', 104 | args: [], 105 | ); 106 | } 107 | 108 | /// `Coordinates` 109 | String get tooltipCoordinates { 110 | return Intl.message( 111 | 'Coordinates', 112 | name: 'tooltipCoordinates', 113 | desc: '', 114 | args: [], 115 | ); 116 | } 117 | 118 | /// `Chat` 119 | String get pageChatTitle { 120 | return Intl.message( 121 | 'Chat', 122 | name: 'pageChatTitle', 123 | desc: '', 124 | args: [], 125 | ); 126 | } 127 | 128 | /// `Order` 129 | String get pageChatTexting { 130 | return Intl.message( 131 | 'Order', 132 | name: 'pageChatTexting', 133 | desc: '', 134 | args: [], 135 | ); 136 | } 137 | 138 | /// `Recording` 139 | String get pageChatRecording { 140 | return Intl.message( 141 | 'Recording', 142 | name: 'pageChatRecording', 143 | desc: '', 144 | args: [], 145 | ); 146 | } 147 | 148 | /// `Hello` 149 | String get pageChatIntroTitle { 150 | return Intl.message( 151 | 'Hello', 152 | name: 'pageChatIntroTitle', 153 | desc: '', 154 | args: [], 155 | ); 156 | } 157 | 158 | /// `Try to talk with voice assistant to issue commands. To begin:` 159 | String get pageChatIntroBody { 160 | return Intl.message( 161 | 'Try to talk with voice assistant to issue commands. To begin:', 162 | name: 'pageChatIntroBody', 163 | desc: '', 164 | args: [], 165 | ); 166 | } 167 | 168 | /// `Click text icon or order field` 169 | String get pageChatIntroAction1 { 170 | return Intl.message( 171 | 'Click text icon or order field', 172 | name: 'pageChatIntroAction1', 173 | desc: '', 174 | args: [], 175 | ); 176 | } 177 | 178 | /// `Hold mic icon` 179 | String get pageChatIntroAction2 { 180 | return Intl.message( 181 | 'Hold mic icon', 182 | name: 'pageChatIntroAction2', 183 | desc: '', 184 | args: [], 185 | ); 186 | } 187 | 188 | /// `Controller` 189 | String get pageControllerTitle { 190 | return Intl.message( 191 | 'Controller', 192 | name: 'pageControllerTitle', 193 | desc: '', 194 | args: [], 195 | ); 196 | } 197 | 198 | /// `Waiting for cammera topic` 199 | String get pageControllerInfoTitle { 200 | return Intl.message( 201 | 'Waiting for cammera topic', 202 | name: 'pageControllerInfoTitle', 203 | desc: '', 204 | args: [], 205 | ); 206 | } 207 | 208 | /// `Map` 209 | String get pageMapTitle { 210 | return Intl.message( 211 | 'Map', 212 | name: 'pageMapTitle', 213 | desc: '', 214 | args: [], 215 | ); 216 | } 217 | 218 | /// `Waiting for map topic` 219 | String get pageMapInfoTitle { 220 | return Intl.message( 221 | 'Waiting for map topic', 222 | name: 'pageMapInfoTitle', 223 | desc: '', 224 | args: [], 225 | ); 226 | } 227 | 228 | /// `Show / hide grid` 229 | String get pageMapButtonGrid { 230 | return Intl.message( 231 | 'Show / hide grid', 232 | name: 'pageMapButtonGrid', 233 | desc: '', 234 | args: [], 235 | ); 236 | } 237 | 238 | /// `Add new map marker` 239 | String get pageMapButtonFloating { 240 | return Intl.message( 241 | 'Add new map marker', 242 | name: 'pageMapButtonFloating', 243 | desc: '', 244 | args: [], 245 | ); 246 | } 247 | 248 | // skipped getter for the 'pageMapInitialRooms' key 249 | 250 | /// `Settings` 251 | String get pageSettingsTitle { 252 | return Intl.message( 253 | 'Settings', 254 | name: 'pageSettingsTitle', 255 | desc: '', 256 | args: [], 257 | ); 258 | } 259 | 260 | /// `{type, select, title {App settings} desc {General settings & accessibility}}` 261 | String pageSettingsGeneral(Object type) { 262 | return Intl.select( 263 | type, 264 | { 265 | 'title': 'App settings', 266 | 'desc': 'General settings & accessibility', 267 | }, 268 | name: 'pageSettingsGeneral', 269 | desc: '', 270 | args: [type], 271 | ); 272 | } 273 | 274 | /// `{theme, select, light {Light theme} dark {Dark theme} system {System theme}}` 275 | String pageSettingsThemes(Object theme) { 276 | return Intl.select( 277 | theme, 278 | { 279 | 'light': 'Light theme', 280 | 'dark': 'Dark theme', 281 | 'system': 'System theme', 282 | }, 283 | name: 'pageSettingsThemes', 284 | desc: '', 285 | args: [theme], 286 | ); 287 | } 288 | 289 | /// `{type, select, title {Limit animations} desc {Changes how lists and messages animate}}` 290 | String pageSettingsAnimations(Object type) { 291 | return Intl.select( 292 | type, 293 | { 294 | 'title': 'Limit animations', 295 | 'desc': 'Changes how lists and messages animate', 296 | }, 297 | name: 'pageSettingsAnimations', 298 | desc: '', 299 | args: [type], 300 | ); 301 | } 302 | 303 | /// `{type, select, title {Button labels} desc {Show additional labels under buttons}}` 304 | String pageSettingsButtonsDesc(Object type) { 305 | return Intl.select( 306 | type, 307 | { 308 | 'title': 'Button labels', 309 | 'desc': 'Show additional labels under buttons', 310 | }, 311 | name: 'pageSettingsButtonsDesc', 312 | desc: '', 313 | args: [type], 314 | ); 315 | } 316 | 317 | /// `{type, select, title {Ros configuration} desc {Ros web config of main and current device}}` 318 | String pageSettingsRos(Object type) { 319 | return Intl.select( 320 | type, 321 | { 322 | 'title': 'Ros configuration', 323 | 'desc': 'Ros web config of main and current device', 324 | }, 325 | name: 'pageSettingsRos', 326 | desc: '', 327 | args: [type], 328 | ); 329 | } 330 | 331 | /// `Main server (ip)` 332 | String get pageSettingsRosMain { 333 | return Intl.message( 334 | 'Main server (ip)', 335 | name: 'pageSettingsRosMain', 336 | desc: '', 337 | args: [], 338 | ); 339 | } 340 | 341 | /// `This device (ip)` 342 | String get pageSettingsRosDevice { 343 | return Intl.message( 344 | 'This device (ip)', 345 | name: 'pageSettingsRosDevice', 346 | desc: '', 347 | args: [], 348 | ); 349 | } 350 | 351 | /// `Odometry` 352 | String get pageSettingsRosOdom { 353 | return Intl.message( 354 | 'Odometry', 355 | name: 'pageSettingsRosOdom', 356 | desc: '', 357 | args: [], 358 | ); 359 | } 360 | 361 | /// `Camera` 362 | String get pageSettingsRosCamera { 363 | return Intl.message( 364 | 'Camera', 365 | name: 'pageSettingsRosCamera', 366 | desc: '', 367 | args: [], 368 | ); 369 | } 370 | 371 | /// `Battery` 372 | String get pageSettingsRosBattery { 373 | return Intl.message( 374 | 'Battery', 375 | name: 'pageSettingsRosBattery', 376 | desc: '', 377 | args: [], 378 | ); 379 | } 380 | 381 | /// `Linear / angular velocity` 382 | String get pageSettingsRosVelocity { 383 | return Intl.message( 384 | 'Linear / angular velocity', 385 | name: 'pageSettingsRosVelocity', 386 | desc: '', 387 | args: [], 388 | ); 389 | } 390 | 391 | /// `Map` 392 | String get pageSettingsRosMap { 393 | return Intl.message( 394 | 'Map', 395 | name: 'pageSettingsRosMap', 396 | desc: '', 397 | args: [], 398 | ); 399 | } 400 | 401 | /// `Navigation / Goal` 402 | String get pageSettingsRosNavigation { 403 | return Intl.message( 404 | 'Navigation / Goal', 405 | name: 'pageSettingsRosNavigation', 406 | desc: '', 407 | args: [], 408 | ); 409 | } 410 | 411 | /// `Chatter` 412 | String get pageSettingsRosChatter { 413 | return Intl.message( 414 | 'Chatter', 415 | name: 'pageSettingsRosChatter', 416 | desc: '', 417 | args: [], 418 | ); 419 | } 420 | 421 | /// `About` 422 | String get pageSettingsAbout { 423 | return Intl.message( 424 | 'About', 425 | name: 'pageSettingsAbout', 426 | desc: '', 427 | args: [], 428 | ); 429 | } 430 | 431 | /// `Add new marker` 432 | String get creatorAddNew { 433 | return Intl.message( 434 | 'Add new marker', 435 | name: 'creatorAddNew', 436 | desc: '', 437 | args: [], 438 | ); 439 | } 440 | 441 | /// `Edit marker` 442 | String get creatorEdit { 443 | return Intl.message( 444 | 'Edit marker', 445 | name: 'creatorEdit', 446 | desc: '', 447 | args: [], 448 | ); 449 | } 450 | 451 | /// `Name` 452 | String get creatorName { 453 | return Intl.message( 454 | 'Name', 455 | name: 'creatorName', 456 | desc: '', 457 | args: [], 458 | ); 459 | } 460 | 461 | /// `Hue` 462 | String get creatorHue { 463 | return Intl.message( 464 | 'Hue', 465 | name: 'creatorHue', 466 | desc: '', 467 | args: [], 468 | ); 469 | } 470 | } 471 | 472 | class AppLocalizationDelegate extends LocalizationsDelegate { 473 | const AppLocalizationDelegate(); 474 | 475 | List get supportedLocales { 476 | return const [ 477 | Locale.fromSubtags(languageCode: 'en'), 478 | Locale.fromSubtags(languageCode: 'pl'), 479 | ]; 480 | } 481 | 482 | @override 483 | bool isSupported(Locale locale) => _isSupported(locale); 484 | @override 485 | Future load(Locale locale) => S.load(locale); 486 | @override 487 | bool shouldReload(AppLocalizationDelegate old) => false; 488 | 489 | bool _isSupported(Locale locale) { 490 | if (locale != null) { 491 | for (var supportedLocale in supportedLocales) { 492 | if (supportedLocale.languageCode == locale.languageCode) { 493 | return true; 494 | } 495 | } 496 | } 497 | return false; 498 | } 499 | } -------------------------------------------------------------------------------- /lib/l10n/intl_en.arb: -------------------------------------------------------------------------------- 1 | { 2 | "tooltipStopActions": "Stop actions", 3 | "tooltipRefreshConnection": "Refresh connection", 4 | "tooltipSettings": "Settings", 5 | "tooltipChatMode": "Text input", 6 | "tooltipChatStar": "Quick Replies", 7 | "tooltipRandom": "Random name", 8 | "tooltipCurrentLocation": "Current robot location", 9 | "tooltipCoordinates": "Coordinates", 10 | "pageChatTitle": "Chat", 11 | "pageChatTexting": "Order", 12 | "pageChatRecording": "Recording", 13 | "pageChatIntroTitle": "Hello", 14 | "pageChatIntroBody": "Try to talk with voice assistant to issue commands. To begin:", 15 | "pageChatIntroAction1": "Click text icon or order field", 16 | "pageChatIntroAction2": "Hold mic icon", 17 | "pageControllerTitle": "Controller", 18 | "pageControllerInfoTitle": "Waiting for cammera topic", 19 | "pageMapTitle": "Map", 20 | "pageMapInfoTitle": "Waiting for map topic", 21 | "pageMapButtonGrid": "Show / hide grid", 22 | "pageMapButtonFloating": "Add new map marker", 23 | "pageMapInitialRooms": "{room, select, kitchen {Kitchen} livingRoom {Living room} bedroom {Bedroom} bathroom {Bathroom}", 24 | "pageSettingsTitle": "Settings", 25 | "pageSettingsGeneral": "{type, select, title {App settings} desc {General settings & accessibility}}", 26 | "pageSettingsThemes": "{theme, select, light {Light theme} dark {Dark theme} system {System theme}}", 27 | "pageSettingsAnimations": "{type, select, title {Limit animations} desc {Changes how lists and messages animate}}", 28 | "pageSettingsButtonsDesc": "{type, select, title {Button labels} desc {Show additional labels under buttons}}", 29 | "pageSettingsRos": "{type, select, title {Ros configuration} desc {Ros web config of main and current device}}", 30 | "pageSettingsRosMain": "Main server (ip)", 31 | "pageSettingsRosDevice": "This device (ip)", 32 | "pageSettingsRosOdom": "Odometry", 33 | "pageSettingsRosCamera": "Camera", 34 | "pageSettingsRosBattery": "Battery", 35 | "pageSettingsRosVelocity": "Linear / angular velocity", 36 | "pageSettingsRosMap": "Map", 37 | "pageSettingsRosNavigation": "Navigation / Goal", 38 | "pageSettingsRosChatter": "Chatter", 39 | "pageSettingsAbout": "About", 40 | "creatorAddNew": "Add new marker", 41 | "creatorEdit": "Edit marker", 42 | "creatorName": "Name", 43 | "creatorHue": "Hue" 44 | } -------------------------------------------------------------------------------- /lib/l10n/intl_pl.arb: -------------------------------------------------------------------------------- 1 | { 2 | "tooltipStopActions": "Zatrzymaj akcje robota", 3 | "tooltipRefreshConnection": "Odśwież połączenie", 4 | "tooltipSettings": "Ustawienia", 5 | "tooltipChatMode": "Polecenie tekstowe", 6 | "tooltipChatStar": "Szybkie odpowiedzi", 7 | "tooltipRandom": "Wylosuj nazwę", 8 | "tooltipCurrentLocation": "Aktualne położenie robota", 9 | "tooltipCoordinates": "Ręczne koordynaty", 10 | "pageChatTitle": "Chat", 11 | "pageChatTexting": "Polecenie", 12 | "pageChatRecording": "Nagrywam...", 13 | "pageChatIntroTitle": "Hello", 14 | "pageChatIntroBody": "Try to talk with voice assistant to issue commands. To begin:", 15 | "pageChatIntroAction1": "Click text icon or order field", 16 | "pageChatIntroAction2": "Hold mic icon", 17 | "pageControllerTitle": "Controller", 18 | "pageControllerInfoTitle": "Czekam na obraz z kamery", 19 | "pageMapTitle": "Mapa", 20 | "pageMapInfoTitle": "Czekam na obraz mapy", 21 | "pageMapButtonGrid": "Pokaż / ukryj siatkę", 22 | "pageMapButtonFloating": "Utwórz nowy znacznik lokalizacyjny", 23 | "pageMapInitialRooms": "{room, select, kitchen {Kitchen} livingRoom {Living room} bedroom {Bedroom} bathroom {Bathroom}", 24 | "pageSettingsTitle": "Ustawienia", 25 | "pageSettingsGeneral": "{type, select, title {Ustawienia aplikacji} desc {Ogólne ustawienia i opcje dostępu}}", 26 | "pageSettingsThemes": "{theme, select, light {Jasny motyw} dark {Ciemny motyw} system {Systemowy motyw}}", 27 | "pageSettingsAnimations": "{type, select, title {Ogranicz animacje} desc {Zmienia zachowanie list, wiadomości}}", 28 | "pageSettingsButtonsDesc": "{type, select, title {Podpisy przycisków} desc {Dodaje podpisy pod przyciskami nawigacji}}", 29 | "pageSettingsRos": "{type, select, title {Konfiguracja ROS} desc {Konfiguracja sieciowa ROS, należy wprowadzić adres urządzenia roscore i adres ip aktualnego urządzenia}}", 30 | "pageSettingsRosMain": "Główny serwer (ip)", 31 | "pageSettingsRosDevice": "To urządzenie (ip)", 32 | "pageSettingsRosOdom": "Odometria robota", 33 | "pageSettingsRosCamera": "Kamera", 34 | "pageSettingsRosBattery": "Bateria", 35 | "pageSettingsRosVelocity": "Prędkość liniowa / kątowa silników", 36 | "pageSettingsRosMap": "Mapa", 37 | "pageSettingsRosNavigation": "Nawigacja / Cel", 38 | "pageSettingsRosChatter": "Chatter", 39 | "pageSettingsAbout": "O aplikacji", 40 | "creatorAddNew": "Dodaj nowy znacznik", 41 | "creatorEdit": "Edytuj znacznik", 42 | "creatorName": "Nazwa", 43 | "creatorHue": "Barwa" 44 | } -------------------------------------------------------------------------------- /lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:async'; 3 | 4 | import 'generated/l10n.dart'; 5 | 6 | import 'package:flutter_localizations/flutter_localizations.dart'; 7 | import 'package:chatapp/providers/AppStateProvider.dart'; 8 | import 'package:chatapp/providers/AudioProvider.dart'; 9 | import 'package:chatapp/providers/ChatInfoProvider.dart'; 10 | import 'package:chatapp/providers/DialogflowProvider.dart'; 11 | import 'package:chatapp/providers/RosProvider.dart'; 12 | import 'package:chatapp/providers/SettingsProvider.dart'; 13 | import 'package:chatapp/screens/MainPage.dart'; 14 | import 'package:flutter/material.dart'; 15 | import 'package:flutter/services.dart'; 16 | import 'package:path_provider/path_provider.dart'; 17 | import 'package:provider/provider.dart'; 18 | 19 | void main() { 20 | WidgetsFlutterBinding.ensureInitialized(); 21 | runApp(MultiProvider(providers: [ 22 | ChangeNotifierProvider(create: (_) => SettingsProvider()), 23 | ChangeNotifierProvider(create: (_) => ChatInfoProvider()), 24 | ChangeNotifierProvider(create: (_) => DialogflowProvider()), 25 | ChangeNotifierProvider(create: (_) => AudioProvider()), 26 | ChangeNotifierProvider(create: (_) => AppStateProvider()), 27 | ChangeNotifierProvider(create: (_) => RosProvider()), 28 | ], child: MyApp())); 29 | } 30 | 31 | class MyApp extends StatefulWidget { 32 | @override 33 | _MyAppState createState() => _MyAppState(); 34 | } 35 | 36 | class _MyAppState extends State { 37 | Future applicationLoaded; 38 | 39 | @override 40 | void didChangeDependencies() { 41 | super.didChangeDependencies(); 42 | applicationLoaded = configureApplication(context); 43 | } 44 | 45 | Future configureApplication(BuildContext context) { 46 | // SystemChrome.setEnabledSystemUIOverlays( 47 | // [SystemUiOverlay.top, SystemUiOverlay.bottom]); 48 | SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( 49 | systemNavigationBarColor: Colors.transparent, 50 | statusBarColor: Colors.transparent)); 51 | 52 | //Get local storage initialized - for saved waypoints locations 53 | Provider.of(context, listen: false) 54 | .localStorageInitialize(); 55 | 56 | return Future.wait([ 57 | //Get shared preferences intialized 58 | Provider.of(context, listen: false).prefsInitialize(), 59 | getTemporaryDirectory().then((dir) async { 60 | dir = Directory(dir.path + '/recordings'); 61 | if (await dir.exists()) { 62 | await dir.delete(recursive: true); 63 | } 64 | await dir.create(); 65 | }), 66 | ]); 67 | } 68 | 69 | @override 70 | Widget build(BuildContext context) { 71 | return FutureBuilder( 72 | future: applicationLoaded, 73 | builder: (context, snapshot) { 74 | if (snapshot.connectionState == ConnectionState.done) { 75 | return mainApp(context); 76 | } else { 77 | return loadingScreen(context); 78 | } 79 | }, 80 | ); 81 | } 82 | 83 | Widget loadingScreen(BuildContext context) { 84 | return MaterialApp( 85 | home: Container(), 86 | ); 87 | } 88 | 89 | Widget mainApp(BuildContext context) { 90 | return MaterialApp( 91 | localizationsDelegates: [ 92 | S.delegate, 93 | GlobalMaterialLocalizations.delegate, 94 | GlobalWidgetsLocalizations.delegate, 95 | GlobalCupertinoLocalizations.delegate, 96 | ], 97 | supportedLocales: S.delegate.supportedLocales, 98 | debugShowCheckedModeBanner: false, 99 | title: 'Voice App', 100 | themeMode: Provider.of(context, listen: true).appTheme, 101 | theme: ThemeData( 102 | brightness: Brightness.light, 103 | // primaryColor: Colors.blueAccent[300], 104 | primaryColor: Colors.white, 105 | secondaryHeaderColor: Colors.blue[50], 106 | canvasColor: Color.fromRGBO(245, 245, 245, 1), 107 | appBarTheme: AppBarTheme(elevation: 0), 108 | backgroundColor: Color.fromRGBO(240, 240, 240, 1), 109 | 110 | // accentColor: Colors.lightBlueAccent[400], 111 | accentColor: Colors.amber[200], 112 | textSelectionHandleColor: Colors.amber, 113 | 114 | scaffoldBackgroundColor: Colors.white, 115 | chipTheme: ThemeData.light() 116 | .chipTheme 117 | .copyWith(backgroundColor: Color.fromRGBO(230, 230, 230, 1)), 118 | ), 119 | // darkTheme: ThemeData( 120 | // brightness: Brightness.dark, 121 | // primaryColor: Color.fromRGBO(60, 60, 60, 1), 122 | // accentColor: Colors.cyan, 123 | // scaffoldBackgroundColor: Color.fromRGBO(80, 80, 80, 1), 124 | // textSelectionHandleColor: Colors.cyanAccent, 125 | // ), 126 | darkTheme: ThemeData( 127 | brightness: Brightness.dark, 128 | // primaryColor: Color.fromRGBO(60, 60, 60, 1), 129 | // scaffoldBackgroundColor: Color.fromRGBO(80, 80, 80, 1), 130 | // textSelectionHandleColor: Colors.cyanAccent, 131 | primaryColor: Color.fromRGBO(40, 40, 40, 1), 132 | canvasColor: Color.fromRGBO(60, 60, 60, 1), 133 | scaffoldBackgroundColor: Color.fromRGBO(40, 40, 40, 1), 134 | backgroundColor: Color.fromRGBO(50, 50, 50, 1), 135 | appBarTheme: AppBarTheme(elevation: 0), 136 | accentColor: Colors.cyan, 137 | textSelectionHandleColor: Colors.cyan, 138 | chipTheme: ThemeData.dark() 139 | .chipTheme 140 | .copyWith(backgroundColor: Color.fromRGBO(50, 50, 50, 1)), 141 | ), 142 | 143 | home: MainPage(), 144 | // initialRoute: '/', 145 | // routes: { 146 | // '/': (context) => ChatPage(), 147 | // }, 148 | ); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /lib/models/ListExtension.dart: -------------------------------------------------------------------------------- 1 | extension ListExtension on List { 2 | List insertEveryNth(T item, {int insertOffset = 2}) { 3 | assert(insertOffset > 1); 4 | 5 | var listLength = length + (length / (insertOffset - 1)).floor(); 6 | var returnList = List(listLength); 7 | var listIterator = iterator; 8 | 9 | for (var i = 0; i < listLength; ++i) { 10 | if (i % insertOffset != insertOffset - 1 && listIterator.moveNext()) { 11 | returnList[i] = listIterator.current; 12 | } else { 13 | returnList[i] = item; 14 | } 15 | } 16 | 17 | return returnList; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/models/Message.dart: -------------------------------------------------------------------------------- 1 | import 'package:audio_recorder/audio_recorder.dart'; 2 | import 'package:chatapp/providers/DialogflowProvider.dart'; 3 | import 'package:flutter/widgets.dart'; 4 | 5 | enum Sender { user, system, bot } 6 | 7 | class IconWithDescription { 8 | final Function onTap; 9 | final IconData icon; 10 | final String description; 11 | 12 | IconWithDescription({this.onTap, this.icon, this.description}) 13 | : assert(onTap != null), 14 | assert(icon != null), 15 | assert(description != null); 16 | } 17 | 18 | class Message { 19 | final String heading; 20 | 21 | // If message has no heading or description, fill body only; 22 | String body; 23 | List actions; 24 | 25 | final Sender sender; 26 | final DateTime timestamp; 27 | final CustomAIResponse aiResponse; 28 | final Recording voiceActing; 29 | 30 | Message({ 31 | this.heading, 32 | this.body, 33 | this.actions, 34 | this.sender, 35 | DateTime timestamp, 36 | this.aiResponse, 37 | this.voiceActing, 38 | }) : this.timestamp = timestamp ?? DateTime.now(); 39 | } 40 | -------------------------------------------------------------------------------- /lib/models/NavMsgsOccupancyGridExtension.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:typed_data'; 3 | import 'dart:ui'; 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:ros_nodes/messages/nav_msgs/OccupancyGrid.dart'; 7 | 8 | extension CallMeBritney on NavMsgsOccupancyGrid { 9 | Uint8List toRGBA({@required Color border, @required Color fill}) { 10 | var buffor = BytesBuilder(); 11 | for (var value in data) { 12 | switch (value) { 13 | case -1: 14 | { 15 | buffor.add([0, 0, 0, 0]); 16 | break; 17 | } 18 | case 0: 19 | { 20 | buffor.add([fill.red, fill.green, fill.blue, fill.alpha]); 21 | break; 22 | } 23 | default: 24 | { 25 | buffor.add([border.red, border.green, border.blue, border.alpha]); 26 | break; 27 | } 28 | } 29 | } 30 | return buffor.takeBytes(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/models/StringExtension.dart: -------------------------------------------------------------------------------- 1 | extension StringExtension on String { 2 | String capitalize() { 3 | return "${this[0].toUpperCase()}${this.substring(1)}"; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/models/Waypoint.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | class Waypoint { 4 | String name; 5 | Color color; 6 | double x; 7 | double y; 8 | double radius; 9 | 10 | Waypoint({this.name, this.color, this.x, this.y, this.radius = 0.0}); 11 | 12 | toJSONEencodable() { 13 | Map encoded = Map(); 14 | 15 | encoded['name'] = name; 16 | encoded['color'] = color; 17 | encoded['x'] = x; 18 | encoded['y'] = y; 19 | encoded['radius'] = radius; 20 | 21 | return encoded; 22 | } 23 | } 24 | 25 | class WaypointList { 26 | List waypoints; 27 | 28 | WaypointList(this.waypoints); 29 | 30 | toJSONEencodable() { 31 | return waypoints.map((item) { 32 | return item.toJSONEencodable(); 33 | }).toList(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/providers/AppStateProvider.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/generated/l10n.dart'; 2 | import 'package:chatapp/screens/ChatPage.dart'; 3 | import 'package:chatapp/screens/ControllerPage.dart'; 4 | import 'package:chatapp/screens/MapPage.dart'; 5 | import 'package:flutter/cupertino.dart'; 6 | 7 | class AppStateProvider extends ChangeNotifier { 8 | var _activePageIndex = 0; 9 | static const _appPages = [ChatPage(), ControllerPage(), MapPage()]; 10 | 11 | var _navigationBarPageController = 12 | PageController(initialPage: 0, keepPage: true); 13 | 14 | void setActivePage(int index) { 15 | if (index != _activePageIndex) { 16 | _activePageIndex = index; 17 | // Navigation with PagedView 18 | // if (WidgetsBinding.instance.disableAnimations) { 19 | // _navigationBarPageController.jumpToPage(index); 20 | // } else { 21 | // _navigationBarPageController.animateToPage(index, 22 | // duration: Duration(milliseconds: 400), curve: Curves.easeOutQuad); 23 | // } 24 | notifyListeners(); 25 | } 26 | } 27 | 28 | int get activePageIndex => _activePageIndex; 29 | PageController get navigationBarPageController => 30 | _navigationBarPageController; 31 | List get appPages => _appPages; 32 | } 33 | -------------------------------------------------------------------------------- /lib/providers/AudioProvider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:io'; 3 | 4 | import 'package:audio_recorder/audio_recorder.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:path_provider/path_provider.dart'; 7 | import 'package:uuid/uuid.dart'; 8 | import 'package:soundpool/soundpool.dart'; 9 | 10 | //Recording and playing sounds 11 | class AudioProvider extends ChangeNotifier { 12 | final bubbleMessagePool = Soundpool(); 13 | 14 | //Split into play/pause/stop? 15 | Future playBubbleUserMessageVoice(String path) async { 16 | bubbleMessagePool.release(); 17 | final bubbleMessageContent = await File(path).readAsBytes(); 18 | final soundId = await bubbleMessagePool.loadUint8List(bubbleMessageContent); 19 | bubbleMessagePool.play(soundId); 20 | } 21 | 22 | Future playBubbleBotMessageVoice(String audio) async { 23 | bubbleMessagePool.release(); 24 | final soundId = await bubbleMessagePool.loadUint8List(base64Decode(audio)); 25 | bubbleMessagePool.play(soundId); 26 | } 27 | 28 | //Updating recordID everytime new record is created 29 | Future getRecordingPath() async { 30 | var directory = await getTemporaryDirectory(); 31 | return directory.path + '/recordings/' + Uuid().v1(); 32 | } 33 | 34 | bool _hasPermission = true; 35 | bool get hasPermission => _hasPermission; 36 | Future _checkPermission() async { 37 | _hasPermission = await AudioRecorder.hasPermissions; 38 | return _hasPermission; 39 | } 40 | 41 | bool _isRecording = false; 42 | bool get isRecording => _isRecording; 43 | 44 | Future start() async { 45 | if (!await _checkPermission()) return; 46 | 47 | var path = await getRecordingPath(); 48 | print(path); 49 | print("started!!!!!!!!"); 50 | await AudioRecorder.start( 51 | path: path, audioOutputFormat: AudioOutputFormat.WAV); 52 | _isRecording = await AudioRecorder.isRecording; 53 | notifyListeners(); 54 | } 55 | 56 | Future stop() async { 57 | var recorrding = await AudioRecorder.stop(); 58 | _isRecording = await AudioRecorder.isRecording; 59 | notifyListeners(); 60 | 61 | return recorrding; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/providers/ChatInfoProvider.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/generated/l10n.dart'; 2 | import 'package:chatapp/models/Message.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter/scheduler.dart'; 5 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 6 | 7 | class ChatInfoProvider extends ChangeNotifier { 8 | //favorite shelf 9 | var _favoriteShelfOpen = true; 10 | void toggleFavoriteShelf() { 11 | _favoriteShelfOpen = !_favoriteShelfOpen; 12 | notifyListeners(); 13 | } 14 | 15 | var _listKey = GlobalKey(); 16 | List _messages = [ 17 | Message( 18 | heading: "Hello", 19 | body: 20 | 'Voice and chat commands are disabled by default in this app version. You can issue commands in controller and map pages. Your actions will show below', 21 | sender: Sender.system, 22 | actions: [ 23 | // IconWithDescription( 24 | // onTap: () { 25 | // print('aaa'); 26 | // }, 27 | // icon: MdiIcons.textShort, 28 | // description: 29 | // 'Naciśnij ikonę tekstu lub kliknij pole "Polecenie"'), 30 | // IconWithDescription( 31 | // onTap: () { 32 | // print('aaa'); 33 | // }, 34 | // icon: Icons.mic, 35 | // description: 36 | // 'Trzymaj ikonę mikrofonu aby nagrać wiadomość głosową'), 37 | ]) 38 | ]; 39 | 40 | var _controller = TextEditingController(); 41 | var _isControllerEmpty = true; 42 | 43 | ChatInfoProvider() : super() { 44 | _controller.addListener(_textUpdate); 45 | } 46 | 47 | void clearController() { 48 | SchedulerBinding.instance.addPostFrameCallback((_) { 49 | _controller.clear(); 50 | }); 51 | } 52 | 53 | void _textUpdate() { 54 | if (_isControllerEmpty != _controller.text.isEmpty) { 55 | _isControllerEmpty = _controller.text.isEmpty; 56 | notifyListeners(); 57 | } 58 | } 59 | 60 | void addMessage({@required Message message}) { 61 | if (_listKey.currentWidget != null) { 62 | print("Animowanie"); 63 | _listKey.currentState.insertItem(_messages.length, 64 | duration: const Duration(milliseconds: 150)); 65 | clearController(); 66 | } 67 | _messages.add(message); 68 | notifyListeners(); 69 | } 70 | 71 | // Works as speech to text from dialogflow 72 | void updateLastVoiceMessageDescription(String description) { 73 | if (_messages[_messages.length - 2].body == 74 | "Wiadomość głosowa bez transkrypcji") { 75 | _messages[_messages.length - 2].body = description; 76 | notifyListeners(); 77 | } 78 | } 79 | 80 | bool get favoriteShelfOpen => _favoriteShelfOpen; 81 | bool get isControllerEmpty => _isControllerEmpty; 82 | TextEditingController get chatTextController => _controller; 83 | GlobalKey get listKey => _listKey; 84 | List get messages => _messages; 85 | } 86 | -------------------------------------------------------------------------------- /lib/providers/DialogflowProvider.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'dart:core'; 3 | import 'dart:io'; 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_dialogflow/dialogflow_v2.dart'; 7 | 8 | //audiotesting 9 | 10 | import 'package:soundpool/soundpool.dart'; 11 | 12 | extension MapExtensions on Map { 13 | Map getMap(K key) { 14 | var keyFound = this.containsKey(key); 15 | if (!keyFound) { 16 | return null; 17 | } 18 | 19 | var value = this[key]; 20 | if (value is Map) { 21 | return value; 22 | } 23 | return null; 24 | } 25 | 26 | V getValue(K key) => this[key]; 27 | } 28 | 29 | class CustomAIResponse extends AIResponse { 30 | List suggestions; 31 | String outputAudio; 32 | 33 | CustomAIResponse({Map body}) : super(body: body) { 34 | var data = body.getMap('queryResult'); 35 | var richResponse = data 36 | ?.getMap('webhookPayload') 37 | ?.getMap('google') 38 | ?.getMap('richResponse') 39 | ?.getValue('suggestions'); 40 | 41 | suggestions = List.from(richResponse ?? const []); 42 | outputAudio = body['outputAudio']; 43 | } 44 | 45 | CustomAIResponse.fromParams(String suggestions, String outputAudio) { 46 | suggestions = suggestions; 47 | outputAudio = outputAudio; 48 | } 49 | } 50 | 51 | class AudioDialogFlow extends Dialogflow { 52 | const AudioDialogFlow({@required authGoogle, language = "en"}) 53 | : super(authGoogle: authGoogle, language: language); 54 | 55 | String _getUrl() { 56 | // return "https://dialogflow.googleapis.com/v2/projects/${authGoogle.getProjectId}/agent/sessions/${authGoogle.getSessionId}:detectIntent"; 57 | 58 | //BETA locations for dialogflow 59 | return "https://europe-west2-dialogflow.googleapis.com/v2beta1/projects/${authGoogle.getProjectId}/locations/europe-west2/agent/sessions/${authGoogle.getSessionId}:detectIntent"; 60 | } 61 | 62 | Future detectIntent(String query, 63 | {bool isAudio = false}) async { 64 | var body = {}; 65 | 66 | if (isAudio) { 67 | body['queryInput'] = { 68 | 'audioConfig': { 69 | 'audioEncoding': 'AUDIO_ENCODING_LINEAR_16', 70 | 'languageCode': language, 71 | } 72 | }; 73 | body['inputAudio'] = query; 74 | } else { 75 | body['queryInput'] = { 76 | 'text': { 77 | 'text': query, 78 | 'languageCode': language, 79 | } 80 | }; 81 | } 82 | 83 | var response = await authGoogle.post( 84 | _getUrl(), 85 | headers: { 86 | HttpHeaders.authorizationHeader: "Bearer ${authGoogle.getToken}" 87 | }, 88 | body: json.encode(body), 89 | ); 90 | 91 | return CustomAIResponse(body: json.decode(response.body)); 92 | } 93 | } 94 | 95 | class DialogflowProvider extends ChangeNotifier { 96 | final Soundpool pool = Soundpool(); 97 | 98 | Future response(inputMessage, 99 | {bool isAudio = false}) async { 100 | AuthGoogle authGoogle = 101 | await AuthGoogle(fileJson: "assets/dialogflowapi.json").build(); 102 | AudioDialogFlow dialogflow = 103 | AudioDialogFlow(authGoogle: authGoogle, language: "pl"); 104 | var aiResponse = 105 | await dialogflow.detectIntent(inputMessage, isAudio: isAudio); 106 | // print(response.queryResult.allRequiredParamsPresent.toString()); 107 | // print(response.queryResult.parameters); 108 | // print(response.getListMessage()); 109 | 110 | pool.release(); 111 | final soundId = 112 | await pool.loadUint8List(base64Decode(aiResponse.outputAudio)); 113 | pool.play(soundId); 114 | 115 | return aiResponse; 116 | 117 | // ChatMessage message = new ChatMessage( 118 | // text: response.getMessageResponse(), 119 | // name: "Bot", 120 | // type: false, 121 | // ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /lib/providers/SettingsProvider.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/models/Waypoint.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:localstorage/localstorage.dart'; 4 | import 'package:shared_preferences/shared_preferences.dart'; 5 | 6 | class SettingsProvider extends ChangeNotifier { 7 | // JSON storage for objects like Waypoints 8 | bool _localAppStorageInitialized = false; 9 | get localAppStorageInitialized => _localAppStorageInitialized; 10 | 11 | WaypointList _waypoints; 12 | 13 | WaypointList get waypoints => _waypoints; 14 | 15 | void addToWaypoints(Waypoint waypoint) { 16 | _waypoints.waypoints.add(waypoint); 17 | notifyListeners(); 18 | } 19 | 20 | void editWaypoint(Waypoint oryginal, Waypoint edited) { 21 | var index = 22 | _waypoints.waypoints.indexWhere((element) => element == oryginal); 23 | print('found the same waypoint'); 24 | _waypoints.waypoints.remove(oryginal); 25 | _waypoints.waypoints.insert(index, edited); 26 | notifyListeners(); 27 | } 28 | 29 | Waypoint findWaypointByName(String name) { 30 | return _waypoints.waypoints.elementAt( 31 | _waypoints.waypoints.indexWhere((element) => element.name == name)); 32 | } 33 | 34 | void removeWaypoint(Waypoint waypoint) { 35 | _waypoints.waypoints.remove(waypoint); 36 | notifyListeners(); 37 | } 38 | 39 | // Shared preferences settings 40 | bool _initialized = false; 41 | 42 | int _themeModeIndex; 43 | int get themeModeIndex => _themeModeIndex; 44 | 45 | ThemeMode _appTheme; 46 | ThemeMode get appTheme => _appTheme; 47 | 48 | bool _limitAnimations; 49 | bool get limitAnimations => _limitAnimations; 50 | 51 | bool _showNavigationBarLabels; 52 | bool get showNavigationBarLabels => _showNavigationBarLabels; 53 | 54 | bool _useTopicsOverWebView; 55 | bool get useTopicsOverWebView => _useTopicsOverWebView; 56 | 57 | bool _showMapGrid; 58 | bool get showMapGrid => _showMapGrid; 59 | 60 | // Textfields controller strings 61 | String _ipAdressMainServer; 62 | String get ipAdressMainServer => _ipAdressMainServer; 63 | 64 | String _ipAdressDevice; 65 | String get ipAdressDevice => _ipAdressDevice; 66 | 67 | String _topicOdometry; 68 | String get topicOdometry => _topicOdometry; 69 | 70 | String _topicCamera; 71 | String get topicCamera => _topicCamera; 72 | 73 | String _topicBattery; 74 | String get topicBattery => _topicBattery; 75 | 76 | String _topicVelocity; 77 | String get topicVelocity => _topicVelocity; 78 | 79 | String _topicMap; 80 | String get topicMap => _topicMap; 81 | 82 | String _topicNavigation; 83 | String get topicNavigation => _topicNavigation; 84 | 85 | String _topicChatter; 86 | String get topicChatter => _topicChatter; 87 | 88 | String _webCameraAdress; 89 | String get webCameraAdress => _webCameraAdress; 90 | 91 | String _webMapAdress; 92 | String get webMapAdress => _webMapAdress; 93 | 94 | void _initializeTheme() { 95 | switch (_themeModeIndex) { 96 | case 0: 97 | { 98 | _appTheme = ThemeMode.light; 99 | 100 | break; 101 | } 102 | case 1: 103 | { 104 | _appTheme = ThemeMode.dark; 105 | break; 106 | } 107 | case 2: 108 | { 109 | _appTheme = ThemeMode.system; 110 | break; 111 | } 112 | } 113 | } 114 | 115 | void _saveTheme() { 116 | switch (_appTheme) { 117 | case ThemeMode.light: 118 | { 119 | _themeModeIndex = 0; 120 | break; 121 | } 122 | case ThemeMode.dark: 123 | { 124 | _themeModeIndex = 1; 125 | break; 126 | } 127 | case ThemeMode.system: 128 | { 129 | _themeModeIndex = 2; 130 | break; 131 | } 132 | } 133 | } 134 | 135 | // Run on app start 136 | // Load saved preferences from Shared preferences 137 | Future prefsInitialize() async { 138 | if (!_initialized) { 139 | Future _prefs = SharedPreferences.getInstance(); 140 | final SharedPreferences prefs = await _prefs; 141 | _themeModeIndex = prefs.getInt('themeModeIndex') ?? 2; 142 | _initializeTheme(); 143 | _limitAnimations = prefs.getBool('limitAnimations') ?? false; 144 | _showNavigationBarLabels = 145 | prefs.getBool('showNavigationBarLabels') ?? false; 146 | _useTopicsOverWebView = prefs.getBool('useTopicsOverWebView') ?? true; 147 | 148 | // Set controllers strings 149 | _ipAdressMainServer = 150 | prefs.getString('ipAdressMainServer') ?? 'http://192.168.1.11:11311/'; 151 | _ipAdressDevice = prefs.getString('ipAdressDevice') ?? '192.168.1.30'; 152 | _topicOdometry = prefs.getString('topicOdometry') ?? 'odom'; 153 | _topicCamera = 154 | prefs.getString('topicCamera') ?? 'camera/rgb/image_raw/compressed'; 155 | _topicBattery = prefs.getString('topicBattery') ?? 'battery_state'; 156 | _topicVelocity = prefs.getString('topicVelocity') ?? 'cmd_vel'; 157 | _topicMap = prefs.getString('topicMap') ?? 'map'; 158 | _topicNavigation = 159 | prefs.getString('topicNavigation') ?? 'move_base_simple/goal'; 160 | _topicChatter = prefs.getString('topicChatter') ?? 'chatter'; 161 | _webCameraAdress = prefs.getString('webCameraAdress') ?? ''; 162 | _webMapAdress = prefs.getString('webMapAdress') ?? ''; 163 | 164 | // Map View 165 | _showMapGrid = prefs.getBool('showMapGrid') ?? false; 166 | _initialized = true; 167 | } 168 | } 169 | 170 | void localStorageInitialize() { 171 | final localAppStorage = LocalStorage('localAppStorage'); 172 | if (!_localAppStorageInitialized) { 173 | // Waypoints from sample turtlebot3 home 3d simulated environmental map, based on true storry 174 | _waypoints = localAppStorage.getItem('waypoints') ?? 175 | WaypointList([ 176 | Waypoint(name: 'K', color: Colors.green, x: 6, y: -1), 177 | Waypoint(name: 'PG', color: Colors.yellow, x: 2.9, y: 2.3), 178 | Waypoint(name: 'S', color: Colors.pink, x: -6, y: 3.11), 179 | Waypoint(name: 'L', color: Colors.blue, x: 1, y: 2.6), 180 | ]); 181 | 182 | _localAppStorageInitialized = true; 183 | } 184 | } 185 | 186 | void localStorageSave() async { 187 | final localAppStorage = LocalStorage('localAppStorage'); 188 | await localAppStorage.setItem('waypoints', _waypoints); 189 | } 190 | 191 | // Run on back button from settings if not saved 192 | // Save current preferences to Shared preferences 193 | void savePrefs() async { 194 | Future _prefs = SharedPreferences.getInstance(); 195 | final SharedPreferences prefs = await _prefs; 196 | _saveTheme(); 197 | prefs.setInt('themeModeIndex', themeModeIndex); 198 | prefs.setBool('limitAnimations', limitAnimations); 199 | prefs.setBool('showNavigationBarLabels', showNavigationBarLabels); 200 | prefs.setBool('useTopicsOverWebView', useTopicsOverWebView); 201 | prefs.setString('ipAdressMainServer', ipAdressMainServer); 202 | prefs.setString('ipAdressDevice', ipAdressDevice); 203 | prefs.setString('topicOdometry', topicOdometry); 204 | prefs.setString('topicCamera', topicCamera); 205 | prefs.setString('topicBattery', topicBattery); 206 | prefs.setString('topicVelocity', topicVelocity); 207 | prefs.setString('topicMap', topicMap); 208 | prefs.setString('topicNavigation', topicNavigation); 209 | prefs.setString('topicChatter', topicChatter); 210 | prefs.setString('webCameraAdress', webCameraAdress); 211 | prefs.setString('webMapAdress', webMapAdress); 212 | 213 | // Map View 214 | prefs.setBool('showMapGrid', showMapGrid); 215 | 216 | notifyListeners(); 217 | } 218 | 219 | void setTheme(ThemeMode value) { 220 | _appTheme = value; 221 | notifyListeners(); 222 | } 223 | 224 | void setLimitAnimations(bool value) { 225 | _limitAnimations = value; 226 | notifyListeners(); 227 | } 228 | 229 | void setShowNavigationBarLabels(bool value) { 230 | _showNavigationBarLabels = value; 231 | notifyListeners(); 232 | } 233 | 234 | void setUseTopicsOverWebView(bool value) { 235 | _useTopicsOverWebView = value; 236 | notifyListeners(); 237 | } 238 | 239 | void setIpAdressMainServer(String str) { 240 | print('Set ip main server to $str'); 241 | _ipAdressMainServer = str; 242 | } 243 | 244 | void setIpAdressDevice(String str) { 245 | _ipAdressDevice = str; 246 | } 247 | 248 | void setTopicOdometry(String str) { 249 | _topicOdometry = str; 250 | } 251 | 252 | void setTopicCamera(String str) { 253 | _topicCamera = str; 254 | } 255 | 256 | void setTopicBattery(String str) { 257 | _topicBattery = str; 258 | } 259 | 260 | void setTopicVelocity(String str) { 261 | _topicVelocity = str; 262 | } 263 | 264 | void setTopicMap(String str) { 265 | _topicMap = str; 266 | } 267 | 268 | void setTopicNavigation(String str) { 269 | _topicNavigation = str; 270 | } 271 | 272 | void setTopicChatter(String str) { 273 | _topicChatter = str; 274 | } 275 | 276 | void setWebCameraAdress(String str) { 277 | _webCameraAdress = str; 278 | } 279 | 280 | void setWebMapAdress(String str) { 281 | _webMapAdress = str; 282 | } 283 | 284 | void toggleMapGrid() { 285 | _showMapGrid = !_showMapGrid; 286 | notifyListeners(); 287 | } 288 | } 289 | -------------------------------------------------------------------------------- /lib/screens/ChatPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/widgets/ChatBar.dart'; 2 | import 'package:chatapp/widgets/FavoriteShelf.dart'; 3 | import 'package:chatapp/widgets/MessagesList.dart'; 4 | import 'package:chatapp/widgets/ShadowLine.dart'; 5 | import 'package:flutter/material.dart'; 6 | 7 | class ChatPage extends StatelessWidget { 8 | const ChatPage({Key key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Container( 13 | child: Column( 14 | children: [ 15 | Messageslist(), 16 | // Divider( 17 | // height: 0, 18 | // thickness: 0.5, 19 | // ), 20 | ShadowLine(), 21 | FavoriteShelf(), 22 | ChatBar(), 23 | ], 24 | ), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lib/screens/ControllerPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/generated/l10n.dart'; 2 | import 'package:chatapp/providers/RosProvider.dart'; 3 | import 'package:chatapp/providers/SettingsProvider.dart'; 4 | import 'package:chatapp/widgets/RainbowCircularIndicator.dart'; 5 | import 'package:chatapp/widgets/ShadowLine.dart'; 6 | import 'package:chatapp/widgets/StatusInfo.dart'; 7 | import 'package:chatapp/widgets/WirtualController.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:provider/provider.dart'; 10 | 11 | class ControllerPage extends StatelessWidget { 12 | const ControllerPage({Key key}) : super(key: key); 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Column( 17 | children: [ 18 | Expanded( 19 | child: Stack( 20 | alignment: AlignmentDirectional.topStart, 21 | fit: StackFit.expand, 22 | children: [ 23 | Consumer2( 24 | builder: (ctx, settingsProvider, rosProvider, child) => 25 | Container( 26 | child: rosProvider.cameraImageAvailable 27 | ? Image.memory( 28 | rosProvider.cameraImage.data, 29 | gaplessPlayback: true, 30 | fit: MediaQuery.of(context).orientation == 31 | Orientation.portrait 32 | ? BoxFit.fitHeight 33 | : BoxFit.fitWidth, 34 | ) 35 | : Column( 36 | mainAxisAlignment: MainAxisAlignment.center, 37 | crossAxisAlignment: CrossAxisAlignment.center, 38 | children: [ 39 | Text(S?.of(context)?.pageControllerInfoTitle, 40 | style: Theme.of(context).textTheme.subtitle1, 41 | textAlign: TextAlign.center), 42 | Text('${settingsProvider.topicCamera}', 43 | style: Theme.of(context).textTheme.caption, 44 | textAlign: TextAlign.center), 45 | SizedBox( 46 | height: 15, 47 | ), 48 | RainbowCircularIndicator() 49 | ], 50 | ), 51 | ), 52 | ), 53 | StatusInfo(), 54 | MediaQuery.of(context).orientation == Orientation.landscape 55 | ? Align( 56 | alignment: Alignment.bottomRight, 57 | child: _JoystickConfigurationLandscape()) 58 | : SizedBox(), 59 | ], 60 | ), 61 | ), 62 | ShadowLine(), 63 | MediaQuery.of(context).orientation == Orientation.portrait 64 | ? _JoystickConfigurationPortrait() 65 | : SizedBox(), 66 | ], 67 | ); 68 | } 69 | } 70 | 71 | class _JoystickConfigurationPortrait extends StatelessWidget { 72 | const _JoystickConfigurationPortrait({Key key}) : super(key: key); 73 | 74 | @override 75 | Widget build(BuildContext context) { 76 | return Container( 77 | color: Theme.of(context).canvasColor, 78 | height: MediaQuery.of(context).size.height / 3.6, 79 | child: Center( 80 | child: Container( 81 | child: WirtualController( 82 | baseSize: MediaQuery.of(context).size.height / 3.9, 83 | stickSize: MediaQuery.of(context).size.height / 3.9 * 0.4, 84 | onStickMove: (offset) { 85 | joystickMove(offset, context); 86 | }, 87 | ), 88 | ), 89 | ), 90 | ); 91 | } 92 | } 93 | 94 | class _JoystickConfigurationLandscape extends StatelessWidget { 95 | const _JoystickConfigurationLandscape({Key key}) : super(key: key); 96 | 97 | @override 98 | Widget build(BuildContext context) { 99 | return Padding( 100 | padding: const EdgeInsets.all(40.0), 101 | child: Container( 102 | color: Colors.transparent, 103 | // height: MediaQuery.of(context).size.height / 4, 104 | child: Container( 105 | child: WirtualController( 106 | baseSize: MediaQuery.of(context).size.height / 2.5, 107 | stickSize: MediaQuery.of(context).size.height / 2.5 * 0.4, 108 | onStickMove: (offset) { 109 | joystickMove(offset, context); 110 | }, 111 | ), 112 | ), 113 | ), 114 | ); 115 | } 116 | } 117 | 118 | void joystickMove(Offset offset, BuildContext context) { 119 | var msg = Provider.of(context, listen: false).velocityPublished; 120 | 121 | msg.linear.x = -offset.dy * 0.4; 122 | msg.angular.z = -offset.dx; 123 | } 124 | -------------------------------------------------------------------------------- /lib/screens/MainPage.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/generated/l10n.dart'; 2 | import 'package:chatapp/providers/AppStateProvider.dart'; 3 | import 'package:chatapp/providers/RosProvider.dart'; 4 | import 'package:chatapp/providers/SettingsProvider.dart'; 5 | import 'package:chatapp/screens/SettingsPageNew.dart'; 6 | import 'package:chatapp/widgets/ShadowLine.dart'; 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter/services.dart'; 9 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 10 | import 'package:provider/provider.dart'; 11 | 12 | import 'ChatPage.dart'; 13 | import 'ControllerPage.dart'; 14 | import 'MapPage.dart'; 15 | 16 | class MainPage extends StatelessWidget { 17 | var appPages = [ChatPage(), ControllerPage(), MapPage()]; 18 | 19 | @override 20 | Widget build(BuildContext context) { 21 | var appPagesNames = [ 22 | S?.of(context)?.pageChatTitle ?? "", 23 | S?.of(context)?.pageControllerTitle ?? "", 24 | S?.of(context)?.pageMapTitle ?? "" 25 | ]; 26 | return AnnotatedRegion( 27 | value: SystemUiOverlayStyle.light.copyWith( 28 | statusBarColor: Colors.transparent, 29 | systemNavigationBarColor: Theme.of(context).canvasColor, 30 | systemNavigationBarIconBrightness: 31 | Theme.of(context).brightness == Brightness.dark 32 | ? Brightness.light 33 | : Brightness.dark), 34 | child: Scaffold( 35 | extendBody: false, 36 | appBar: AppBar( 37 | backgroundColor: Theme.of(context).canvasColor, 38 | bottom: PreferredSize( 39 | preferredSize: const Size.fromHeight(0), child: ShadowLine()), 40 | toolbarHeight: MediaQuery.of(context).orientation == Orientation.portrait 41 | ? null 42 | : 45, 43 | title: Consumer( 44 | builder: (context, myType, child) => Text( 45 | appPagesNames[ 46 | Provider.of(context).activePageIndex], 47 | style: TextStyle( 48 | color: Theme.of(context).brightness == Brightness.light 49 | ? Colors.black54 50 | : Colors.white)), 51 | ), 52 | actions: [ 53 | //IconButtonsForAlternativeNavigation 54 | MediaQuery.of(context).orientation == Orientation.landscape 55 | ? _NavigationIconsRow() 56 | : SizedBox(), 57 | 58 | IconButton( 59 | tooltip: S?.of(context)?.tooltipRefreshConnection ?? "", 60 | icon: Icon(MdiIcons.refresh, 61 | // size: 30, 62 | color: Theme.of(context).brightness == Brightness.light 63 | ? Colors.black54 64 | : Colors.white), 65 | onPressed: () { 66 | Provider.of(context, listen: false) 67 | .subscribeRosAllTopics(context); 68 | }, 69 | ), 70 | 71 | IconButton( 72 | tooltip: S?.of(context)?.tooltipStopActions ?? "", 73 | icon: Icon(MdiIcons.stop, 74 | // size: 30, 75 | color: Theme.of(context).brightness == Brightness.light 76 | ? Colors.black54 77 | : Colors.white), 78 | onPressed: () { 79 | Provider.of(context, listen: false) 80 | .unsubscribeRosAllTopics(context); 81 | }, 82 | ), 83 | 84 | IconButton( 85 | tooltip: S?.of(context)?.tooltipSettings ?? "", 86 | icon: Icon(MdiIcons.cog, 87 | color: Theme.of(context).brightness == Brightness.light 88 | ? Colors.black54 89 | : Colors.white), 90 | onPressed: () { 91 | Navigator.push( 92 | context, 93 | MaterialPageRoute( 94 | builder: (context) => SettingsPageNew())); 95 | }), 96 | ]), 97 | // bottomNavigationBar: Consumer2( 98 | // builder: (BuildContext context, appStateProvider, 99 | // settingsProvider, Widget child) => 100 | // CustomNavigationBar( 101 | // background: Theme.of(context).canvasColor, 102 | // buttons: [ 103 | // CustomNavigationBarIcon( 104 | // icon: Icon(Icons.chat_sharp), 105 | // label: 'Czat', 106 | // onPressed: () { 107 | // appStateProvider.setActivePage(0); 108 | // }, 109 | // showLabel: false, 110 | // selectedColo: 111 | // Theme.of(context).brightness == Brightness.light 112 | // ? Colors.black54 113 | // : Colors.white, 114 | // unselectedColor: 115 | // Theme.of(context).brightness == Brightness.light 116 | // ? Colors.black12 117 | // : Colors.white24, 118 | // index: 0, 119 | // pageIndex: appStateProvider.activePageIndex, 120 | // ), 121 | // CustomNavigationBarIcon( 122 | // icon: Icon(MdiIcons.gamepadUp), 123 | // label: 'Sterowanie', 124 | // onPressed: () { 125 | // appStateProvider.setActivePage(1); 126 | // }, 127 | // showLabel: true, 128 | // selectedColo: 129 | // Theme.of(context).brightness == Brightness.light 130 | // ? Colors.black54 131 | // : Colors.white, 132 | // unselectedColor: 133 | // Theme.of(context).brightness == Brightness.light 134 | // ? Colors.black12 135 | // : Colors.white24, 136 | // index: 1, 137 | // pageIndex: appStateProvider.activePageIndex, 138 | // ), 139 | // CustomNavigationBarIcon( 140 | // icon: Icon(MdiIcons.earthBox), 141 | // label: 'Mapa', 142 | // onPressed: () { 143 | // appStateProvider.setActivePage(2); 144 | // }, 145 | // showLabel: false, 146 | // selectedColo: 147 | // Theme.of(context).brightness == Brightness.light 148 | // ? Colors.black54 149 | // : Colors.white, 150 | // unselectedColor: 151 | // Theme.of(context).brightness == Brightness.light 152 | // ? Colors.black12 153 | // : Colors.white24, 154 | // index: 2, 155 | // pageIndex: appStateProvider.activePageIndex, 156 | // ), 157 | // ], 158 | // )), 159 | 160 | //MATERIAL BOTTOM NAVIGATION BAR 161 | bottomNavigationBar: MediaQuery.of(context).orientation == 162 | Orientation.portrait 163 | ? Consumer2( 164 | builder: (BuildContext context, appStateProvider, 165 | settingsProvider, Widget child) => 166 | BottomNavigationBar( 167 | currentIndex: appStateProvider.activePageIndex, 168 | backgroundColor: Theme.of(context).canvasColor, 169 | showSelectedLabels: 170 | settingsProvider.showNavigationBarLabels ?? false, 171 | showUnselectedLabels: 172 | settingsProvider.showNavigationBarLabels ?? false, 173 | unselectedFontSize: 174 | Theme.of(context).textTheme.bodyText2.fontSize, 175 | selectedFontSize: 176 | Theme.of(context).textTheme.bodyText2.fontSize, 177 | elevation: 0, 178 | unselectedItemColor: 179 | Theme.of(context).brightness == Brightness.light 180 | ? Colors.black12 181 | : Colors.white24, 182 | selectedItemColor: 183 | Theme.of(context).brightness == Brightness.light 184 | ? Colors.black54 185 | : Colors.white, 186 | items: [ 187 | BottomNavigationBarItem( 188 | label: S?.of(context)?.pageChatTitle ?? "", 189 | icon: Icon(Icons.chat_sharp), 190 | ), 191 | BottomNavigationBarItem( 192 | icon: Icon(MdiIcons.gamepadUp), 193 | label: S?.of(context)?.pageControllerTitle ?? "", 194 | ), 195 | BottomNavigationBarItem( 196 | // icon: Icon(MdiIcons.mapMarkerDistance), title: Text("Mapa")), 197 | icon: Icon(MdiIcons.earthBox), 198 | label: S?.of(context)?.pageMapTitle ?? "", 199 | ), 200 | ], 201 | onTap: (index) { 202 | appStateProvider.setActivePage(index); 203 | // Navigation with PagedView 204 | // Provider.of(context, listen: false) 205 | // .navigationBarPageController 206 | // .animateTo(index.toDouble(), 207 | // duration: Duration(milliseconds: 200), curve: Curves.linear); 208 | })) 209 | : SizedBox(), 210 | body: Consumer( 211 | builder: (context, provider, child) => appPages[provider.activePageIndex])), 212 | ); 213 | } 214 | } 215 | 216 | class _CustomNavigationBar extends StatelessWidget { 217 | final Color background; 218 | final List buttons; 219 | const _CustomNavigationBar( 220 | {Key key, @required this.background, @required this.buttons}) 221 | : super(key: key); 222 | 223 | @override 224 | Widget build(BuildContext context) { 225 | return Container( 226 | color: background, 227 | width: MediaQuery.of(context).size.width, 228 | child: Row( 229 | mainAxisSize: MainAxisSize.max, 230 | mainAxisAlignment: MainAxisAlignment.spaceEvenly, 231 | children: buttons, 232 | ), 233 | ); 234 | } 235 | } 236 | 237 | class _CustomNavigationBarIcon extends StatelessWidget { 238 | final Function onPressed; 239 | final Icon icon; 240 | final String label; 241 | final bool showLabel; 242 | final Color selectedColo; 243 | final Color unselectedColor; 244 | final int index; 245 | final int pageIndex; 246 | 247 | const _CustomNavigationBarIcon( 248 | {Key key, 249 | @required this.onPressed, 250 | @required this.icon, 251 | @required this.label, 252 | @required this.showLabel, 253 | @required this.selectedColo, 254 | @required this.unselectedColor, 255 | @required this.index, 256 | @required this.pageIndex}) 257 | : super(key: key); 258 | 259 | Widget build(BuildContext context) { 260 | return Container( 261 | child: Column( 262 | mainAxisSize: MainAxisSize.min, 263 | mainAxisAlignment: MainAxisAlignment.center, 264 | children: [ 265 | IconButton( 266 | tooltip: label, 267 | icon: icon, 268 | color: index == pageIndex ? selectedColo : unselectedColor, 269 | onPressed: onPressed), 270 | ], 271 | ), 272 | ); 273 | } 274 | } 275 | 276 | //Used for landscape navigation mode 277 | class _NavigationIconsRow extends StatelessWidget { 278 | const _NavigationIconsRow({Key key}) : super(key: key); 279 | 280 | @override 281 | Widget build(BuildContext context) { 282 | return Row( 283 | children: [ 284 | IconButton( 285 | tooltip: "Czat", 286 | icon: Icon(Icons.chat_sharp, 287 | // size: 30, 288 | color: Provider.of(context, listen: true) 289 | .activePageIndex == 290 | 0 291 | ? Theme.of(context).brightness == Brightness.light 292 | ? Colors.black54 293 | : Colors.white 294 | : Theme.of(context).brightness == Brightness.light 295 | ? Colors.black12 296 | : Colors.white24), 297 | onPressed: () { 298 | Provider.of(context, listen: false) 299 | .setActivePage(0); 300 | }, 301 | ), 302 | VerticalDivider(), 303 | IconButton( 304 | tooltip: "Sterowanie", 305 | icon: Icon(MdiIcons.gamepadUp, 306 | // size: 30, 307 | color: Provider.of(context, listen: true) 308 | .activePageIndex == 309 | 1 310 | ? Theme.of(context).brightness == Brightness.light 311 | ? Colors.black54 312 | : Colors.white 313 | : Theme.of(context).brightness == Brightness.light 314 | ? Colors.black12 315 | : Colors.white24), 316 | onPressed: () { 317 | Provider.of(context, listen: false) 318 | .setActivePage(1); 319 | }, 320 | ), 321 | VerticalDivider(), 322 | IconButton( 323 | tooltip: "Mapa", 324 | icon: Icon(MdiIcons.earthBox, 325 | // size: 30, 326 | color: Provider.of(context, listen: true) 327 | .activePageIndex == 328 | 2 329 | ? Theme.of(context).brightness == Brightness.light 330 | ? Colors.black54 331 | : Colors.white 332 | : Theme.of(context).brightness == Brightness.light 333 | ? Colors.black12 334 | : Colors.white24), 335 | onPressed: () { 336 | Provider.of(context, listen: false) 337 | .setActivePage(2); 338 | }, 339 | ), 340 | VerticalDivider( 341 | width: 0, 342 | ), 343 | ], 344 | ); 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /lib/screens/MapPage.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui' as ui; 2 | 3 | import 'package:chatapp/generated/l10n.dart'; 4 | import 'package:chatapp/providers/RosProvider.dart'; 5 | import 'package:chatapp/providers/SettingsProvider.dart'; 6 | import 'package:chatapp/widgets/MapPainter.dart'; 7 | import 'package:chatapp/widgets/MapShelfButtons.dart'; 8 | import 'package:chatapp/widgets/RainbowCircularIndicator.dart'; 9 | import 'package:chatapp/widgets/ShadowLine.dart'; 10 | import 'package:chatapp/widgets/StatusInfo.dart'; 11 | import 'package:chatapp/widgets/WaypointDialog.dart'; 12 | import 'package:chatapp/widgets/WaypointShelf.dart'; 13 | import 'package:flutter/material.dart'; 14 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 15 | import 'package:provider/provider.dart'; 16 | 17 | class MapPage extends StatefulWidget { 18 | const MapPage({Key key}) : super(key: key); 19 | 20 | @override 21 | _MapPageState createState() => _MapPageState(); 22 | } 23 | 24 | class _MapPageState extends State with TickerProviderStateMixin { 25 | ui.Image previousMap; 26 | @override 27 | Widget build(BuildContext context) { 28 | return Stack( 29 | fit: StackFit.expand, 30 | children: [ 31 | Positioned( 32 | bottom: 45, 33 | left: 0, 34 | right: 0, 35 | top: 0, 36 | child: Provider.of(context, listen: true) 37 | .mapImageAvailable 38 | ? Container( 39 | // color: Theme.of(context).canvasColor, 40 | child: Consumer2( 41 | builder: (ctx, settingsProvider, rosProvider, child) { 42 | assert(rosProvider.mapImage != null); 43 | return InteractiveViewer( 44 | maxScale: 10, 45 | child: Container( 46 | width: double.infinity, 47 | child: Center( 48 | child: FutureBuilder( 49 | future: rosProvider.getMapAsImage( 50 | Theme.of(context).backgroundColor, 51 | Theme.of(context).brightness == Brightness.light 52 | ? Colors.black 53 | : Colors.grey[300]), 54 | initialData: previousMap, 55 | builder: (_, img) { 56 | if (img.data == null) { 57 | return SizedBox(); 58 | } 59 | previousMap = img.data; 60 | return Map( 61 | map: img.data, 62 | showGrid: settingsProvider.showMapGrid); 63 | }), 64 | ), 65 | ), 66 | ); 67 | })) 68 | : Consumer( 69 | builder: (ctx, settingsProvider, child) => Column( 70 | mainAxisAlignment: MainAxisAlignment.center, 71 | children: [ 72 | Text(S?.of(context)?.pageMapInfoTitle, 73 | style: Theme.of(context).textTheme.subtitle1, 74 | textAlign: TextAlign.center), 75 | Text('${settingsProvider.topicMap}', 76 | style: Theme.of(context).textTheme.caption, 77 | textAlign: TextAlign.center), 78 | SizedBox(height: 15), 79 | RainbowCircularIndicator(), 80 | ])), 81 | ), 82 | Positioned(child: StatusInfo()), 83 | Positioned( 84 | bottom: 52, 85 | left: 0, 86 | child: MapShelfButtons(), 87 | ), 88 | Positioned(bottom: 0, left: 0, right: 0, child: WaypointShelf()), 89 | Positioned( 90 | bottom: 45, 91 | right: 0, 92 | left: 0, 93 | child: ShadowLine(), 94 | ), 95 | Positioned( 96 | bottom: 0, 97 | right: 0, 98 | child: Padding( 99 | padding: const EdgeInsets.only(bottom: 55, right: 10), 100 | child: Column(mainAxisAlignment: MainAxisAlignment.end, children: [ 101 | Padding( 102 | padding: const EdgeInsets.only(bottom: 8), 103 | child: FloatingActionButton( 104 | backgroundColor: 105 | Theme.of(context).chipTheme.backgroundColor, 106 | heroTag: null, 107 | tooltip: S?.of(context)?.pageMapButtonFloating, 108 | onPressed: () { 109 | showDialog( 110 | context: context, builder: (_) => WaypointDialog()); 111 | }, 112 | child: Icon(MdiIcons.plus, 113 | color: Theme.of(context).brightness == Brightness.light 114 | ? Colors.black45 115 | : Colors.white), 116 | mini: false), 117 | ), 118 | // FloatingActionButton( 119 | // heroTag: null, 120 | // backgroundColor: Theme.of(context).chipTheme.backgroundColor, 121 | // elevation: Provider.of(context).mapImageAvailable 122 | // ? null 123 | // : 0, 124 | // tooltip: 'Przejedź robotem do wybranego znacznika', 125 | // onPressed: () {}, 126 | // child: Icon(Icons.directions, 127 | // color: Provider.of(context).mapImageAvailable 128 | // ? Theme.of(context).brightness == Brightness.light 129 | // ? Colors.black45 130 | // : Colors.white 131 | // : Theme.of(context).brightness == Brightness.light 132 | // ? Colors.black12 133 | // : Colors.white24), 134 | // mini: false), 135 | ]), 136 | ), 137 | ) 138 | ], 139 | ); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /lib/widgets/ColorPickerCustom.dart: -------------------------------------------------------------------------------- 1 | /// HSV(HSB)/HSL Color Picker example 2 | /// 3 | /// You can create your own layout by importing `hsv_picker.dart`. 4 | /// BASED ON @mchome https://github.com/mchome/flutter_colorpicker 5 | /// https://pub.flutter-io.cn/packages/flutter_colorpicker/example 6 | 7 | import 'package:flutter/material.dart'; 8 | import 'package:flutter_colorpicker/flutter_colorpicker.dart'; 9 | 10 | class ColorPickerModified extends StatefulWidget { 11 | final double width; 12 | final double height; 13 | final Color pickerColor; 14 | final BorderRadius pickerAreaBorderRadius; 15 | final ValueChanged onColorChanged; 16 | final Color textColor; 17 | final String hueLabel; 18 | 19 | const ColorPickerModified({ 20 | @required this.pickerColor, 21 | @required this.onColorChanged, 22 | @required this.textColor, 23 | @required this.hueLabel, 24 | this.width: 300.0, 25 | this.height: 200.0, 26 | this.pickerAreaBorderRadius: const BorderRadius.all(Radius.zero), 27 | }) : assert(pickerAreaBorderRadius != null); 28 | 29 | @override 30 | _ColorPickerModifiedState createState() => _ColorPickerModifiedState(); 31 | } 32 | 33 | class _ColorPickerModifiedState extends State { 34 | HSVColor currentHsvColor = const HSVColor.fromAHSV(0.0, 0.0, 0.0, 0.0); 35 | 36 | var _r = TextEditingController(); 37 | var _g = TextEditingController(); 38 | var _b = TextEditingController(); 39 | 40 | @override 41 | void initState() { 42 | super.initState(); 43 | currentHsvColor = HSVColor.fromColor(widget.pickerColor); 44 | var color = currentHsvColor.toColor(); 45 | 46 | _r.value = TextEditingValue(text: color.red.toString()); 47 | _g.value = TextEditingValue(text: color.green.toString()); 48 | _b.value = TextEditingValue(text: color.blue.toString()); 49 | } 50 | 51 | Widget colorPickerArea() { 52 | return ClipRRect( 53 | borderRadius: widget.pickerAreaBorderRadius, 54 | child: ColorPickerArea( 55 | currentHsvColor, 56 | (HSVColor color) { 57 | setState(() => currentHsvColor = color); 58 | updateColor(color.toColor()); 59 | }, 60 | PaletteType.hsv, 61 | )); 62 | } 63 | 64 | void updateColor(Color color) { 65 | _r.value = TextEditingValue(text: color.red.toString()); 66 | _g.value = TextEditingValue(text: color.green.toString()); 67 | _b.value = TextEditingValue(text: color.blue.toString()); 68 | widget.onColorChanged(color); 69 | } 70 | 71 | @override 72 | Widget build(BuildContext context) { 73 | var currentColor = currentHsvColor.toColor(); 74 | 75 | return Column( 76 | children: [ 77 | SizedBox( 78 | width: widget.width, 79 | height: widget.height, 80 | child: colorPickerArea()), 81 | Padding( 82 | padding: 83 | const EdgeInsets.only(top: 10, bottom: 5, left: 0, right: 0), 84 | child: Row( 85 | mainAxisAlignment: MainAxisAlignment.center, 86 | children: [ 87 | Container( 88 | height: 44, 89 | width: 44, 90 | decoration: BoxDecoration( 91 | borderRadius: widget.pickerAreaBorderRadius, 92 | color: currentColor)), 93 | Expanded( 94 | child: SizedBox( 95 | height: 48.0, 96 | width: widget.width, 97 | child: SliderTheme( 98 | data: Theme.of(context).sliderTheme.copyWith( 99 | trackShape: RectangularSliderTrackShape(), 100 | trackHeight: 2), 101 | child: Stack( 102 | fit: StackFit.expand, 103 | children: [ 104 | Padding( 105 | padding: const EdgeInsets.only(left: 25.0), 106 | child: Text( 107 | widget.hueLabel, 108 | style: Theme.of(context) 109 | .textTheme 110 | .overline 111 | .merge(TextStyle( 112 | color: widget.textColor)), 113 | ), 114 | ), 115 | Slider( 116 | activeColor: currentHsvColor.toColor(), 117 | min: 0, 118 | max: 360, 119 | value: currentHsvColor.hue, 120 | onChanged: (double value) { 121 | setState(() { 122 | currentHsvColor = HSVColor.fromAHSV( 123 | currentHsvColor.alpha, 124 | value, 125 | currentHsvColor.saturation, 126 | currentHsvColor.value); 127 | }); 128 | updateColor(currentHsvColor.toColor()); 129 | }), 130 | ], 131 | )))) 132 | ])), 133 | Row( 134 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 135 | children: [ 136 | Expanded( 137 | child: TextField( 138 | style: TextStyle(color: widget.textColor), 139 | controller: _r, 140 | keyboardType: TextInputType.number, 141 | onSubmitted: (text) { 142 | setState(() { 143 | var red = int.parse(text); 144 | currentHsvColor = HSVColor.fromColor(Color.fromRGBO( 145 | red, currentColor.green, currentColor.blue, 1)); 146 | }); 147 | updateColor(currentHsvColor.toColor()); 148 | }, 149 | decoration: InputDecoration( 150 | labelText: "R", 151 | contentPadding: const EdgeInsets.all(5)))), 152 | SizedBox( 153 | width: 2, 154 | ), 155 | Expanded( 156 | child: TextField( 157 | style: TextStyle(color: widget.textColor), 158 | controller: _g, 159 | keyboardType: TextInputType.number, 160 | onSubmitted: (text) { 161 | setState(() { 162 | var green = int.parse(text); 163 | currentHsvColor = HSVColor.fromColor(Color.fromRGBO( 164 | currentColor.red, green, currentColor.blue, 1)); 165 | }); 166 | updateColor(currentHsvColor.toColor()); 167 | }, 168 | decoration: InputDecoration( 169 | labelText: "G", 170 | contentPadding: const EdgeInsets.all(5)))), 171 | SizedBox( 172 | width: 2, 173 | ), 174 | Expanded( 175 | child: TextField( 176 | style: TextStyle(color: widget.textColor), 177 | controller: _b, 178 | keyboardType: TextInputType.number, 179 | onSubmitted: (text) { 180 | setState(() { 181 | var blue = int.parse(text); 182 | currentHsvColor = HSVColor.fromColor(Color.fromRGBO( 183 | currentColor.red, currentColor.green, blue, 1)); 184 | }); 185 | updateColor(currentHsvColor.toColor()); 186 | }, 187 | decoration: InputDecoration( 188 | labelText: "B", 189 | contentPadding: const EdgeInsets.all(5)))), 190 | ], 191 | ) 192 | ], 193 | ); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /lib/widgets/FavoriteShelf.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/models/Message.dart'; 2 | import 'package:chatapp/providers/ChatInfoProvider.dart'; 3 | import 'package:chatapp/providers/DialogflowProvider.dart'; 4 | import 'package:chatapp/providers/RosProvider.dart'; 5 | import 'package:chatapp/providers/SettingsProvider.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:provider/provider.dart'; 8 | import 'package:chatapp/models/ListExtension.dart'; 9 | 10 | class FavoriteShelf extends StatelessWidget { 11 | List buildSugestions(BuildContext context) { 12 | var chatInfoProvider = Provider.of(context); 13 | var message = chatInfoProvider.messages.last; 14 | Color textColor = Theme.of(context).accentColor.computeLuminance() > 0.4 15 | ? Colors.black.withOpacity(0.6) 16 | : Colors.white; 17 | 18 | var textTheme = Theme.of(context) 19 | .textTheme 20 | .subtitle1 21 | .merge(TextStyle(color: textColor)); 22 | 23 | if (message.aiResponse == null) { 24 | return []; 25 | } 26 | 27 | var params = message.aiResponse.suggestions; 28 | return params 29 | .map( 30 | (suggestion) => GestureDetector( 31 | child: Chip( 32 | shape: RoundedRectangleBorder( 33 | borderRadius: BorderRadius.circular(8)), 34 | label: Text( 35 | suggestion['title'], 36 | style: textTheme, 37 | ), 38 | backgroundColor: Theme.of(context).accentColor, 39 | ), 40 | onTap: () { 41 | chatInfoProvider.addMessage( 42 | message: 43 | Message(body: suggestion['title'], sender: Sender.user)); 44 | Provider.of(context, listen: false) 45 | .response(suggestion['title']) 46 | .then((response) { 47 | chatInfoProvider.addMessage( 48 | message: Message( 49 | body: response.getMessage(), 50 | sender: Sender.bot, 51 | aiResponse: response)); 52 | 53 | //Supply response to matching Intent (to get action done) 54 | Provider.of(context, listen: false) 55 | .matchIntent(response, context); 56 | }); 57 | }, 58 | ), 59 | ) 60 | .toList(); 61 | } 62 | 63 | @override 64 | Widget build(BuildContext context) { 65 | return Material( 66 | color: Theme.of(context).canvasColor, 67 | // color: Colors.transparent, 68 | child: Consumer2( 69 | builder: (context, chatInfoProvider, settingsProvider, child) { 70 | var isUser = 71 | (chatInfoProvider.messages.last?.sender == Sender.user) ?? true; 72 | var suggestionAvailable = chatInfoProvider 73 | .messages.last?.aiResponse?.suggestions?.isNotEmpty ?? 74 | false; 75 | return Container( 76 | child: AnimatedContainer( 77 | height: chatInfoProvider.favoriteShelfOpen && suggestionAvailable 78 | ? 40 79 | : 0, 80 | width: MediaQuery.of(context).size.width, 81 | duration: Duration( 82 | milliseconds: 83 | WidgetsBinding.instance.disableAnimations ? 0 : 150), 84 | child: !isUser 85 | ? Padding( 86 | padding: const EdgeInsets.only(top: 4.0), 87 | child: ListView( 88 | physics: settingsProvider.limitAnimations ?? false 89 | ? null 90 | : BouncingScrollPhysics(), 91 | reverse: false, 92 | padding: EdgeInsets.symmetric( 93 | horizontal: 10, 94 | ), 95 | scrollDirection: Axis.horizontal, 96 | shrinkWrap: false, 97 | children: buildSugestions(context).insertEveryNth( 98 | SizedBox(width: 5), 99 | ), 100 | ), 101 | ) 102 | : SizedBox(), 103 | ), 104 | ); 105 | }, 106 | ), 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /lib/widgets/MapPainter.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/models/Waypoint.dart'; 2 | import 'package:chatapp/providers/RosProvider.dart'; 3 | import 'package:chatapp/providers/SettingsProvider.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:provider/provider.dart'; 6 | import 'dart:ui' as ui; 7 | import 'package:vector_math/vector_math.dart' show radians, Quaternion; 8 | import 'dart:math' as math; 9 | 10 | import 'package:ros_nodes/messages/nav_msgs/Odometry.dart'; 11 | 12 | class MapPainter extends CustomPainter { 13 | final double waveRadius; 14 | final Color waveAccentColor; 15 | final Color waveColor; 16 | final NavMsgsOdometry robotOdom; 17 | final ui.Image map; 18 | final WaypointList waypoints; 19 | final Waypoint activeWaypoint; 20 | 21 | Paint wavePaint, wavePaint2, solidPaint, waypointPaint; 22 | double robotFootprint = 4.0; 23 | double maxRadius = 15; 24 | double gaps = 5; 25 | bool debugGrig; 26 | 27 | double waypointMinSize = 3; 28 | double waypointRadiusMax = 5; 29 | int waypointSides = 4; 30 | 31 | MapPainter({ 32 | @required this.map, 33 | @required this.waveRadius, 34 | @required this.waveAccentColor, 35 | @required this.waveColor, 36 | @required this.robotOdom, 37 | @required this.waypoints, 38 | @required this.activeWaypoint, 39 | this.debugGrig = false, 40 | }) { 41 | wavePaint = Paint() 42 | ..color = waveColor 43 | ..style = PaintingStyle.fill 44 | ..strokeWidth = 0.5 45 | ..isAntiAlias = true; 46 | wavePaint2 = Paint() 47 | ..color = waveAccentColor 48 | ..style = PaintingStyle.stroke 49 | ..strokeWidth = 0.5 50 | ..isAntiAlias = true; 51 | solidPaint = Paint() 52 | ..color = waveColor 53 | ..style = PaintingStyle.fill 54 | ..strokeWidth = 0.5 55 | ..isAntiAlias = true; 56 | waypointPaint = Paint() 57 | ..style = PaintingStyle.fill 58 | ..strokeWidth = 0.5 59 | ..isAntiAlias = true; 60 | } 61 | 62 | @override 63 | void paint(Canvas canvas, Size size) { 64 | canvas.save(); 65 | { 66 | // canvas.scale(1, -1); 67 | // canvas.translate(0, map.height.toDouble()); 68 | 69 | canvas.translate(map.width / 2, map.height / 2.5); 70 | canvas.rotate(radians(180)); 71 | canvas.translate(-map.width / 2, -map.height / 2); 72 | canvas.scale(1, -1); 73 | canvas.translate(0, -map.height.toDouble()); 74 | 75 | canvas.save(); 76 | { 77 | //Przesunięcie obrazu o magic number. 78 | //Pozycja robota jest zaliczana jako środek przodu robota, 79 | //stąd jest lekka różnica w oczekiwanym położeniu 80 | canvas.translate(-6, -6); 81 | canvas.drawImage(map, Offset.zero, Paint()); 82 | } 83 | canvas.restore(); 84 | 85 | canvas.save(); 86 | { 87 | double centerX = map.width / 2; 88 | double centerY = map.height / 2; 89 | canvas.translate(centerX, centerY); 90 | 91 | final resolution = 0.05; 92 | 93 | //Siatka do debugowania pozycji na mapie 94 | //region 95 | if (debugGrig) { 96 | for (var i = -20; i <= 20; i++) { 97 | canvas.drawLine( 98 | Offset(i / resolution, -20 / resolution), 99 | Offset(i / resolution, 20 / resolution), 100 | Paint()..color = Colors.grey.withOpacity(0.3), 101 | ); 102 | canvas.drawLine( 103 | Offset(-10 / resolution, i / resolution), 104 | Offset(10 / resolution, i / resolution), 105 | Paint()..color = Colors.grey.withOpacity(0.3), 106 | ); 107 | } 108 | } 109 | //endregion 110 | 111 | //draw waypoints 112 | // var miliseconds = DateTime.now().millisecondsSinceEpoch; 113 | // var animationSizePercent = (miliseconds % 1700) / 1700; 114 | // for (var item in waypoints.waypoints) { 115 | // canvas.save(); 116 | // { 117 | // canvas.translate(item.x / resolution, item.y / resolution); 118 | // canvas.drawPath( 119 | // drawNSide( 120 | // 6, 121 | // waypointMinSize + 122 | // (animationSizePercent * 123 | // (waypointRadiusMax - waypointMinSize)), 124 | // ), 125 | // waypointPaint 126 | // ..color = item.color.withOpacity(animationSizePercent)); 127 | // canvas.restore(); 128 | // } 129 | // } 130 | double robotPositionX = (robotOdom.pose.pose.position.x) / resolution; 131 | double robotPositionY = (robotOdom.pose.pose.position.y) / resolution; 132 | 133 | //draw robot 134 | var robotCenter = Offset(0, 0); 135 | var currentRadius = waveRadius; 136 | bool drawOnce = true; 137 | while (currentRadius < maxRadius) { 138 | //Drawing waypoints 139 | for (var item in waypoints.waypoints) { 140 | bool active = item == activeWaypoint; 141 | canvas.save(); 142 | canvas.translate(item.x / resolution, item.y / resolution); 143 | //---Pulsating inner 144 | if (active) { 145 | canvas.drawPath( 146 | drawNSide(waypointSides, currentRadius * 0.8), 147 | waypointPaint 148 | ..style = PaintingStyle.fill 149 | ..strokeWidth = 1 150 | ..color = 151 | item.color.withOpacity(1 - currentRadius / maxRadius)); 152 | } 153 | //---Pulsating outer 154 | canvas.drawPath( 155 | drawNSide(waypointSides, currentRadius * 0.8), 156 | waypointPaint 157 | ..style = PaintingStyle.stroke 158 | ..strokeWidth = active ? 1 : 0.2 159 | ..color = 160 | item.color.withOpacity(1 - currentRadius / maxRadius)); 161 | //---Solid shape 162 | canvas.drawPath( 163 | drawNSide(waypointSides, 3), 164 | waypointPaint 165 | ..style = PaintingStyle.fill 166 | ..color = item.color.withOpacity(1)); 167 | canvas.restore(); 168 | } 169 | //Drawing robot 170 | canvas.save(); 171 | canvas.translate(robotPositionX, robotPositionY); 172 | 173 | //---Drawing Cone shape 174 | if (drawOnce) { 175 | canvas.save(); 176 | var robotRotation = Quaternion( 177 | robotOdom.pose.pose.orientation.x, 178 | robotOdom.pose.pose.orientation.y, 179 | robotOdom.pose.pose.orientation.z, 180 | robotOdom.pose.pose.orientation.w); 181 | canvas.rotate(robotOdom.pose.pose.orientation.x < 0 182 | ? robotRotation.radians 183 | : -robotRotation.radians); 184 | 185 | var rect = Rect.fromCircle( 186 | center: Offset(0, 0), 187 | radius: 15.0, 188 | ); 189 | 190 | var gradient = RadialGradient( 191 | colors: [ 192 | waveColor.withOpacity(0), 193 | waveColor.withOpacity(0), 194 | waveAccentColor.withOpacity(0.7), 195 | waveAccentColor.withOpacity(0.0), 196 | ], 197 | stops: [0.0, 0.25, 0.251, 1.0], 198 | ); 199 | 200 | //---/---/create the Shader from the gradient and the bounding square 201 | var paint = Paint()..shader = gradient.createShader(rect); 202 | 203 | canvas.drawPath(drawCone(15, 55), paint..isAntiAlias = true); 204 | canvas.restore(); 205 | //---/---/preventing blinking 206 | drawOnce = false; 207 | } 208 | canvas.drawCircle( 209 | robotCenter, 210 | currentRadius, 211 | wavePaint 212 | ..color = 213 | wavePaint.color.withOpacity(1 - currentRadius / maxRadius)); 214 | canvas.drawCircle( 215 | robotCenter, 216 | currentRadius, 217 | wavePaint2 218 | ..color = wavePaint2.color 219 | .withOpacity(1 - currentRadius / maxRadius)); 220 | canvas.drawCircle(robotCenter, 3, solidPaint); 221 | canvas.restore(); 222 | 223 | currentRadius += 7; 224 | } 225 | } 226 | canvas.restore(); 227 | } 228 | canvas.restore(); 229 | } 230 | 231 | Path drawNSide(int sides, double radius) { 232 | assert(sides >= 3); 233 | final shape = Path(); 234 | var angle = (math.pi * 2) / sides; 235 | // Offset firstPoint = Offset(radius * math.cos(0.0), radius * math.sin(0.0)); 236 | Offset firstPoint = Offset(radius * 1, 0); 237 | shape.moveTo(firstPoint.dx, firstPoint.dy); 238 | for (int i = 1; i <= sides; i++) { 239 | double shapeX = radius * math.cos(angle * i); 240 | double shapeY = radius * math.sin(angle * i); 241 | shape.lineTo(shapeX, shapeY); 242 | } 243 | shape.close(); 244 | return shape; 245 | } 246 | 247 | Path drawCone(double radius, double angle) { 248 | angle /= 2; 249 | final shape = Path(); 250 | Offset firstPoint = Offset(0, 0); 251 | Offset secondPoint = Offset( 252 | radius * math.cos(radians(-angle)), radius * math.sin(radians(-angle))); 253 | Offset thirdPoint = Offset( 254 | radius * math.cos(radians(angle)), radius * math.sin(radians(angle))); 255 | var rect = Rect.fromCircle( 256 | center: Offset(0, 0), 257 | radius: radius, 258 | ); 259 | 260 | shape.moveTo(firstPoint.dx, firstPoint.dy); 261 | shape.lineTo(secondPoint.dx, secondPoint.dy); 262 | shape.arcToPoint(thirdPoint, radius: Radius.circular(radius)); 263 | 264 | shape.close(); 265 | return shape; 266 | } 267 | 268 | @override 269 | bool shouldRepaint(MapPainter oldDelegate) { 270 | return oldDelegate.waveRadius != waveRadius || 271 | oldDelegate.map.hashCode != map.hashCode; 272 | } 273 | } 274 | 275 | class Map extends StatefulWidget { 276 | const Map({Key key, @required this.map, this.showGrid}) 277 | : assert(map != null), 278 | super(key: key); 279 | final ui.Image map; 280 | final showGrid; 281 | 282 | @override 283 | _MapState createState() => _MapState(); 284 | } 285 | 286 | class _MapState extends State with SingleTickerProviderStateMixin { 287 | double waveRadius = 0.0; 288 | double waveGap = 7.0; 289 | Animation _animation; 290 | AnimationController controller; 291 | 292 | @override 293 | void initState() { 294 | super.initState(); 295 | controller = AnimationController( 296 | duration: Duration(milliseconds: 1500), vsync: this); 297 | 298 | controller.forward(); 299 | 300 | controller.addStatusListener((status) { 301 | if (status == AnimationStatus.completed) { 302 | controller.reset(); 303 | } else if (status == AnimationStatus.dismissed) { 304 | controller.forward(); 305 | } 306 | }); 307 | } 308 | 309 | @override 310 | Widget build(BuildContext context) { 311 | _animation = Tween(begin: 0.0, end: waveGap).animate(controller) 312 | ..addListener(() { 313 | setState(() { 314 | waveRadius = _animation.value; 315 | }); 316 | }); 317 | return FittedBox( 318 | child: SizedBox( 319 | width: widget.map.width.toDouble(), 320 | height: widget.map.height.toDouble(), 321 | child: CustomPaint( 322 | painter: MapPainter( 323 | map: widget.map, 324 | debugGrig: widget.showGrid, 325 | waveRadius: waveRadius, 326 | waveAccentColor: Theme.of(context).accentColor, 327 | waveColor: Theme.of(context).brightness == Brightness.light 328 | ? Colors.amberAccent 329 | : Colors.cyanAccent, 330 | robotOdom: Provider.of(context).odometry, 331 | waypoints: Provider.of(context).waypoints, 332 | activeWaypoint: Provider.of(context).activeWaypoint), 333 | ), 334 | ), 335 | ); 336 | } 337 | 338 | @override 339 | void dispose() { 340 | controller.dispose(); 341 | super.dispose(); 342 | } 343 | } 344 | -------------------------------------------------------------------------------- /lib/widgets/MapShelfButtons.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/generated/l10n.dart'; 2 | import 'package:chatapp/providers/RosProvider.dart'; 3 | import 'package:chatapp/providers/SettingsProvider.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class MapShelfButtons extends StatelessWidget { 8 | const MapShelfButtons({Key key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Container( 13 | child: Wrap(children: [ 14 | Consumer2( 15 | builder: (context, settingsProvider, rosProvider, child) => 16 | FloatingActionButton( 17 | tooltip: S?.of(context)?.pageMapButtonGrid, 18 | backgroundColor: Theme.of(context).chipTheme.backgroundColor, 19 | elevation: Provider.of(context).mapImageAvailable 20 | ? null 21 | : 0, 22 | mini: true, 23 | child: Icon( 24 | settingsProvider.showMapGrid 25 | ? Icons.grid_on 26 | : Icons.grid_off, 27 | color: Provider.of(context).mapImageAvailable 28 | ? Theme.of(context).brightness == Brightness.light 29 | ? Colors.black45 30 | : Colors.white 31 | : Theme.of(context).brightness == Brightness.light 32 | ? Colors.black12 33 | : Colors.white24), 34 | onPressed: () { 35 | if (rosProvider.mapImageAvailable) 36 | settingsProvider.toggleMapGrid(); 37 | })) 38 | ])); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/widgets/MessagesList.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/providers/ChatInfoProvider.dart'; 2 | import 'package:chatapp/providers/SettingsProvider.dart'; 3 | import 'package:chatapp/widgets/BubbleMessage.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class Messageslist extends StatelessWidget { 8 | final controller = ScrollController(); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | Provider.of(context, listen: false).addListener( 13 | () async { 14 | await Future.delayed(Duration(milliseconds: 250)); 15 | if (controller.positions.isEmpty) return; 16 | if (WidgetsBinding.instance.disableAnimations) { 17 | controller.jumpTo( 18 | controller.position.maxScrollExtent, 19 | ); 20 | } else { 21 | controller.animateTo(controller.position.maxScrollExtent, 22 | duration: Duration(milliseconds: 500), curve: Curves.easeInOut); 23 | } 24 | }, 25 | ); 26 | return Flexible( 27 | child: Consumer( 28 | builder: (context, provider, child) => AnimatedList( 29 | physics: Provider.of(context, listen: false) 30 | .limitAnimations ?? 31 | false 32 | ? null 33 | : BouncingScrollPhysics(), 34 | padding: EdgeInsets.only(top: 5, bottom: 20, left: 0, right: 0), 35 | key: provider.listKey, 36 | reverse: false, 37 | controller: controller, 38 | initialItemCount: provider.messages.length, 39 | itemBuilder: (context, index, animation) { 40 | return SlideTransition( 41 | position: Tween( 42 | begin: const Offset(0, 1.5), 43 | end: Offset.zero, 44 | ).animate(animation), 45 | child: BubbleMessage( 46 | message: provider.messages[index], 47 | ), 48 | ); 49 | }, 50 | ), 51 | ), 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lib/widgets/RainbowCircularIndicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RainbowCircularIndicator extends StatefulWidget { 4 | RainbowCircularIndicator({Key key}) : super(key: key); 5 | 6 | @override 7 | _RainbowCircularIndicatorState createState() => 8 | _RainbowCircularIndicatorState(); 9 | } 10 | 11 | class _RainbowCircularIndicatorState extends State 12 | with TickerProviderStateMixin { 13 | AnimationController _controller; 14 | 15 | @override 16 | void initState() { 17 | super.initState(); 18 | _controller = AnimationController( 19 | vsync: this, // the SingleTickerProviderStateMixin 20 | duration: Duration(milliseconds: 2000), 21 | ); 22 | _controller.repeat(reverse: true); 23 | } 24 | 25 | @override 26 | void dispose() { 27 | _controller.dispose(); 28 | super.dispose(); 29 | } 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | return CircularProgressIndicator( 34 | valueColor: ColorTween( 35 | begin: Theme.of(context).accentColor, 36 | end: Theme.of(context).brightness == Brightness.light 37 | ? Colors.pinkAccent[100] 38 | : Colors.amber) 39 | .animate(_controller), 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/widgets/RainbowLinearIndicator.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RainbowLinearIndicator extends StatefulWidget { 4 | RainbowLinearIndicator({Key key}) : super(key: key); 5 | 6 | @override 7 | _RainbowLinearIndicatorState createState() => _RainbowLinearIndicatorState(); 8 | } 9 | 10 | class _RainbowLinearIndicatorState extends State 11 | with TickerProviderStateMixin { 12 | AnimationController _controller; 13 | 14 | @override 15 | void initState() { 16 | super.initState(); 17 | _controller = AnimationController( 18 | vsync: this, // the SingleTickerProviderStateMixin 19 | duration: Duration(milliseconds: 2000), 20 | ); 21 | _controller.repeat(reverse: true); 22 | } 23 | 24 | @override 25 | void dispose() { 26 | _controller.dispose(); 27 | super.dispose(); 28 | } 29 | 30 | @override 31 | Widget build(BuildContext context) { 32 | return LinearProgressIndicator( 33 | valueColor: 34 | ColorTween(begin: Theme.of(context).accentColor, end: Colors.amber) 35 | .animate(_controller), 36 | ); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/widgets/RoomShelf.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/models/Message.dart'; 2 | import 'package:chatapp/providers/ChatInfoProvider.dart'; 3 | import 'package:chatapp/providers/DialogflowProvider.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:provider/provider.dart'; 6 | import 'package:chatapp/models/ListExtension.dart'; 7 | 8 | class RoomShelf extends StatelessWidget { 9 | List buildSugestions(BuildContext context) { 10 | var chatInfoProvider = Provider.of(context); 11 | var message = chatInfoProvider.messages.last; 12 | 13 | if (message.aiResponse == null) { 14 | return []; 15 | } 16 | 17 | var params = message.aiResponse.suggestions; 18 | return params 19 | .map( 20 | (suggestion) => GestureDetector( 21 | child: Chip( 22 | shape: StadiumBorder( 23 | side: BorderSide(color: Colors.amber[300], width: 2)), 24 | elevation: 0, 25 | label: Text( 26 | suggestion['title'], 27 | style: TextStyle(color: Colors.black), 28 | ), 29 | backgroundColor: Colors.amber[200], 30 | ), 31 | onTap: () { 32 | chatInfoProvider.addMessage( 33 | message: 34 | Message(body: suggestion['title'], sender: Sender.user)); 35 | Provider.of(context, listen: false) 36 | .response(suggestion['title']) 37 | .then((response) => chatInfoProvider.addMessage( 38 | message: Message( 39 | body: response.getMessage(), 40 | sender: Sender.bot, 41 | aiResponse: response))); 42 | }, 43 | ), 44 | ) 45 | .toList(); 46 | } 47 | 48 | @override 49 | Widget build(BuildContext context) { 50 | return Material( 51 | color: Colors.grey.withOpacity(0.1), 52 | // color: Colors.transparent, 53 | child: Consumer( 54 | builder: (BuildContext context, ChatInfoProvider chatInfoProvider, 55 | Widget child) { 56 | var isUser = 57 | chatInfoProvider.messages.last?.sender == Sender.user ?? true; 58 | var suggestionAvailable = chatInfoProvider 59 | .messages.last?.aiResponse?.suggestions?.isNotEmpty ?? 60 | false; 61 | return Container( 62 | child: AnimatedContainer( 63 | height: chatInfoProvider.favoriteShelfOpen && suggestionAvailable 64 | ? 50 65 | : 0, 66 | width: MediaQuery.of(context).size.width, 67 | duration: Duration( 68 | milliseconds: 69 | WidgetsBinding.instance.disableAnimations ? 0 : 150), 70 | child: !isUser ? child : SizedBox(), 71 | ), 72 | ); 73 | }, 74 | child: Center( 75 | child: Container( 76 | child: ListView( 77 | reverse: false, 78 | padding: EdgeInsets.symmetric(horizontal: 16), 79 | scrollDirection: Axis.horizontal, 80 | shrinkWrap: true, 81 | children: buildSugestions(context).insertEveryNth( 82 | SizedBox( 83 | width: 10, 84 | ), 85 | ), 86 | ), 87 | ), 88 | ), 89 | ), 90 | ); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/widgets/RoundedCornersContainer.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class RoundedCornersContainer extends StatelessWidget { 4 | RoundedCornersContainer( 5 | {Key key, 6 | @required this.child, 7 | @required this.top, 8 | @required this.bottom}); 9 | 10 | final Widget child; 11 | final bool top; 12 | final bool bottom; 13 | 14 | @override 15 | Widget build(BuildContext context) { 16 | return Container( 17 | color: Theme.of(context).canvasColor, 18 | child: ClipRRect( 19 | borderRadius: BorderRadius.only( 20 | topLeft: Radius.circular(top ? 10.0 : 0), 21 | topRight: Radius.circular(top ? 10.0 : 0), 22 | bottomLeft: Radius.circular(bottom ? 10.0 : 0), 23 | bottomRight: Radius.circular(bottom ? 10.0 : 0), 24 | ), 25 | child: Container( 26 | color: Theme.of(context).scaffoldBackgroundColor, 27 | child: child, 28 | ), 29 | ), 30 | ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/widgets/ShadowLine.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | class ShadowLine extends StatelessWidget { 4 | const ShadowLine({Key key}) : super(key: key); 5 | 6 | @override 7 | Widget build(BuildContext context) { 8 | return Divider( 9 | height: 0, 10 | thickness: 1, 11 | // color: Theme.of(context).brightness == Brightness.light 12 | // ? Colors.black26 13 | // : Colors.black87, 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/widgets/StatusInfo.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/providers/RosProvider.dart'; 2 | import 'package:chatapp/providers/SettingsProvider.dart'; 3 | import 'package:flutter/material.dart'; 4 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 5 | import 'package:provider/provider.dart'; 6 | 7 | class StatusInfo extends StatelessWidget { 8 | const StatusInfo({Key key}) : super(key: key); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | return Padding( 13 | padding: const EdgeInsets.only(top: 10, left: 10), 14 | child: Consumer2( 15 | builder: (context, settingsProvider, rosProvider, child) => Wrap( 16 | direction: Axis.horizontal, 17 | spacing: 5, 18 | children: [ 19 | MiniInfoButton( 20 | iconData: MdiIcons.lightningBolt, 21 | text: settingsProvider.topicBattery, 22 | tooltip: 'Poziom naładowania baterii', 23 | iconColor: Colors.amberAccent, 24 | ), 25 | MiniInfoButton( 26 | iconData: MdiIcons.arrowUp, 27 | text: rosProvider.veliocityAvailable 28 | ? rosProvider.veliocity.linear.x >= 0 29 | ? ' ${rosProvider.veliocity.linear.x.toStringAsFixed(2)}' 30 | : rosProvider.veliocity.linear.x.toStringAsFixed(2) 31 | : settingsProvider.topicVelocity, 32 | tooltip: 'Prędkość liniowa', 33 | iconColor: Colors.greenAccent, 34 | ), 35 | MiniInfoButton( 36 | iconData: MdiIcons.rotateRight, 37 | text: rosProvider.veliocityAvailable 38 | ? rosProvider.veliocity.angular.z.sign >= 0 39 | ? ' ${rosProvider.veliocity.angular.z.toStringAsFixed(2)}' 40 | : rosProvider.veliocity.angular.z.toStringAsFixed(2) 41 | : settingsProvider.topicVelocity, 42 | tooltip: 'Prędkość kątowa', 43 | iconColor: Colors.blueAccent, 44 | ), 45 | ], 46 | ), 47 | ), 48 | ); 49 | } 50 | } 51 | 52 | class MiniInfoButton extends StatelessWidget { 53 | const MiniInfoButton( 54 | {Key key, 55 | @required this.tooltip, 56 | @required this.text, 57 | @required this.iconData, 58 | this.iconColor}) 59 | : assert(text != null), 60 | assert(iconData != null), 61 | assert(tooltip != null), 62 | super(key: key); 63 | 64 | final String tooltip; 65 | final String text; 66 | final IconData iconData; 67 | final Color iconColor; 68 | 69 | @override 70 | Widget build(BuildContext context) { 71 | return Tooltip( 72 | message: tooltip, 73 | child: Theme( 74 | data: Theme.of(context) 75 | .copyWith(canvasColor: Theme.of(context).canvasColor), 76 | child: Chip( 77 | elevation: 0, 78 | backgroundColor: Colors.transparent, 79 | // shape: StadiumBorder( 80 | // side: BorderSide(color: Theme.of(context).canvasColor, width: 1)), 81 | materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, 82 | labelPadding: EdgeInsets.only(left: 3, right: 4), 83 | avatar: Icon(iconData, 84 | size: 18, color: iconColor ?? Theme.of(context).iconTheme.color), 85 | label: Text( 86 | text, 87 | 88 | //Theme.of(context).textTheme.caption 89 | style: Theme.of(context).textTheme.caption, 90 | ), 91 | visualDensity: VisualDensity.compact, 92 | ), 93 | ), 94 | ); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /lib/widgets/WaypointDialog.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:chatapp/generated/l10n.dart'; 4 | import 'package:chatapp/models/Waypoint.dart'; 5 | import 'package:chatapp/providers/RosProvider.dart'; 6 | import 'package:chatapp/providers/SettingsProvider.dart'; 7 | import 'package:chatapp/widgets/ColorPickerCustom.dart'; 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter/widgets.dart'; 10 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 11 | import 'package:provider/provider.dart'; 12 | import 'package:english_words/english_words.dart' as wp; 13 | 14 | String _randomName() { 15 | return '${wp.generateWordPairs().take(1).reduce((value, element) => null).asPascalCase}'; 16 | } 17 | 18 | class WaypointDialog extends StatefulWidget { 19 | const WaypointDialog({Key key, this.existingWaypoint}) : super(key: key); 20 | 21 | final Waypoint existingWaypoint; 22 | 23 | @override 24 | _WaypointDialogState createState() => _WaypointDialogState(); 25 | } 26 | 27 | class _WaypointDialogState extends State { 28 | // List _selections = List.generate(3, (_) => false); 29 | 30 | List _selections = [false, false]; 31 | var _nameController = TextEditingController(); 32 | var _xController = TextEditingController(); 33 | var _yController = TextEditingController(); 34 | 35 | var _scrollController = ScrollController(); 36 | Color _waypointColor; 37 | 38 | bool _isEditMode = false; 39 | 40 | @override 41 | void initState() { 42 | super.initState(); 43 | _nameController.text = widget.existingWaypoint?.name ?? _randomName(); 44 | _xController.text = widget.existingWaypoint?.x.toString() ?? '0'; 45 | _yController.text = widget.existingWaypoint?.y.toString() ?? '0'; 46 | _waypointColor = widget.existingWaypoint?.color ?? 47 | HSVColor.fromAHSV(1, Random().nextDouble() * 360, 1, 1).toColor(); 48 | 49 | if (widget.existingWaypoint != null) { 50 | _isEditMode = true; 51 | _selections[1] = true; 52 | } else { 53 | _selections[0] = true; 54 | } 55 | } 56 | 57 | @override 58 | Widget build(BuildContext context) { 59 | Color textColor = Theme.of(context).brightness == Brightness.light 60 | ? Colors.black.withOpacity(0.6) 61 | : Colors.white; 62 | 63 | if (_selections[0] && 64 | Provider.of(context, listen: false).mapImageAvailable) { 65 | _xController.text = Provider.of(context, listen: false) 66 | .odometry 67 | .pose 68 | .pose 69 | .position 70 | .x 71 | .toStringAsFixed(2); 72 | _yController.text = Provider.of(context, listen: false) 73 | .odometry 74 | .pose 75 | .pose 76 | .position 77 | .y 78 | .toStringAsFixed(2); 79 | } 80 | 81 | return AlertDialog( 82 | insetPadding: EdgeInsets.symmetric(horizontal: 30), 83 | actionsPadding: EdgeInsets.only(right: 10), 84 | contentPadding: EdgeInsets.all(0), 85 | titlePadding: EdgeInsets.fromLTRB(29, 24, 24, 10), 86 | title: Row( 87 | children: [ 88 | Theme( 89 | data: Theme.of(context) 90 | .copyWith(iconTheme: IconThemeData(color: textColor)), 91 | child: Icon(_isEditMode ? Icons.create : Icons.add)), 92 | SizedBox(width: 8), 93 | _isEditMode 94 | ? Text(S?.of(context)?.creatorEdit ?? "", 95 | style: TextStyle(color: textColor)) 96 | : Text(S?.of(context)?.creatorAddNew ?? "", 97 | style: TextStyle(color: textColor)), 98 | ], 99 | ), 100 | content: Theme( 101 | data: Theme.of(context).copyWith( 102 | primaryColor: Theme.of(context).brightness == Brightness.light 103 | ? Theme.of(context).accentColor 104 | : null), 105 | child: Container( 106 | width: MediaQuery.of(context).size.width, 107 | child: Scrollbar( 108 | child: ListView( 109 | controller: _scrollController, 110 | padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), 111 | physics: Provider.of(context, listen: false) 112 | .limitAnimations 113 | ? null 114 | : BouncingScrollPhysics(), 115 | shrinkWrap: true, 116 | children: [ 117 | // TextField in Stack -> makes button click not focus text field -> OK 118 | Stack( 119 | alignment: Alignment.centerRight, 120 | children: [ 121 | TextField( 122 | style: TextStyle(color: textColor), 123 | controller: _nameController, 124 | decoration: InputDecoration( 125 | labelText: S?.of(context)?.creatorName ?? "", 126 | contentPadding: 127 | const EdgeInsets.fromLTRB(5, 5, 48, 5))), 128 | IconButton( 129 | tooltip: S?.of(context)?.tooltipRandom ?? "", 130 | icon: Icon( 131 | MdiIcons.dice6, 132 | size: 20, 133 | color: textColor, 134 | ), 135 | onPressed: () { 136 | setState(() { 137 | _nameController.text = _randomName(); 138 | }); 139 | }, 140 | ), 141 | ], 142 | ), 143 | SizedBox(height: 10), 144 | //Get coordinates for markers 145 | Row(children: [ 146 | Expanded( 147 | child: TextField( 148 | style: TextStyle(color: textColor), 149 | controller: _xController, 150 | enabled: _selections[1], 151 | keyboardType: TextInputType.number, 152 | decoration: InputDecoration( 153 | disabledBorder: InputBorder.none, 154 | labelText: "X", 155 | contentPadding: const EdgeInsets.all(5)))), 156 | SizedBox(width: 2), 157 | Expanded( 158 | child: TextField( 159 | style: TextStyle(color: textColor), 160 | controller: _yController, 161 | enabled: _selections[1], 162 | keyboardType: TextInputType.number, 163 | decoration: InputDecoration( 164 | disabledBorder: InputBorder.none, 165 | labelText: "Y", 166 | contentPadding: const EdgeInsets.all(5)))), 167 | SizedBox(width: 2), 168 | ToggleButtons( 169 | fillColor: 170 | Theme.of(context).brightness == Brightness.light 171 | ? Colors.black.withOpacity(0.1) 172 | : Colors.white24, 173 | selectedColor: textColor, 174 | color: textColor, 175 | children: [ 176 | Tooltip( 177 | message: 178 | S?.of(context)?.tooltipCurrentLocation ?? 179 | "", 180 | child: Icon(MdiIcons.earthBox)), 181 | Tooltip( 182 | message: 183 | S?.of(context)?.tooltipCoordinates ?? "", 184 | child: Icon(MdiIcons.numeric)), 185 | // Tooltip( 186 | // message: 'Przeciągnij znacznik później', 187 | // child: Icon(MdiIcons.gestureTap)) 188 | ], 189 | isSelected: _selections, 190 | onPressed: (int index) { 191 | setState(() { 192 | // _selections[index] = !_selections[index]; 193 | for (var i = 0; i < _selections.length; i++) { 194 | if (i == index) { 195 | _selections[i] = true; 196 | } else { 197 | _selections[i] = false; 198 | } 199 | } 200 | }); 201 | }), 202 | ]), 203 | SizedBox(height: 15), 204 | ColorPickerModified( 205 | textColor: textColor, 206 | pickerColor: _waypointColor, 207 | onColorChanged: (color) => _waypointColor = color, 208 | pickerAreaBorderRadius: 209 | BorderRadius.all(Radius.circular(2)), 210 | hueLabel: S?.of(context)?.creatorHue ?? "", 211 | ), 212 | ]), 213 | )), 214 | ), 215 | actions: [ 216 | FlatButton( 217 | onPressed: () { 218 | Navigator.of(context).pop(); 219 | }, 220 | child: Text(MaterialLocalizations.of(context).cancelButtonLabel, 221 | style: TextStyle(color: textColor))), 222 | FlatButton( 223 | onPressed: () { 224 | var waypoint = Waypoint( 225 | name: _nameController.text, 226 | color: _waypointColor, 227 | x: double.parse(_xController.text), 228 | y: double.parse(_yController.text), 229 | radius: 0.5); 230 | Navigator.of(context).pop(_isEditMode 231 | ? Provider.of(context, listen: false) 232 | .editWaypoint(widget.existingWaypoint, waypoint) 233 | : Provider.of(context, listen: false) 234 | .addToWaypoints(waypoint)); 235 | }, 236 | child: Text( 237 | MaterialLocalizations.of(context).saveButtonLabel, 238 | style: TextStyle(color: textColor), 239 | )), 240 | ], 241 | ); 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /lib/widgets/WaypointShelf.dart: -------------------------------------------------------------------------------- 1 | import 'package:chatapp/generated/l10n.dart'; 2 | import 'package:chatapp/models/Waypoint.dart'; 3 | import 'package:chatapp/providers/ChatInfoProvider.dart'; 4 | import 'package:chatapp/providers/RosProvider.dart'; 5 | import 'package:chatapp/providers/SettingsProvider.dart'; 6 | import 'package:flutter/material.dart'; 7 | import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; 8 | import 'package:provider/provider.dart'; 9 | import 'package:chatapp/models/StringExtension.dart'; 10 | 11 | import 'WaypointDialog.dart'; 12 | 13 | enum WaypointShelfEditOptions { edit, delete, cancel } 14 | 15 | class WaypointShelf extends StatelessWidget { 16 | List buildWaypoints(BuildContext context, WaypointList waypoints) { 17 | if (waypoints == null) { 18 | return []; 19 | } 20 | 21 | return waypoints.waypoints 22 | .map((waypoint) => 23 | Consumer(builder: (context, rosProvider, child) { 24 | bool isActive = rosProvider.activeWaypoint == waypoint; 25 | Color waypointColor = waypoint.color; 26 | // Color backgroundColor = isActive 27 | // ? Theme.of(context).accentColor 28 | // : Theme.of(context).chipTheme.backgroundColor; 29 | Color backgroundColor = 30 | Theme.of(context).chipTheme.backgroundColor; 31 | Color textColor = backgroundColor.computeLuminance() > 0.5 32 | ? Colors.black 33 | : Colors.white; 34 | // Color avatarBackgroundColor = 35 | // waypoint.color.computeLuminance() > 0.5 36 | // ? Colors.black38 37 | // : Colors.white30; 38 | return GestureDetector( 39 | child: Theme( 40 | data: Theme.of(context) 41 | .copyWith(canvasColor: Colors.transparent), 42 | child: Padding( 43 | padding: const EdgeInsets.symmetric(horizontal: 2.0), 44 | child: Chip( 45 | elevation: 0, 46 | avatar: CircleAvatar( 47 | backgroundColor: Colors.transparent, 48 | child: Icon( 49 | isActive 50 | ? MdiIcons.rhombus 51 | : MdiIcons.rhombusOutline, 52 | color: isActive 53 | ? waypointColor 54 | : waypointColor.withOpacity(0.4), 55 | ), 56 | ), 57 | shape: isActive 58 | ? StadiumBorder( 59 | side: 60 | BorderSide(color: waypointColor, width: 1)) 61 | : StadiumBorder( 62 | side: BorderSide( 63 | color: Colors.transparent, width: 1)), 64 | label: Text(waypoint.name.capitalize(), 65 | style: TextStyle(color: textColor)), 66 | backgroundColor: 67 | isActive ? backgroundColor.withOpacity(0.8) : null, 68 | ), 69 | )), 70 | onTap: () { 71 | rosProvider.setactiveWaypoint(waypoint, context); 72 | }, 73 | onLongPress: () { 74 | showModalBottomSheet( 75 | isDismissible: true, 76 | context: context, 77 | builder: (BuildContext context) { 78 | return Column( 79 | mainAxisSize: MainAxisSize.min, 80 | mainAxisAlignment: MainAxisAlignment.center, 81 | children: [ 82 | ListTile( 83 | dense: true, 84 | leading: Icon( 85 | MdiIcons.rhombus, 86 | color: waypoint.color, 87 | ), 88 | title: Text( 89 | '${waypoint.name.capitalize()}', 90 | style: Theme.of(context).textTheme.subtitle1, 91 | )), 92 | Divider( 93 | height: 0, 94 | thickness: 1, 95 | ), 96 | ListTile( 97 | leading: Icon(Icons.edit), 98 | title: Text(S?.of(context)?.creatorEdit ?? ""), 99 | onTap: () { 100 | showDialog( 101 | context: context, 102 | builder: (_) => WaypointDialog( 103 | existingWaypoint: waypoint, 104 | )).then( 105 | (value) => Navigator.of(context).pop()); 106 | }, 107 | ), 108 | ListTile( 109 | leading: Icon(Icons.delete), 110 | title: Text(MaterialLocalizations.of(context) 111 | .deleteButtonTooltip), 112 | onTap: () { 113 | Navigator.of(context).pop( 114 | Provider.of(context, 115 | listen: false) 116 | .removeWaypoint(waypoint), 117 | ); 118 | }, 119 | ) 120 | ], 121 | ); 122 | }); 123 | }, 124 | ); 125 | })) 126 | .toList(); 127 | } 128 | 129 | @override 130 | Widget build(BuildContext context) { 131 | return Container( 132 | height: 45, 133 | child: Material( 134 | elevation: 0, 135 | child: Consumer2( 136 | builder: (context, chatInfoProvider, settingsProvider, child) => 137 | ListView( 138 | physics: settingsProvider.limitAnimations 139 | ? null 140 | : BouncingScrollPhysics(), 141 | padding: EdgeInsets.symmetric(horizontal: 10), 142 | scrollDirection: Axis.horizontal, 143 | children: buildWaypoints( 144 | context, settingsProvider.waypoints)))), 145 | ); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /lib/widgets/WirtualController.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:flutter/material.dart'; 3 | 4 | class WirtualController extends StatefulWidget { 5 | final double baseSize; 6 | final double stickSize; 7 | final void Function(Offset) onStickMove; 8 | 9 | const WirtualController( 10 | {Key key, 11 | @required this.baseSize, 12 | @required this.stickSize, 13 | this.onStickMove}) 14 | : super(key: key); 15 | 16 | @override 17 | State createState() { 18 | var baseSize2 = baseSize; 19 | return _WirtualControllerState( 20 | baseSize2, 21 | stickSize, 22 | onStickMove, 23 | ); 24 | } 25 | } 26 | 27 | class _WirtualControllerState extends State { 28 | final double baseSize; 29 | final double stickSize; 30 | var tapCount = 0; 31 | Offset offset = Offset(0, 0); 32 | var angle = 0; 33 | var radius; 34 | bool inMotion = false; 35 | 36 | void Function(Offset) onStickMove; 37 | 38 | _WirtualControllerState(this.baseSize, this.stickSize, this.onStickMove) { 39 | radius = baseSize / 2; 40 | // msg = GeometryMsgsTwist(); 41 | // //ANDROID DEVICE DEFAULT IP WHEN TETHERING: 192.168.43.1 42 | // var config = 43 | // RosNode('http://192.168.43.145:11311/', '192.168.43.92', 51235); 44 | // var publisher = RosPublisher('sticky_publisher', 'cmd_vel', msg, config, 45 | // publishInterval: Duration(milliseconds: 100)); 46 | // publisher.register(); 47 | 48 | // onStickMove = (offset) { 49 | // msg.linear.x = -offset.dy * 0.4; 50 | // msg.angular.z = -offset.dx * 1.5; 51 | //if (offset.dy < 0) msg.angular.z *= -1; 52 | // print(offset.dy.toString()); 53 | // }; 54 | } 55 | 56 | @override 57 | Widget build(BuildContext context) { 58 | return GestureDetector( 59 | onTap: () { 60 | print('Button pressed ${++tapCount}'); 61 | }, 62 | onPanUpdate: (start) { 63 | inMotion = true; 64 | var local = start.localPosition.translate(-radius, -radius); 65 | var x = cos(local.direction); 66 | var y = sin(local.direction); 67 | var maxDistance = (local.distance / radius); 68 | maxDistance = maxDistance > 1 ? 1 : maxDistance; 69 | if (onStickMove != null) onStickMove(Offset(x, y) * maxDistance); 70 | if (local.distance >= radius) { 71 | local = Offset(x, y) * radius; 72 | } 73 | setState(() { 74 | offset = local; 75 | }); 76 | }, 77 | onPanEnd: (_) { 78 | inMotion = false; 79 | if (onStickMove != null) onStickMove(Offset(0, 0)); 80 | setState(() { 81 | offset = Offset(0, 0); 82 | }); 83 | }, 84 | child: Material( 85 | //OUTER RADIUS 86 | shape: CircleBorder( 87 | side: BorderSide(width: 2, color: Colors.grey.withAlpha((80)))), 88 | color: Colors.white.withAlpha(0), 89 | child: Container( 90 | height: baseSize, 91 | width: baseSize, 92 | child: Center( 93 | child: Stack( 94 | children: [ 95 | //Middle RADIUS 96 | Center( 97 | child: Material( 98 | shape: CircleBorder( 99 | side: BorderSide( 100 | width: 4, color: Colors.grey.withAlpha((20)))), 101 | color: Colors.grey.withAlpha(0), 102 | child: Container( 103 | height: baseSize * 0.7, 104 | width: baseSize * 0.7, 105 | ), 106 | ), 107 | ), 108 | //Inner RADIUS 109 | Center( 110 | child: Material( 111 | shape: CircleBorder(), 112 | color: Colors.grey.withAlpha(30), 113 | child: Container( 114 | height: stickSize, 115 | width: stickSize, 116 | ), 117 | ), 118 | ), 119 | Center( 120 | child: Transform.translate( 121 | offset: offset, 122 | child: Material( 123 | shape: CircleBorder( 124 | side: BorderSide(width: 2, color: Colors.black38)), 125 | color: Colors.grey, 126 | //color: Color.fromRGBO(89, 89, 89, 1) 127 | elevation: 4.0, 128 | child: Container( 129 | height: inMotion ? stickSize / 2 : stickSize, 130 | width: inMotion ? stickSize / 2 : stickSize, 131 | child: Center( 132 | child: Icon( 133 | Icons.blur_on, 134 | size: inMotion 135 | ? stickSize / 2 / 1.4 136 | : stickSize / 1.4, 137 | color: Colors.black26, 138 | ), 139 | ), 140 | ), 141 | ), 142 | ), 143 | ), 144 | ], 145 | ), 146 | ), 147 | ), 148 | ), 149 | ); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | asn1lib: 5 | dependency: transitive 6 | description: 7 | name: asn1lib 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "0.6.5" 11 | async: 12 | dependency: transitive 13 | description: 14 | name: async 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.5.0-nullsafety.1" 18 | audio_recorder: 19 | dependency: "direct main" 20 | description: 21 | name: audio_recorder 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.0.2" 25 | basic_utils: 26 | dependency: "direct main" 27 | description: 28 | name: basic_utils 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "2.6.2" 32 | boolean_selector: 33 | dependency: transitive 34 | description: 35 | name: boolean_selector 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "2.1.0-nullsafety.1" 39 | characters: 40 | dependency: transitive 41 | description: 42 | name: characters 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.1.0-nullsafety.3" 46 | charcode: 47 | dependency: transitive 48 | description: 49 | name: charcode 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.2.0-nullsafety.1" 53 | clock: 54 | dependency: transitive 55 | description: 56 | name: clock 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.1.0-nullsafety.1" 60 | collection: 61 | dependency: transitive 62 | description: 63 | name: collection 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.15.0-nullsafety.3" 67 | convert: 68 | dependency: transitive 69 | description: 70 | name: convert 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "2.1.1" 74 | crypto: 75 | dependency: transitive 76 | description: 77 | name: crypto 78 | url: "https://pub.dartlang.org" 79 | source: hosted 80 | version: "2.1.5" 81 | cupertino_icons: 82 | dependency: "direct main" 83 | description: 84 | name: cupertino_icons 85 | url: "https://pub.dartlang.org" 86 | source: hosted 87 | version: "0.1.3" 88 | english_words: 89 | dependency: "direct main" 90 | description: 91 | name: english_words 92 | url: "https://pub.dartlang.org" 93 | source: hosted 94 | version: "3.1.5" 95 | fake_async: 96 | dependency: transitive 97 | description: 98 | name: fake_async 99 | url: "https://pub.dartlang.org" 100 | source: hosted 101 | version: "1.2.0-nullsafety.1" 102 | file: 103 | dependency: transitive 104 | description: 105 | name: file 106 | url: "https://pub.dartlang.org" 107 | source: hosted 108 | version: "5.2.1" 109 | flutter: 110 | dependency: "direct main" 111 | description: flutter 112 | source: sdk 113 | version: "0.0.0" 114 | flutter_colorpicker: 115 | dependency: "direct main" 116 | description: 117 | name: flutter_colorpicker 118 | url: "https://pub.dartlang.org" 119 | source: hosted 120 | version: "0.3.4" 121 | flutter_dialogflow: 122 | dependency: "direct main" 123 | description: 124 | name: flutter_dialogflow 125 | url: "https://pub.dartlang.org" 126 | source: hosted 127 | version: "0.1.3" 128 | flutter_localizations: 129 | dependency: "direct main" 130 | description: flutter 131 | source: sdk 132 | version: "0.0.0" 133 | flutter_test: 134 | dependency: "direct dev" 135 | description: flutter 136 | source: sdk 137 | version: "0.0.0" 138 | flutter_web_plugins: 139 | dependency: transitive 140 | description: flutter 141 | source: sdk 142 | version: "0.0.0" 143 | googleapis_auth: 144 | dependency: transitive 145 | description: 146 | name: googleapis_auth 147 | url: "https://pub.dartlang.org" 148 | source: hosted 149 | version: "0.2.12" 150 | http: 151 | dependency: transitive 152 | description: 153 | name: http 154 | url: "https://pub.dartlang.org" 155 | source: hosted 156 | version: "0.12.2" 157 | http_parser: 158 | dependency: transitive 159 | description: 160 | name: http_parser 161 | url: "https://pub.dartlang.org" 162 | source: hosted 163 | version: "3.1.4" 164 | intl: 165 | dependency: transitive 166 | description: 167 | name: intl 168 | url: "https://pub.dartlang.org" 169 | source: hosted 170 | version: "0.16.1" 171 | json_annotation: 172 | dependency: transitive 173 | description: 174 | name: json_annotation 175 | url: "https://pub.dartlang.org" 176 | source: hosted 177 | version: "3.0.1" 178 | localstorage: 179 | dependency: "direct main" 180 | description: 181 | name: localstorage 182 | url: "https://pub.dartlang.org" 183 | source: hosted 184 | version: "3.0.2+5" 185 | logging: 186 | dependency: transitive 187 | description: 188 | name: logging 189 | url: "https://pub.dartlang.org" 190 | source: hosted 191 | version: "0.11.4" 192 | matcher: 193 | dependency: transitive 194 | description: 195 | name: matcher 196 | url: "https://pub.dartlang.org" 197 | source: hosted 198 | version: "0.12.10-nullsafety.1" 199 | material_design_icons_flutter: 200 | dependency: "direct main" 201 | description: 202 | name: material_design_icons_flutter 203 | url: "https://pub.dartlang.org" 204 | source: hosted 205 | version: "4.0.5345" 206 | meta: 207 | dependency: transitive 208 | description: 209 | name: meta 210 | url: "https://pub.dartlang.org" 211 | source: hosted 212 | version: "1.3.0-nullsafety.3" 213 | nested: 214 | dependency: transitive 215 | description: 216 | name: nested 217 | url: "https://pub.dartlang.org" 218 | source: hosted 219 | version: "0.0.4" 220 | path: 221 | dependency: transitive 222 | description: 223 | name: path 224 | url: "https://pub.dartlang.org" 225 | source: hosted 226 | version: "1.8.0-nullsafety.1" 227 | path_provider: 228 | dependency: "direct main" 229 | description: 230 | name: path_provider 231 | url: "https://pub.dartlang.org" 232 | source: hosted 233 | version: "1.6.11" 234 | path_provider_linux: 235 | dependency: transitive 236 | description: 237 | name: path_provider_linux 238 | url: "https://pub.dartlang.org" 239 | source: hosted 240 | version: "0.0.1+2" 241 | path_provider_macos: 242 | dependency: transitive 243 | description: 244 | name: path_provider_macos 245 | url: "https://pub.dartlang.org" 246 | source: hosted 247 | version: "0.0.4+3" 248 | path_provider_platform_interface: 249 | dependency: transitive 250 | description: 251 | name: path_provider_platform_interface 252 | url: "https://pub.dartlang.org" 253 | source: hosted 254 | version: "1.0.2" 255 | pedantic: 256 | dependency: transitive 257 | description: 258 | name: pedantic 259 | url: "https://pub.dartlang.org" 260 | source: hosted 261 | version: "1.9.2" 262 | permission_handler: 263 | dependency: "direct main" 264 | description: 265 | name: permission_handler 266 | url: "https://pub.dartlang.org" 267 | source: hosted 268 | version: "5.0.1+1" 269 | permission_handler_platform_interface: 270 | dependency: transitive 271 | description: 272 | name: permission_handler_platform_interface 273 | url: "https://pub.dartlang.org" 274 | source: hosted 275 | version: "2.0.1" 276 | petitparser: 277 | dependency: transitive 278 | description: 279 | name: petitparser 280 | url: "https://pub.dartlang.org" 281 | source: hosted 282 | version: "3.1.0" 283 | platform: 284 | dependency: transitive 285 | description: 286 | name: platform 287 | url: "https://pub.dartlang.org" 288 | source: hosted 289 | version: "2.2.1" 290 | plugin_platform_interface: 291 | dependency: transitive 292 | description: 293 | name: plugin_platform_interface 294 | url: "https://pub.dartlang.org" 295 | source: hosted 296 | version: "1.0.2" 297 | pointycastle: 298 | dependency: transitive 299 | description: 300 | name: pointycastle 301 | url: "https://pub.dartlang.org" 302 | source: hosted 303 | version: "1.0.2" 304 | process: 305 | dependency: transitive 306 | description: 307 | name: process 308 | url: "https://pub.dartlang.org" 309 | source: hosted 310 | version: "3.0.13" 311 | provider: 312 | dependency: "direct main" 313 | description: 314 | name: provider 315 | url: "https://pub.dartlang.org" 316 | source: hosted 317 | version: "4.3.2" 318 | ros_nodes: 319 | dependency: "direct main" 320 | description: 321 | path: "." 322 | ref: HEAD 323 | resolved-ref: "7309bd8bb41014f72a263c6d64c05f69c14c9e21" 324 | url: "git://github.com/Sashiri/ros_nodes.git" 325 | source: git 326 | version: "0.1.0" 327 | shared_preferences: 328 | dependency: "direct main" 329 | description: 330 | name: shared_preferences 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "0.5.8" 334 | shared_preferences_linux: 335 | dependency: transitive 336 | description: 337 | name: shared_preferences_linux 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "0.0.2+1" 341 | shared_preferences_macos: 342 | dependency: transitive 343 | description: 344 | name: shared_preferences_macos 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "0.0.1+10" 348 | shared_preferences_platform_interface: 349 | dependency: transitive 350 | description: 351 | name: shared_preferences_platform_interface 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "1.0.4" 355 | shared_preferences_web: 356 | dependency: transitive 357 | description: 358 | name: shared_preferences_web 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "0.1.2+7" 362 | sky_engine: 363 | dependency: transitive 364 | description: flutter 365 | source: sdk 366 | version: "0.0.99" 367 | soundpool: 368 | dependency: "direct main" 369 | description: 370 | name: soundpool 371 | url: "https://pub.dartlang.org" 372 | source: hosted 373 | version: "1.1.1" 374 | soundpool_macos: 375 | dependency: transitive 376 | description: 377 | name: soundpool_macos 378 | url: "https://pub.dartlang.org" 379 | source: hosted 380 | version: "0.2.4" 381 | soundpool_platform_interface: 382 | dependency: transitive 383 | description: 384 | name: soundpool_platform_interface 385 | url: "https://pub.dartlang.org" 386 | source: hosted 387 | version: "1.0.1" 388 | soundpool_web: 389 | dependency: transitive 390 | description: 391 | name: soundpool_web 392 | url: "https://pub.dartlang.org" 393 | source: hosted 394 | version: "1.0.3" 395 | source_span: 396 | dependency: transitive 397 | description: 398 | name: source_span 399 | url: "https://pub.dartlang.org" 400 | source: hosted 401 | version: "1.8.0-nullsafety.2" 402 | stack_trace: 403 | dependency: transitive 404 | description: 405 | name: stack_trace 406 | url: "https://pub.dartlang.org" 407 | source: hosted 408 | version: "1.10.0-nullsafety.1" 409 | stream_channel: 410 | dependency: transitive 411 | description: 412 | name: stream_channel 413 | url: "https://pub.dartlang.org" 414 | source: hosted 415 | version: "2.1.0-nullsafety.1" 416 | string_scanner: 417 | dependency: transitive 418 | description: 419 | name: string_scanner 420 | url: "https://pub.dartlang.org" 421 | source: hosted 422 | version: "1.1.0-nullsafety.1" 423 | term_glyph: 424 | dependency: transitive 425 | description: 426 | name: term_glyph 427 | url: "https://pub.dartlang.org" 428 | source: hosted 429 | version: "1.2.0-nullsafety.1" 430 | test_api: 431 | dependency: transitive 432 | description: 433 | name: test_api 434 | url: "https://pub.dartlang.org" 435 | source: hosted 436 | version: "0.2.19-nullsafety.2" 437 | typed_data: 438 | dependency: transitive 439 | description: 440 | name: typed_data 441 | url: "https://pub.dartlang.org" 442 | source: hosted 443 | version: "1.3.0-nullsafety.3" 444 | uuid: 445 | dependency: "direct main" 446 | description: 447 | name: uuid 448 | url: "https://pub.dartlang.org" 449 | source: hosted 450 | version: "2.2.0" 451 | vector_math: 452 | dependency: transitive 453 | description: 454 | name: vector_math 455 | url: "https://pub.dartlang.org" 456 | source: hosted 457 | version: "2.1.0-nullsafety.3" 458 | xdg_directories: 459 | dependency: transitive 460 | description: 461 | name: xdg_directories 462 | url: "https://pub.dartlang.org" 463 | source: hosted 464 | version: "0.1.0" 465 | xml: 466 | dependency: transitive 467 | description: 468 | name: xml 469 | url: "https://pub.dartlang.org" 470 | source: hosted 471 | version: "3.7.0" 472 | xml_rpc: 473 | dependency: transitive 474 | description: 475 | name: xml_rpc 476 | url: "https://pub.dartlang.org" 477 | source: hosted 478 | version: "0.2.4" 479 | xmlrpc_server: 480 | dependency: transitive 481 | description: 482 | path: "." 483 | ref: HEAD 484 | resolved-ref: "35b112f851a5c479dac2720637ef566b291c658c" 485 | url: "git://github.com/sashiri/xmlrpc_server.git" 486 | source: git 487 | version: "0.0.1" 488 | sdks: 489 | dart: ">=2.10.0-110 <2.11.0" 490 | flutter: ">=1.16.0 <2.0.0" 491 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: chatapp 2 | description: Flutter chat app 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # In Android, build-name is used as versionName while build-number used as versionCode. 10 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 11 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 12 | # Read more about iOS versioning at 13 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 14 | version: 1.0.0+1 15 | 16 | environment: 17 | sdk: ">=2.8.0 <3.0.0" 18 | 19 | dependencies: 20 | flutter: 21 | sdk: flutter 22 | cupertino_icons: ^0.1.2 23 | provider: ^4.0.5+1 24 | flutter_dialogflow: ^0.1.3 25 | uuid: ^2.0.0 26 | soundpool: ^1.0.1 27 | audio_recorder: ^1.0.2 28 | path_provider: ^1.6.7 29 | basic_utils: ^2.5.3 30 | material_design_icons_flutter: ^4.0.5345 31 | shared_preferences: ^0.5.8 32 | ros_nodes: 33 | git: 34 | url: git://github.com/Sashiri/ros_nodes.git 35 | localstorage: ^3.0.0 36 | flutter_colorpicker: ^0.3.4 37 | english_words: ^3.1.5 38 | flutter_localizations: 39 | sdk: flutter 40 | permission_handler: ^5.0.1+1 41 | 42 | dev_dependencies: 43 | flutter_test: 44 | sdk: flutter 45 | 46 | # For information on the generic Dart part of this file, see the 47 | # following page: https://dart.dev/tools/pub/pubspec 48 | # The following section is specific to Flutter. 49 | flutter: 50 | 51 | # The following line ensures that the Material Icons font is 52 | # included with your application, so that you can use the icons in 53 | # the material Icons class. 54 | uses-material-design: true 55 | 56 | # To add assets to your application, add an assets section, like this: 57 | assets: 58 | - assets/dialogflowapi.json 59 | # - images/a_dot_burr.jpeg 60 | # - images/a_dot_ham.jpeg 61 | # An image asset can refer to one or more resolution-specific "variants", see 62 | # https://flutter.dev/assets-and-images/#resolution-aware. 63 | # For details regarding adding assets from package dependencies, see 64 | # https://flutter.dev/assets-and-images/#from-packages 65 | # To add custom fonts to your application, add a fonts section here, 66 | # in this "flutter" section. Each entry in this list should have a 67 | # "family" key with the font family name, and a "fonts" key with a 68 | # list giving the asset and other descriptors for the font. For 69 | # example: 70 | # fonts: 71 | # - family: Schyler 72 | # fonts: 73 | # - asset: fonts/Schyler-Regular.ttf 74 | # - asset: fonts/Schyler-Italic.ttf 75 | # style: italic 76 | # - family: Trajan Pro 77 | # fonts: 78 | # - asset: fonts/TrajanPro.ttf 79 | # - asset: fonts/TrajanPro_Bold.ttf 80 | # weight: 700 81 | # 82 | # For details regarding fonts from package dependencies, 83 | # see https://flutter.dev/custom-fonts/#from-packages 84 | flutter_intl: 85 | enabled: true 86 | -------------------------------------------------------------------------------- /test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:chatapp/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/web/favicon.png -------------------------------------------------------------------------------- /web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/web/icons/Icon-192.png -------------------------------------------------------------------------------- /web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rongix/ros_navigation_command_app/b753892383b08cfb929a6e9aeb3718b4cdbc3163/web/icons/Icon-512.png -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | chat_app 18 | 19 | 20 | 21 | 24 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chat_app", 3 | "short_name": "chat_app", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | } 22 | ] 23 | } 24 | --------------------------------------------------------------------------------