From 8655d2e7b8f36749b6a9b4cd0c6141f28cc9a33f Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 21 Jun 2021 13:05:30 -0700 Subject: [PATCH] [Fixed] ESP32 | BLUETOOTH CLASSIC | FLUTTER - Let's build BT Serial based on the examples. (Ft. Chat App) --- .../.flutter-plugins-dependencies | 1 + .../android_bluetooth_serial_app/.gitignore | 877 +++++++++++++++++- .../lib/BackgroundCollectedPage.dart | 145 --- .../lib/BackgroundCollectingTask.dart | 123 --- .../lib/BluetoothDeviceListEntry.dart | 12 +- .../lib/ChatPage.dart | 23 +- .../lib/DiscoveryPage.dart | 56 +- .../lib/MainPage.dart | 215 +---- .../lib/SelectBondedDevicePage.dart | 144 --- .../lib/helpers/LineChart.dart | 600 ------------ .../lib/helpers/PaintStyle.dart | 263 ------ .../lib/main.dart | 16 +- .../android_bluetooth_serial_app/pubspec.lock | 50 +- .../android_bluetooth_serial_app/pubspec.yaml | 3 +- 14 files changed, 932 insertions(+), 1596 deletions(-) create mode 100644 ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.flutter-plugins-dependencies delete mode 100755 ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectedPage.dart delete mode 100755 ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectingTask.dart delete mode 100755 ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/SelectBondedDevicePage.dart delete mode 100755 ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/LineChart.dart delete mode 100755 ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/PaintStyle.dart diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.flutter-plugins-dependencies b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.flutter-plugins-dependencies new file mode 100644 index 0000000..439c32a --- /dev/null +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.flutter-plugins-dependencies @@ -0,0 +1 @@ +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"flutter_bluetooth_serial","path":"/Users/sil0/.pub-cache/hosted/pub.dartlang.org/flutter_bluetooth_serial-0.2.2/","dependencies":[]}],"android":[{"name":"flutter_bluetooth_serial","path":"/Users/sil0/.pub-cache/hosted/pub.dartlang.org/flutter_bluetooth_serial-0.2.2/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_bluetooth_serial","dependencies":[]}],"date_created":"2021-06-21 13:03:01.480634","version":"2.2.2"} \ No newline at end of file diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.gitignore b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.gitignore index f3c2053..38ac421 100644 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.gitignore +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/.gitignore @@ -1,5 +1,8 @@ +### Flutter Generated + # Miscellaneous *.class +*.lock *.log *.pyc *.swp @@ -15,30 +18,878 @@ *.iws .idea/ -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ +# Visual Studio Code related +.vscode/ # Flutter/Dart/Pub related **/doc/api/ -**/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins -.flutter-plugins-dependencies .packages .pub-cache/ .pub/ +build/ + +# Android related +**/android/** +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/** +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + + +# macOS related +**/macos/** + + +### https://raw.github.com/github/gitignore//Android.gitignore + +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/caches + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + + +### https://raw.github.com/github/gitignore//Dart.gitignore + +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + + +### https://raw.github.com/github/gitignore//Global/JetBrains.gitignore + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + + +### https://raw.github.com/github/gitignore//Global/macOS.gitignore + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### https://raw.github.com/github/gitignore//Global/Xcode.gitignore + +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/Archives.gitignore + +# It's better to unpack these files and commit the raw source because +# git has its own built in compression methods. +*.7z +*.jar +*.rar +*.zip +*.gz +*.tgz +*.bzip +*.bz2 +*.xz +*.lzma +*.cab + +# Packing-only formats +*.iso +*.tar + +# Package management formats +*.dmg +*.xpi +*.gem +*.egg +*.deb +*.rpm +*.msi +*.msm +*.msp + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/Backup.gitignore + +*.bak +*.gho +*.ori +*.orig +*.tmp + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Android.gitignore + +# Built application files +*.apk +*.ap_ + +# Files for the ART/Dalvik VM +*.dex + +# Java class files +*.class + +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files +*.log + +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/caches + +# Keystore files +# Uncomment the following line if you do not want to check your keystore files in. +#*.jks + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output +fastlane/readme.md + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Dart.gitignore + +# See https://www.dartlang.org/guides/libraries/private-files + +# Files and directories created by pub +.dart_tool/ +.packages +build/ +# If you're building an application, you may want to check-in your pubspec.lock +pubspec.lock + +# Directory created by dartdoc +# If you don't generate documentation locally you can remove this line. +doc/api/ + +# Avoid committing generated Javascript files: +*.dart.js +*.info.json # Produced by the --dump-info flag. +*.js # When generated by dart2js. Don't specify *.js if your + # project includes source files written in JavaScript. +*.js_ +*.js.deps +*.js.map + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/DartEditor.gitignore + +.project +.buildlog + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/Emacs.gitignore + +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Gradle.gitignore + +.gradle /build/ -# Web related -lib/generated_plugin_registrant.dart +# Ignore Gradle GUI config +gradle-app.setting -# Symbolication related -app.*.symbols +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar -# Obfuscation related -app.*.map.json +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Java.gitignore + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/JetBrains.gitignore + +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/JEnv.gitignore + +# JEnv local Java version configuration file +.java-version + +# Used by previous versions of JEnv +.jenv-version + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Kotlin.gitignore + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/Linux.gitignore + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/macOS.gitignore + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Maven.gitignore + +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Objective-C.gitignore + +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/SublimeText.gitignore + +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/Vim.gitignore + +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/VisualStudioCode.gitignore + +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/Windows.gitignore + +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +### https://raw.github.com/github/gitignore/340e2fe08a2356c2e3760ff58c3a9e1fddf08060/Global/Xcode.gitignore + +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + + +### Flutter Generated Exceptions # Exceptions to above rules. -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages \ No newline at end of file diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectedPage.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectedPage.dart deleted file mode 100755 index 298cc16..0000000 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectedPage.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:flutter/material.dart'; - -import './BackgroundCollectingTask.dart'; -import './helpers/LineChart.dart'; -import './helpers/PaintStyle.dart'; - -class BackgroundCollectedPage extends StatelessWidget { - @override - Widget build(BuildContext context) { - final BackgroundCollectingTask task = - BackgroundCollectingTask.of(context, rebuildOnChange: true); - - // Arguments shift is needed for timestamps as miliseconds in double could loose precision. - final int argumentsShift = - task.samples.first.timestamp.millisecondsSinceEpoch; - - final Duration showDuration = - Duration(hours: 2); // @TODO . show duration should be configurable - final Iterable lastSamples = task.getLastOf(showDuration); - - final Iterable arguments = lastSamples.map((sample) { - return (sample.timestamp.millisecondsSinceEpoch - argumentsShift) - .toDouble(); - }); - - // Step for argument labels - final Duration argumentsStep = - Duration(minutes: 15); // @TODO . step duration should be configurable - - // Find first timestamp floored to step before - final DateTime beginningArguments = lastSamples.first.timestamp; - DateTime beginningArgumentsStep = DateTime(beginningArguments.year, - beginningArguments.month, beginningArguments.day); - while (beginningArgumentsStep.isBefore(beginningArguments)) { - beginningArgumentsStep = beginningArgumentsStep.add(argumentsStep); - } - beginningArgumentsStep = beginningArgumentsStep.subtract(argumentsStep); - final DateTime endingArguments = lastSamples.last.timestamp; - - // Generate list of timestamps of labels - final Iterable argumentsLabelsTimestamps = () sync* { - DateTime timestamp = beginningArgumentsStep; - yield timestamp; - while (timestamp.isBefore(endingArguments)) { - timestamp = timestamp.add(argumentsStep); - yield timestamp; - } - }(); - - // Map strings for labels - final Iterable argumentsLabels = - argumentsLabelsTimestamps.map((timestamp) { - return LabelEntry( - (timestamp.millisecondsSinceEpoch - argumentsShift).toDouble(), - ((timestamp.hour <= 9 ? '0' : '') + - timestamp.hour.toString() + - ':' + - (timestamp.minute <= 9 ? '0' : '') + - timestamp.minute.toString())); - }); - - return Scaffold( - appBar: AppBar( - title: Text('Collected data'), - actions: [ - // Progress circle - (task.inProgress - ? FittedBox( - child: Container( - margin: new EdgeInsets.all(16.0), - child: CircularProgressIndicator( - valueColor: - AlwaysStoppedAnimation(Colors.white)))) - : Container(/* Dummy */)), - // Start/stop buttons - (task.inProgress - ? IconButton(icon: Icon(Icons.pause), onPressed: task.pause) - : IconButton( - icon: Icon(Icons.play_arrow), onPressed: task.reasume)), - ], - ), - body: ListView( - children: [ - Divider(), - ListTile( - leading: const Icon(Icons.brightness_7), - title: const Text('Temperatures'), - subtitle: const Text('In Celsius'), - ), - LineChart( - constraints: const BoxConstraints.expand(height: 350), - arguments: arguments, - argumentsLabels: argumentsLabels, - values: [ - lastSamples.map((sample) => sample.temperature1), - lastSamples.map((sample) => sample.temperature2), - ], - verticalLinesStyle: const PaintStyle(color: Colors.grey), - additionalMinimalHorizontalLabelsInterval: 0, - additionalMinimalVerticalLablesInterval: 0, - seriesPointsStyles: [ - null, - null, - //const PaintStyle(style: PaintingStyle.stroke, strokeWidth: 1.7*3, color: Colors.indigo, strokeCap: StrokeCap.round), - ], - seriesLinesStyles: [ - const PaintStyle( - style: PaintingStyle.stroke, - strokeWidth: 1.7, - color: Colors.indigoAccent), - const PaintStyle( - style: PaintingStyle.stroke, - strokeWidth: 1.7, - color: Colors.redAccent), - ], - ), - Divider(), - ListTile( - leading: const Icon(Icons.filter_vintage), - title: const Text('Water pH level'), - ), - LineChart( - constraints: const BoxConstraints.expand(height: 200), - arguments: arguments, - argumentsLabels: argumentsLabels, - values: [ - lastSamples.map((sample) => sample.waterpHlevel), - ], - verticalLinesStyle: const PaintStyle(color: Colors.grey), - additionalMinimalHorizontalLabelsInterval: 0, - additionalMinimalVerticalLablesInterval: 0, - seriesPointsStyles: [ - null, - ], - seriesLinesStyles: [ - const PaintStyle( - style: PaintingStyle.stroke, - strokeWidth: 1.7, - color: Colors.greenAccent), - ], - ), - ], - )); - } -} diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectingTask.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectingTask.dart deleted file mode 100755 index 9cc73d2..0000000 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BackgroundCollectingTask.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; -import 'package:scoped_model/scoped_model.dart'; - -class DataSample { - double temperature1; - double temperature2; - double waterpHlevel; - DateTime timestamp; - - DataSample({ - this.temperature1, - this.temperature2, - this.waterpHlevel, - this.timestamp, - }); -} - -class BackgroundCollectingTask extends Model { - static BackgroundCollectingTask of( - BuildContext context, { - bool rebuildOnChange = false, - }) => - ScopedModel.of( - context, - rebuildOnChange: rebuildOnChange, - ); - - final BluetoothConnection _connection; - List _buffer = List(); - - // @TODO , Such sample collection in real code should be delegated - // (via `Stream` preferably) and then saved for later - // displaying on chart (or even stright prepare for displaying). - // @TODO ? should be shrinked at some point, endless colleting data would cause memory shortage. - List samples = List(); - - bool inProgress; - - BackgroundCollectingTask._fromConnection(this._connection) { - _connection.input.listen((data) { - _buffer += data; - - while (true) { - // If there is a sample, and it is full sent - int index = _buffer.indexOf('t'.codeUnitAt(0)); - if (index >= 0 && _buffer.length - index >= 7) { - final DataSample sample = DataSample( - temperature1: (_buffer[index + 1] + _buffer[index + 2] / 100), - temperature2: (_buffer[index + 3] + _buffer[index + 4] / 100), - waterpHlevel: (_buffer[index + 5] + _buffer[index + 6] / 100), - timestamp: DateTime.now()); - _buffer.removeRange(0, index + 7); - - samples.add(sample); - notifyListeners(); // Note: It shouldn't be invoked very often - in this example data comes at every second, but if there would be more data, it should update (including repaint of graphs) in some fixed interval instead of after every sample. - //print("${sample.timestamp.toString()} -> ${sample.temperature1} / ${sample.temperature2}"); - } - // Otherwise break - else { - break; - } - } - }).onDone(() { - inProgress = false; - notifyListeners(); - }); - } - - static Future connect( - BluetoothDevice server) async { - final BluetoothConnection connection = - await BluetoothConnection.toAddress(server.address); - return BackgroundCollectingTask._fromConnection(connection); - } - - void dispose() { - _connection.dispose(); - } - - Future start() async { - inProgress = true; - _buffer.clear(); - samples.clear(); - notifyListeners(); - _connection.output.add(ascii.encode('start')); - await _connection.output.allSent; - } - - Future cancel() async { - inProgress = false; - notifyListeners(); - _connection.output.add(ascii.encode('stop')); - await _connection.finish(); - } - - Future pause() async { - inProgress = false; - notifyListeners(); - _connection.output.add(ascii.encode('stop')); - await _connection.output.allSent; - } - - Future reasume() async { - inProgress = true; - notifyListeners(); - _connection.output.add(ascii.encode('start')); - await _connection.output.allSent; - } - - Iterable getLastOf(Duration duration) { - DateTime startingTime = DateTime.now().subtract(duration); - int i = samples.length; - do { - i -= 1; - if (i <= 0) { - break; - } - } while (samples[i].timestamp.isAfter(startingTime)); - return samples.getRange(i, samples.length); - } -} diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BluetoothDeviceListEntry.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BluetoothDeviceListEntry.dart index ff9781b..8a7ff4e 100755 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BluetoothDeviceListEntry.dart +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/BluetoothDeviceListEntry.dart @@ -3,17 +3,15 @@ import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; class BluetoothDeviceListEntry extends ListTile { BluetoothDeviceListEntry({ - @required BluetoothDevice device, - int rssi, - GestureTapCallback onTap, - GestureLongPressCallback onLongPress, + required BluetoothDevice device, + required rssi, + required GestureTapCallback onTap, bool enabled = true, }) : super( onTap: onTap, - onLongPress: onLongPress, enabled: enabled, - leading: - Icon(Icons.devices), // @TODO . !BluetoothClass! class aware icon + leading: Icon(Icons.devices), + // @TODO . !BluetoothClass! class aware icon title: Text(device.name ?? "Unknown device"), subtitle: Text(device.address.toString()), trailing: Row( diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/ChatPage.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/ChatPage.dart index 596f81f..336aa0c 100755 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/ChatPage.dart +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/ChatPage.dart @@ -1,13 +1,14 @@ import 'dart:async'; import 'dart:convert'; import 'dart:typed_data'; + import 'package:flutter/material.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; class ChatPage extends StatefulWidget { final BluetoothDevice server; - const ChatPage({this.server}); + const ChatPage({required this.server}); @override _ChatPage createState() => new _ChatPage(); @@ -22,9 +23,9 @@ class _Message { class _ChatPage extends State { static final clientID = 0; - BluetoothConnection connection; + var connection; //BluetoothConnection - List<_Message> messages = List<_Message>(); + List<_Message> messages = []; String _messageBuffer = ''; final TextEditingController textEditingController = @@ -32,8 +33,6 @@ class _ChatPage extends State { final ScrollController listScrollController = new ScrollController(); bool isConnecting = true; - bool get isConnected => connection != null && connection.isConnected; - bool isDisconnecting = false; @override @@ -73,7 +72,7 @@ class _ChatPage extends State { @override void dispose() { // Avoid memory leak (`setState` after dispose) and disconnect - if (isConnected) { + if (isConnected()) { isDisconnecting = true; connection.dispose(); connection = null; @@ -112,7 +111,7 @@ class _ChatPage extends State { appBar: AppBar( title: (isConnecting ? Text('Connecting chat to ' + widget.server.name + '...') - : isConnected + : isConnected() ? Text('Live chat with ' + widget.server.name) : Text('Chat log with ' + widget.server.name))), body: SafeArea( @@ -135,12 +134,12 @@ class _ChatPage extends State { decoration: InputDecoration.collapsed( hintText: isConnecting ? 'Wait until connected...' - : isConnected + : isConnected() ? 'Type your message...' : 'Chat got disconnected', hintStyle: const TextStyle(color: Colors.grey), ), - enabled: isConnected, + enabled: isConnected(), ), ), ), @@ -148,7 +147,7 @@ class _ChatPage extends State { margin: const EdgeInsets.all(8.0), child: IconButton( icon: const Icon(Icons.send), - onPressed: isConnected + onPressed: isConnected() ? () => _sendMessage(textEditingController.text) : null), ), @@ -234,4 +233,8 @@ class _ChatPage extends State { } } } + + bool isConnected() { + return connection != null && connection.isConnected; + } } diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/DiscoveryPage.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/DiscoveryPage.dart index d96a6b5..6c88c75 100755 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/DiscoveryPage.dart +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/DiscoveryPage.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; @@ -15,11 +16,9 @@ class DiscoveryPage extends StatefulWidget { } class _DiscoveryPage extends State { - StreamSubscription _streamSubscription; - List results = List(); - bool isDiscovering; - - _DiscoveryPage(); + late StreamSubscription _streamSubscription; + List results = []; + late bool isDiscovering; @override void initState() { @@ -98,53 +97,6 @@ class _DiscoveryPage extends State { onTap: () { Navigator.of(context).pop(result.device); }, - onLongPress: () async { - try { - bool bonded = false; - if (result.device.isBonded) { - print('Unbonding from ${result.device.address}...'); - await FlutterBluetoothSerial.instance - .removeDeviceBondWithAddress(result.device.address); - print('Unbonding from ${result.device.address} has succed'); - } else { - print('Bonding with ${result.device.address}...'); - bonded = await FlutterBluetoothSerial.instance - .bondDeviceAtAddress(result.device.address); - print( - 'Bonding with ${result.device.address} has ${bonded ? 'succed' : 'failed'}.'); - } - setState(() { - results[results.indexOf(result)] = BluetoothDiscoveryResult( - device: BluetoothDevice( - name: result.device.name ?? '', - address: result.device.address, - type: result.device.type, - bondState: bonded - ? BluetoothBondState.bonded - : BluetoothBondState.none, - ), - rssi: result.rssi); - }); - } catch (ex) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Error occured while bonding'), - content: Text("${ex.toString()}"), - actions: [ - new FlatButton( - child: new Text("Close"), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - }, ); }, ), diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/MainPage.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/MainPage.dart index 87aa67b..d238e83 100755 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/MainPage.dart +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/MainPage.dart @@ -1,15 +1,10 @@ import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; -import 'package:scoped_model/scoped_model.dart'; -import './DiscoveryPage.dart'; -import './SelectBondedDevicePage.dart'; import './ChatPage.dart'; -import './BackgroundCollectingTask.dart'; -import './BackgroundCollectedPage.dart'; - -// import './helpers/LineChart.dart'; +import './DiscoveryPage.dart'; class MainPage extends StatefulWidget { @override @@ -22,13 +17,6 @@ class _MainPage extends State { String _address = "..."; String _name = "..."; - Timer _discoverableTimeoutTimer; - int _discoverableTimeoutSecondsLeft = 0; - - BackgroundCollectingTask _collectingTask; - - bool _autoAcceptPairingRequests = false; - @override void initState() { super.initState(); @@ -68,10 +56,6 @@ class _MainPage extends State { .listen((BluetoothState state) { setState(() { _bluetoothState = state; - - // Discoverable mode is disabled when Bluetooth gets disabled - _discoverableTimeoutTimer = null; - _discoverableTimeoutSecondsLeft = 0; }); }); } @@ -79,8 +63,6 @@ class _MainPage extends State { @override void dispose() { FlutterBluetoothSerial.instance.setPairingRequestHandler(null); - _collectingTask?.dispose(); - _discoverableTimeoutTimer?.cancel(); super.dispose(); } @@ -132,91 +114,11 @@ class _MainPage extends State { subtitle: Text(_name), onLongPress: null, ), - ListTile( - title: _discoverableTimeoutSecondsLeft == 0 - ? const Text("Discoverable") - : Text( - "Discoverable for ${_discoverableTimeoutSecondsLeft}s"), - subtitle: const Text("PsychoX-Luna"), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Checkbox( - value: _discoverableTimeoutSecondsLeft != 0, - onChanged: null, - ), - IconButton( - icon: const Icon(Icons.edit), - onPressed: null, - ), - IconButton( - icon: const Icon(Icons.refresh), - onPressed: () async { - print('Discoverable requested'); - final int timeout = await FlutterBluetoothSerial.instance - .requestDiscoverable(60); - if (timeout < 0) { - print('Discoverable mode denied'); - } else { - print( - 'Discoverable mode acquired for $timeout seconds'); - } - setState(() { - _discoverableTimeoutTimer?.cancel(); - _discoverableTimeoutSecondsLeft = timeout; - _discoverableTimeoutTimer = - Timer.periodic(Duration(seconds: 1), (Timer timer) { - setState(() { - if (_discoverableTimeoutSecondsLeft < 0) { - FlutterBluetoothSerial.instance.isDiscoverable - .then((isDiscoverable) { - if (isDiscoverable) { - print( - "Discoverable after timeout... might be infinity timeout :F"); - _discoverableTimeoutSecondsLeft += 1; - } - }); - timer.cancel(); - _discoverableTimeoutSecondsLeft = 0; - } else { - _discoverableTimeoutSecondsLeft -= 1; - } - }); - }); - }); - }, - ) - ], - ), - ), Divider(), - ListTile(title: const Text('Devices discovery and connection')), - SwitchListTile( - title: const Text('Auto-try specific pin when pairing'), - subtitle: const Text('Pin 1234'), - value: _autoAcceptPairingRequests, - onChanged: (bool value) { - setState(() { - _autoAcceptPairingRequests = value; - }); - if (value) { - FlutterBluetoothSerial.instance.setPairingRequestHandler( - (BluetoothPairingRequest request) { - print("Trying to auto-pair with Pin 1234"); - if (request.pairingVariant == PairingVariant.Pin) { - return Future.value("1234"); - } - return null; - }); - } else { - FlutterBluetoothSerial.instance - .setPairingRequestHandler(null); - } - }, - ), ListTile( - title: RaisedButton( - child: const Text('Explore discovered devices'), + title: TextButton( + child: + const Text('Connect to paired device to chat with ESP32'), onPressed: () async { final BluetoothDevice selectedDevice = await Navigator.of(context).push( @@ -229,86 +131,12 @@ class _MainPage extends State { if (selectedDevice != null) { print('Discovery -> selected ' + selectedDevice.address); + _startChat(context, selectedDevice); } else { print('Discovery -> no device selected'); } }), ), - ListTile( - title: RaisedButton( - child: const Text('Connect to paired device to chat'), - onPressed: () async { - final BluetoothDevice selectedDevice = - await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return SelectBondedDevicePage(checkAvailability: false); - }, - ), - ); - - if (selectedDevice != null) { - print('Connect -> selected ' + selectedDevice.address); - _startChat(context, selectedDevice); - } else { - print('Connect -> no device selected'); - } - }, - ), - ), - Divider(), - ListTile(title: const Text('Multiple connections example')), - ListTile( - title: RaisedButton( - child: ((_collectingTask != null && _collectingTask.inProgress) - ? const Text('Disconnect and stop background collecting') - : const Text('Connect to start background collecting')), - onPressed: () async { - if (_collectingTask != null && _collectingTask.inProgress) { - await _collectingTask.cancel(); - setState(() { - /* Update for `_collectingTask.inProgress` */ - }); - } else { - final BluetoothDevice selectedDevice = - await Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return SelectBondedDevicePage( - checkAvailability: false); - }, - ), - ); - - if (selectedDevice != null) { - await _startBackgroundTask(context, selectedDevice); - setState(() { - /* Update for `_collectingTask.inProgress` */ - }); - } - } - }, - ), - ), - ListTile( - title: RaisedButton( - child: const Text('View background collected data'), - onPressed: (_collectingTask != null) - ? () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) { - return ScopedModel( - model: _collectingTask, - child: BackgroundCollectedPage(), - ); - }, - ), - ); - } - : null, - ), - ), ], ), ), @@ -324,35 +152,4 @@ class _MainPage extends State { ), ); } - - Future _startBackgroundTask( - BuildContext context, - BluetoothDevice server, - ) async { - try { - _collectingTask = await BackgroundCollectingTask.connect(server); - await _collectingTask.start(); - } catch (ex) { - if (_collectingTask != null) { - _collectingTask.cancel(); - } - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Error occured while connecting'), - content: Text("${ex.toString()}"), - actions: [ - new FlatButton( - child: new Text("Close"), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - } } diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/SelectBondedDevicePage.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/SelectBondedDevicePage.dart deleted file mode 100755 index 29584bc..0000000 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/SelectBondedDevicePage.dart +++ /dev/null @@ -1,144 +0,0 @@ -import 'dart:async'; -import 'package:flutter/material.dart'; -import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; - -import './BluetoothDeviceListEntry.dart'; - -class SelectBondedDevicePage extends StatefulWidget { - /// If true, on page start there is performed discovery upon the bonded devices. - /// Then, if they are not avaliable, they would be disabled from the selection. - final bool checkAvailability; - - const SelectBondedDevicePage({this.checkAvailability = true}); - - @override - _SelectBondedDevicePage createState() => new _SelectBondedDevicePage(); -} - -enum _DeviceAvailability { - no, - maybe, - yes, -} - -class _DeviceWithAvailability extends BluetoothDevice { - BluetoothDevice device; - _DeviceAvailability availability; - int rssi; - - _DeviceWithAvailability(this.device, this.availability, [this.rssi]); -} - -class _SelectBondedDevicePage extends State { - List<_DeviceWithAvailability> devices = List<_DeviceWithAvailability>(); - - // Availability - StreamSubscription _discoveryStreamSubscription; - bool _isDiscovering; - - _SelectBondedDevicePage(); - - @override - void initState() { - super.initState(); - - _isDiscovering = widget.checkAvailability; - - if (_isDiscovering) { - _startDiscovery(); - } - - // Setup a list of the bonded devices - FlutterBluetoothSerial.instance - .getBondedDevices() - .then((List bondedDevices) { - setState(() { - devices = bondedDevices - .map( - (device) => _DeviceWithAvailability( - device, - widget.checkAvailability - ? _DeviceAvailability.maybe - : _DeviceAvailability.yes, - ), - ) - .toList(); - }); - }); - } - - void _restartDiscovery() { - setState(() { - _isDiscovering = true; - }); - - _startDiscovery(); - } - - void _startDiscovery() { - _discoveryStreamSubscription = - FlutterBluetoothSerial.instance.startDiscovery().listen((r) { - setState(() { - Iterator i = devices.iterator; - while (i.moveNext()) { - var _device = i.current; - if (_device.device == r.device) { - _device.availability = _DeviceAvailability.yes; - _device.rssi = r.rssi; - } - } - }); - }); - - _discoveryStreamSubscription.onDone(() { - setState(() { - _isDiscovering = false; - }); - }); - } - - @override - void dispose() { - // Avoid memory leak (`setState` after dispose) and cancel discovery - _discoveryStreamSubscription?.cancel(); - - super.dispose(); - } - - @override - Widget build(BuildContext context) { - List list = devices - .map((_device) => BluetoothDeviceListEntry( - device: _device.device, - rssi: _device.rssi, - enabled: _device.availability == _DeviceAvailability.yes, - onTap: () { - Navigator.of(context).pop(_device.device); - }, - )) - .toList(); - return Scaffold( - appBar: AppBar( - title: Text('Select device'), - actions: [ - _isDiscovering - ? FittedBox( - child: Container( - margin: new EdgeInsets.all(16.0), - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Colors.white, - ), - ), - ), - ) - : IconButton( - icon: Icon(Icons.replay), - onPressed: _restartDiscovery, - ) - ], - ), - body: ListView(children: list), - ); - } -} diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/LineChart.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/LineChart.dart deleted file mode 100755 index 281001e..0000000 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/LineChart.dart +++ /dev/null @@ -1,600 +0,0 @@ -/// @name LineChart -/// @version 0.0.5 -/// @description Simple line chart widget -/// @author Patryk "PsychoX" Ludwikowski -/// @license MIT License (see https://mit-license.org/) - -import 'package:flutter/material.dart'; -import 'dart:ui' as ui; -import 'dart:math' as math show min, max; - -import './PaintStyle.dart'; - -class LabelEntry { - final double value; - final String label; - - LabelEntry(this.value, this.label); -} - -/// Widget that allows to show data on line chart. -/// -/// All arguments, values and labels data should be sorted! -/// Since both the arguments and the values must be `double` type, -/// be aware of the precision. -class LineChart extends StatelessWidget { - /// Constraints for the line chart. - final BoxConstraints constraints; - - // @TODO ? Both `_LineChartPainter` and `LineChart` have most the same fields. - // `LineChart` is just mainly passing them to the painter. Shouldn't there be - // only one class containing these data? Some `LineChartData` forged inside here - // and then passed and used by the painter? :thinking: - - /// Padding around main drawng area. Necessary for displaying labels (around the chart). - final EdgeInsets padding; - - /* Arguments */ - /// Collection of doubles as arguments. - final Iterable arguments; - - /// Mappings of strings for doubles arguments, which allow to specify custom - /// strings as labels for certain arguments. - final Iterable argumentsLabels; - - /* Values */ - /// Collection of data series as collections of next values on corresponding arguments. - final Iterable> values; - - /// Mappings of string for doubles values, which allow to specify custom - /// string as labels for certain values. - final Iterable valuesLabels; - - /* Labels & lines styles */ - /// Style of horizontal lines labels - final TextStyle horizontalLabelsTextStyle; - - /// Style of vertical lines labels - final TextStyle verticalLabelsTextStyle; - - /// Defines style of horizontal lines. Might be null in order to prevent lines from drawing. - final Paint horizontalLinesPaint; - - /// Defines style of vertical lines. Might be null in order to prevent lines from drawing. - final Paint verticalLinesPaint; - - // @TODO . expose it - final bool snapToLeftLabel = false; - final bool snapToTopLabel = true; - final bool snapToRightLabel = false; - final bool snapToBottomLabel = true; - - /* Series points & lines styles */ - /// List of paint styles for series values points. - /// - /// On whole list null would use predefined set of styles. - /// On list entry null there will be no points for certain series. - final List seriesPointsPaints; - - /// List of paint styles for lines between next series points. - /// - /// On null there will be no lines. - final List seriesLinesPaints; - - final double additionalMinimalHorizontalLabelsInterval; - final double additionalMinimalVerticalLablesInterval; - - LineChart({ - @required this.constraints, - this.padding = const EdgeInsets.fromLTRB(32, 12, 20, 28), - this.arguments, - this.argumentsLabels, - this.values, - this.valuesLabels, - this.horizontalLabelsTextStyle, - this.verticalLabelsTextStyle, - PaintStyle horizontalLinesStyle = const PaintStyle(color: Colors.grey), - PaintStyle verticalLinesStyle, // null for default - - this.additionalMinimalHorizontalLabelsInterval = 8, - this.additionalMinimalVerticalLablesInterval = 8, - Iterable - seriesPointsStyles, // null would use predefined set of styles - Iterable seriesLinesStyles, // null for default - }) : horizontalLinesPaint = horizontalLinesStyle?.toPaint(), - verticalLinesPaint = verticalLinesStyle?.toPaint(), - seriesPointsPaints = _prepareSeriesPointsPaints(seriesPointsStyles), - seriesLinesPaints = _prepareSeriesLinesPaints(seriesLinesStyles) { - if (seriesPointsStyles.length < values.length && - 12 /* default paints */ < values.length) { - throw "Too few `seriesPointsPaintStyle`s! Try define more or limit number of displayed series"; - } - if (seriesLinesStyles.length < values.length) { - throw "Too few `seriesLinesStyles`s! Try define more or limit number of displayed series"; - } - } - - static Iterable _prepareSeriesPointsPaints( - Iterable seriesPointsStyles) { - if (seriesPointsStyles == null) { - // Default paint for points - return List.unmodifiable([ - PaintStyle(strokeWidth: 1.7, color: Colors.blue).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.red).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.yellow).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.green).toPaint(), - - PaintStyle(strokeWidth: 1.7, color: Colors.purple).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.deepOrange).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.brown).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.lime).toPaint(), - - PaintStyle(strokeWidth: 1.7, color: Colors.indigo).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.pink).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.amber).toPaint(), - PaintStyle(strokeWidth: 1.7, color: Colors.teal).toPaint(), - - // For more, user should specify them :F - ]); - } else { - return seriesPointsStyles.map((style) => style?.toPaint()).toList(); - } - } - - static Iterable _prepareSeriesLinesPaints( - Iterable seriesLinesStyles) { - if (seriesLinesStyles == null) { - return null; - } else { - return seriesLinesStyles.map((style) => style.toPaint()).toList(); - } - } - - @override - Widget build(BuildContext context) { - return ConstrainedBox( - constraints: this.constraints, - child: CustomPaint( - painter: _LineChartPainter( - padding: padding, - arguments: arguments, - argumentsLabels: argumentsLabels, - values: values, - valuesLabels: valuesLabels, - horizontalLabelsTextStyle: - horizontalLabelsTextStyle ?? Theme.of(context).textTheme.caption, - verticalLabelsTextStyle: - verticalLabelsTextStyle ?? Theme.of(context).textTheme.caption, - horizontalLinesPaint: horizontalLinesPaint, - verticalLinesPaint: verticalLinesPaint, - additionalMinimalHorizontalLabelsInterval: - additionalMinimalHorizontalLabelsInterval, - additionalMinimalVerticalLablesInterval: - additionalMinimalVerticalLablesInterval, - seriesPointsPaints: seriesPointsPaints, - seriesLinesPaints: seriesLinesPaints, - ))); - } -} - -class _LineChartPainter extends CustomPainter { - /// Padding around main drawng area. Necessary for displaying labels (around the chart). - final EdgeInsets padding; - - /* Arguments */ - /// Collection of doubles as arguments. - final Iterable arguments; - - /// Mappings of strings for doubles arguments, which allow to specify custom - /// strings as labels for certain arguments. - final Iterable argumentsLabels; - - /* Values */ - /// Collection of data series as collections of next values on corresponding arguments. - final Iterable> values; - - /// Mappings of string for doubles values, which allow to specify custom - /// string as labels for certain values. - final Iterable valuesLabels; - - /* Labels & lines styles */ - /// Style of horizontal lines labels - final TextStyle horizontalLabelsTextStyle; - - /// Style of vertical lines labels - final TextStyle verticalLabelsTextStyle; - - /// Defines style of horizontal lines. Might be null in order to prevent lines from drawing. - final Paint horizontalLinesPaint; - - /// Defines style of vertical lines. Might be null in order to prevent lines from drawing. - final Paint verticalLinesPaint; - - // @TODO . expose it - final bool snapToLeftLabel = false; - final bool snapToTopLabel = true; - final bool snapToRightLabel = false; - final bool snapToBottomLabel = true; - - /* Series points & lines styles */ - /// Collection of paint styles for series values points. - /// - /// On whole argument null would use predefined set of styles. - /// On collection entry null there will be no points for certain series. - final Iterable seriesPointsPaints; - - /// Collection of paint styles for lines between next series points. - /// - /// On null there will be no lines. - final Iterable seriesLinesPaints; - - /* Runtime */ - /// Minimal allowed interval between horizontal lines. Calculated from font size. - final double minimalHorizontalLabelsInterval; - - /// Maximal value of all data series values - double maxValue = -double.maxFinite; - - /// Minimal value of all data series values - double minValue = double.maxFinite; - - double _minimalHorizontalRatio = 0; - double _minimalVerticalRatio = 0; - - /// Creates `_LineChartPainter` (`CustomPainter`) with given data and styling. - _LineChartPainter({ - this.padding = const EdgeInsets.fromLTRB(40, 8, 8, 32), - this.arguments, - this.argumentsLabels, - this.values, - this.valuesLabels, - @required this.horizontalLabelsTextStyle, - @required this.verticalLabelsTextStyle, - @required this.horizontalLinesPaint, - @required this.verticalLinesPaint, - double additionalMinimalHorizontalLabelsInterval = 8, - double additionalMinimalVerticalLablesInterval = 8, - @required this.seriesPointsPaints, - @required this.seriesLinesPaints, - }) : this.minimalHorizontalLabelsInterval = - horizontalLabelsTextStyle.fontSize + - additionalMinimalHorizontalLabelsInterval { - // Find max & min values of data to be show - for (Iterable series in values) { - for (double value in series) { - if (value > maxValue) { - maxValue = value; - } else if (value < minValue) { - minValue = value; - } - } - } - - if (valuesLabels != null) { - // Find minimal vertical ratio to fit all provided values labels - Iterator entry = valuesLabels.iterator; - entry.moveNext(); - double lastValue = entry.current.value; - - while (entry.moveNext()) { - final double goodRatio = - minimalHorizontalLabelsInterval / (entry.current.value - lastValue); - if (goodRatio > _minimalVerticalRatio) { - _minimalVerticalRatio = goodRatio; - } - - lastValue = entry.current.value; - } - } - - if (argumentsLabels != null) { - // Find minimal horizontal ratio to fit all provided arguments labels - Iterator entry = argumentsLabels.iterator; - entry.moveNext(); - double lastValue = entry.current.value; - double lastWidth = - _getLabelTextPainter(entry.current.label, verticalLabelsTextStyle) - .width; - - while (entry.moveNext()) { - final double nextValue = entry.current.value; - final double nextWidth = - _getLabelTextPainter(entry.current.label, verticalLabelsTextStyle) - .width; - - final double goodRatio = ((lastWidth + nextWidth) / 2 + - additionalMinimalVerticalLablesInterval) / - (nextValue - lastValue); - if (goodRatio > _minimalHorizontalRatio) { - _minimalHorizontalRatio = goodRatio; - } - - lastValue = nextValue; - lastWidth = nextWidth; - } - } - } - - @override - void paint(Canvas canvas, Size size) { - final double width = size.width - padding.left - padding.right; - final double height = size.height - padding.top - padding.bottom; - - /* Horizontal lines with labels */ - double valuesOffset = 0; // @TODO ? could be used in future for scrolling - double verticalRatio; - - { - Iterable labels; - - // If no labels provided - generate them! - if (valuesLabels == null) { - final double optimalStepValue = - _calculateOptimalStepValue(maxValue - minValue, height); - int stepsNumber = 1; - - // Find bottom line value - double bottomValue = 0; - if (minValue > 0) { - while (bottomValue < minValue) { - bottomValue += optimalStepValue; - } - bottomValue -= optimalStepValue; - } else { - while (bottomValue > minValue) { - bottomValue -= optimalStepValue; - } - } - valuesOffset = bottomValue; - - // Find top line value - double topValue = bottomValue; - while (topValue < maxValue) { - topValue += optimalStepValue; - stepsNumber += 1; - } - - // Set labels iterable from prepared generator - Iterable generator(double optimalStepValue, int stepsNumber, - [double value = 0.0]) sync* { - //double value = _bottomValue; - for (int i = 0; i < stepsNumber; i++) { - yield LabelEntry( - value, - value - .toString()); // @TODO , choose better precision based on optimal step value while parsing to string - value += optimalStepValue; - } - } - - labels = generator(optimalStepValue, stepsNumber, bottomValue); - - if (!snapToTopLabel) { - topValue = maxValue; - } - if (!snapToBottomLabel) { - bottomValue = valuesOffset = minValue; - } - - // Calculate vertical ratio of pixels per value - // Note: There is no empty space already - verticalRatio = height / (topValue - bottomValue); - } - // If labels provided - use them - else { - // Set labels iterable as the provided list - labels = valuesLabels; - - // Use minimal visible value as offset. - // Note: `minValue` is calculated in constructor and includes miniaml labels values. - valuesOffset = minValue; - - // Calculate vertical ratio of pixels per value - // Note: `_minimalVerticalRatio` is calculated in constructor - final double topValue = snapToTopLabel - ? math.max(maxValue, valuesLabels.last.value) - : maxValue; - final double bottomValue = snapToBottomLabel - ? math.min(minValue, valuesLabels.first.value) - : minValue; - final double noEmptySpaceRatio = height / (topValue - bottomValue); - verticalRatio = math.max(_minimalVerticalRatio, noEmptySpaceRatio); - } - - // Draw the horizontal lines and labels - for (LabelEntry tuple in labels) { - if (tuple.value < valuesOffset) continue; - final double yOffset = (size.height - - padding.bottom - - (tuple.value - valuesOffset) * verticalRatio); - if (yOffset < padding.top) break; - - // Draw line - if (horizontalLinesPaint != null) { - canvas.drawLine( - Offset(padding.left, yOffset), - Offset(size.width - padding.right, yOffset), - horizontalLinesPaint); - } - - // Draw label - TextPainter( - text: TextSpan(text: tuple.label, style: horizontalLabelsTextStyle), - textAlign: TextAlign.right, - textDirection: TextDirection.ltr) - ..layout(minWidth: padding.left - 4) - ..paint(canvas, - Offset(0, yOffset - horizontalLabelsTextStyle.fontSize / 2 - 1)); - } - } - - /* Vertical lines with labels */ - double argumentsOffset = 0; - final double xOffsetLimit = size.width - padding.right; - double horizontalRatio; - - { - Iterable labels; - - // If no labels provided - generate them! - if (argumentsLabels == null) { - throw "not implemented"; - // @TODO . after few hot days of thinking about the problem for 1-2 hour a day, I just gave up. - // The hardest in the problem is that there must be trade-off between space for labels and max lines, - // but keep in mind that the label values should be in some human-readable steps (0.5, 10, 0.02...). - } - // If labels provided - use them - else { - // Set labels iterable as the provided list - labels = argumentsLabels; - - // Use first visible argument as arguments offset - argumentsOffset = argumentsLabels.first.value; - - if (!snapToLeftLabel) { - argumentsOffset = arguments.first; - } - - // Calculate vertical ratio of pixels per value - // Note: `_minimalHorizontalRatio` is calculated in constructor - final double leftMost = snapToLeftLabel - ? math.min(arguments.first, argumentsLabels.first.value) - : arguments.first; - final double rightMost = snapToRightLabel - ? math.max(arguments.last, argumentsLabels.last.value) - : arguments.last; - final double noEmptySpaceRatio = width / (rightMost - leftMost); - horizontalRatio = math.max(_minimalHorizontalRatio, noEmptySpaceRatio); - } - - // Draw the vertical lines and labels - for (LabelEntry tuple in labels) { - if (tuple.value < argumentsOffset) continue; - final double xOffset = - padding.left + (tuple.value - argumentsOffset) * horizontalRatio; - if (xOffset > xOffsetLimit) break; - - // Draw line - if (verticalLinesPaint != null) { - canvas.drawLine( - Offset(xOffset, padding.top), - Offset(xOffset, size.height - padding.bottom), - verticalLinesPaint); - } - - // Draw label - final TextPainter textPainter = TextPainter( - text: TextSpan(text: tuple.label, style: verticalLabelsTextStyle), - textDirection: TextDirection.ltr) - ..layout(); - textPainter.paint( - canvas, - Offset(xOffset - textPainter.width / 2, - size.height - verticalLabelsTextStyle.fontSize - 8)); - } - } - - /* Points and lines between subsequent */ - Iterator> series = values.iterator; - Iterator linesPaints = seriesLinesPaints == null - ? [].iterator - : seriesLinesPaints.iterator; - Iterator pointsPaints = seriesPointsPaints.iterator; - while (series.moveNext()) { - List points = []; - Iterator value = series.current.iterator; - Iterator argument = arguments.iterator; - while (value.moveNext()) { - argument.moveNext(); - if (value.current == null || value.current == double.nan) continue; - - if (argument.current < argumentsOffset) continue; - final double xOffset = padding.left + - (argument.current - argumentsOffset) * horizontalRatio; - if (xOffset > xOffsetLimit) break; - - if (value.current < valuesOffset) continue; - final double yOffset = size.height - - padding.bottom - - (value.current - valuesOffset) * verticalRatio; - if (yOffset < padding.top) continue; - - points.add(Offset(xOffset, yOffset)); - } - - // Lines - if (linesPaints.moveNext() && linesPaints.current != null) { - canvas.drawPath(Path()..addPolygon(points, false), linesPaints.current); - } - - // Points - if (pointsPaints.moveNext() && pointsPaints.current != null) { - canvas.drawPoints(ui.PointMode.points, points, pointsPaints.current); - } - } - } - - @override - bool shouldRepaint(_LineChartPainter old) => - (this.arguments != old.arguments || - this.values != old.values || - this.argumentsLabels != old.argumentsLabels || - this.valuesLabels != old.valuesLabels || - this.seriesPointsPaints != old.seriesPointsPaints || - this.seriesLinesPaints != old.seriesLinesPaints || - this.horizontalLabelsTextStyle != old.horizontalLabelsTextStyle || - this.verticalLabelsTextStyle != old.verticalLabelsTextStyle || - this.padding != old.padding // - ); - - // ..., 0.01, 0.02, 0.05, 0.1, [0.125], 0.2, [0.25], 0.5, 1, 2, 5, 10, 20, 50, 100, 200, 500, ... - double _calculateOptimalStepValue(double valueRange, double height) { - final int maxSteps = height ~/ minimalHorizontalLabelsInterval; - if (maxSteps <= 0) { - throw "invalid max lines!"; - } - double interval = valueRange / maxSteps; - if (interval > 1) { - int zeros = 0; - while (interval >= 10) { - interval = interval / 10; - zeros += 1; - } - /**/ if (interval <= 1) { - interval = 1; - } else if (interval <= 2) { - interval = 2; - } else if (interval <= 5) { - interval = 5; - } - for (; zeros-- != 0;) { - interval *= 10; - } - } else { - // @TODO ! not working at all for lower :C - int zeros = 0; - while (interval < 0) { - interval = interval * 10; - zeros += 1; - } - /**/ if (interval <= 1) { - interval = 1; - } else if (interval <= 2) { - interval = 2; - } else if (interval <= 5) { - interval = 5; - } - for (; zeros-- != 0;) { - interval /= 10; - } - } - return interval; - } - - TextPainter _getLabelTextPainter(String text, TextStyle style) { - return TextPainter( - text: TextSpan(text: text, style: style), - textDirection: TextDirection.ltr) - ..layout(); - } -} diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/PaintStyle.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/PaintStyle.dart deleted file mode 100755 index 179828e..0000000 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/helpers/PaintStyle.dart +++ /dev/null @@ -1,263 +0,0 @@ -import 'dart:ui'; - -/// A description of the style to use when drawing on a [Canvas]. -/// -/// Most APIs on [Canvas] take a [Paint] object to describe the style -/// to use for that operation. [PaintStyle] allows to be const -/// constructed and later in runtime forged into the [Paint] object. -class PaintStyle { - /// Whether to apply anti-aliasing to lines and images drawn on the - /// canvas. - /// - /// Defaults to true. - final bool isAntiAlias; - - // Must be kept in sync with the default in paint.cc. - static const int _kColorDefault = 0xFF000000; - - /// The color to use when stroking or filling a shape. - /// - /// Defaults to opaque black. - /// - /// See also: - /// - /// * [style], which controls whether to stroke or fill (or both). - /// * [colorFilter], which overrides [color]. - /// * [shader], which overrides [color] with more elaborate effects. - /// - /// This color is not used when compositing. To colorize a layer, use - /// [colorFilter]. - final Color color; - - // Must be kept in sync with the default in paint.cc. - static final int _kBlendModeDefault = BlendMode.srcOver.index; - - /// A blend mode to apply when a shape is drawn or a layer is composited. - /// - /// The source colors are from the shape being drawn (e.g. from - /// [Canvas.drawPath]) or layer being composited (the graphics that were drawn - /// between the [Canvas.saveLayer] and [Canvas.restore] calls), after applying - /// the [colorFilter], if any. - /// - /// The destination colors are from the background onto which the shape or - /// layer is being composited. - /// - /// Defaults to [BlendMode.srcOver]. - /// - /// See also: - /// - /// * [Canvas.saveLayer], which uses its [Paint]'s [blendMode] to composite - /// the layer when [restore] is called. - /// * [BlendMode], which discusses the user of [saveLayer] with [blendMode]. - final BlendMode blendMode; - - /// Whether to paint inside shapes, the edges of shapes, or both. - /// - /// Defaults to [PaintingStyle.fill]. - final PaintingStyle style; - - /// How wide to make edges drawn when [style] is set to - /// [PaintingStyle.stroke]. The width is given in logical pixels measured in - /// the direction orthogonal to the direction of the path. - /// - /// Defaults to 0.0, which correspond to a hairline width. - final double strokeWidth; - - /// The kind of finish to place on the end of lines drawn when - /// [style] is set to [PaintingStyle.stroke]. - /// - /// Defaults to [StrokeCap.butt], i.e. no caps. - final StrokeCap strokeCap; - - /// The kind of finish to place on the joins between segments. - /// - /// This applies to paths drawn when [style] is set to [PaintingStyle.stroke], - /// It does not apply to points drawn as lines with [Canvas.drawPoints]. - /// - /// Defaults to [StrokeJoin.miter], i.e. sharp corners. - /// - /// Some examples of joins: - /// - /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4} - /// - /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/round_join.mp4} - /// - /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/bevel_join.mp4} - /// - /// The centers of the line segments are colored in the diagrams above to - /// highlight the joins, but in normal usage the join is the same color as the - /// line. - /// - /// See also: - /// - /// * [strokeMiterLimit] to control when miters are replaced by bevels when - /// this is set to [StrokeJoin.miter]. - /// * [strokeCap] to control what is drawn at the ends of the stroke. - /// * [StrokeJoin] for the definitive list of stroke joins. - final StrokeJoin strokeJoin; - - // Must be kept in sync with the default in paint.cc. - static const double _kStrokeMiterLimitDefault = 4.0; - - /// The limit for miters to be drawn on segments when the join is set to - /// [StrokeJoin.miter] and the [style] is set to [PaintingStyle.stroke]. If - /// this limit is exceeded, then a [StrokeJoin.bevel] join will be drawn - /// instead. This may cause some 'popping' of the corners of a path if the - /// angle between line segments is animated, as seen in the diagrams below. - /// - /// This limit is expressed as a limit on the length of the miter. - /// - /// Defaults to 4.0. Using zero as a limit will cause a [StrokeJoin.bevel] - /// join to be used all the time. - /// - /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_0_join.mp4} - /// - /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_4_join.mp4} - /// - /// {@animation 300 300 https://flutter.github.io/assets-for-api-docs/assets/dart-ui/miter_6_join.mp4} - /// - /// The centers of the line segments are colored in the diagrams above to - /// highlight the joins, but in normal usage the join is the same color as the - /// line. - /// - /// See also: - /// - /// * [strokeJoin] to control the kind of finish to place on the joins - /// between segments. - /// * [strokeCap] to control what is drawn at the ends of the stroke. - final double strokeMiterLimit; - - /// A mask filter (for example, a blur) to apply to a shape after it has been - /// drawn but before it has been composited into the image. - /// - /// See [MaskFilter] for details. - final MaskFilter maskFilter; - - /// Controls the performance vs quality trade-off to use when applying - /// filters, such as [maskFilter], or when drawing images, as with - /// [Canvas.drawImageRect] or [Canvas.drawImageNine]. - /// - /// Defaults to [FilterQuality.none]. - // TODO(ianh): verify that the image drawing methods actually respect this - final FilterQuality filterQuality; - - /// The shader to use when stroking or filling a shape. - /// - /// When this is null, the [color] is used instead. - /// - /// See also: - /// - /// * [Gradient], a shader that paints a color gradient. - /// * [ImageShader], a shader that tiles an [Image]. - /// * [colorFilter], which overrides [shader]. - /// * [color], which is used if [shader] and [colorFilter] are null. - final Shader shader; - - /// A color filter to apply when a shape is drawn or when a layer is - /// composited. - /// - /// See [ColorFilter] for details. - /// - /// When a shape is being drawn, [colorFilter] overrides [color] and [shader]. - final ColorFilter colorFilter; - - /// Whether the colors of the image are inverted when drawn. - /// - /// Inverting the colors of an image applies a new color filter that will - /// be composed with any user provided color filters. This is primarily - /// used for implementing smart invert on iOS. - final bool invertColors; - - const PaintStyle({ - this.isAntiAlias = true, - this.color = const Color(_kColorDefault), - this.blendMode = BlendMode.srcOver, - this.style = PaintingStyle.fill, - this.strokeWidth = 0.0, - this.strokeCap = StrokeCap.butt, - this.strokeJoin = StrokeJoin.miter, - this.strokeMiterLimit = 4.0, - this.maskFilter, // null - this.filterQuality = FilterQuality.none, - this.shader, // null - this.colorFilter, // null - this.invertColors = false, - }); - - @override - String toString() { - final StringBuffer result = StringBuffer(); - String semicolon = ''; - result.write('PaintStyle('); - if (style == PaintingStyle.stroke) { - result.write('$style'); - if (strokeWidth != 0.0) - result.write(' ${strokeWidth.toStringAsFixed(1)}'); - else - result.write(' hairline'); - if (strokeCap != StrokeCap.butt) result.write(' $strokeCap'); - if (strokeJoin == StrokeJoin.miter) { - if (strokeMiterLimit != _kStrokeMiterLimitDefault) - result.write( - ' $strokeJoin up to ${strokeMiterLimit.toStringAsFixed(1)}'); - } else { - result.write(' $strokeJoin'); - } - semicolon = '; '; - } - if (isAntiAlias != true) { - result.write('${semicolon}antialias off'); - semicolon = '; '; - } - if (color != const Color(_kColorDefault)) { - if (color != null) - result.write('$semicolon$color'); - else - result.write('${semicolon}no color'); - semicolon = '; '; - } - if (blendMode.index != _kBlendModeDefault) { - result.write('$semicolon$blendMode'); - semicolon = '; '; - } - if (colorFilter != null) { - result.write('${semicolon}colorFilter: $colorFilter'); - semicolon = '; '; - } - if (maskFilter != null) { - result.write('${semicolon}maskFilter: $maskFilter'); - semicolon = '; '; - } - if (filterQuality != FilterQuality.none) { - result.write('${semicolon}filterQuality: $filterQuality'); - semicolon = '; '; - } - if (shader != null) { - result.write('${semicolon}shader: $shader'); - semicolon = '; '; - } - if (invertColors) result.write('${semicolon}invert: $invertColors'); - result.write(')'); - return result.toString(); - } - - Paint toPaint() { - Paint paint = Paint(); - if (this.isAntiAlias != true) paint.isAntiAlias = this.isAntiAlias; - if (this.color != const Color(_kColorDefault)) paint.color = this.color; - if (this.blendMode != BlendMode.srcOver) paint.blendMode = this.blendMode; - if (this.style != PaintingStyle.fill) paint.style = this.style; - if (this.strokeWidth != 0.0) paint.strokeWidth = this.strokeWidth; - if (this.strokeCap != StrokeCap.butt) paint.strokeCap = this.strokeCap; - if (this.strokeJoin != StrokeJoin.miter) paint.strokeJoin = this.strokeJoin; - if (this.strokeMiterLimit != 4.0) - paint.strokeMiterLimit = this.strokeMiterLimit; - if (this.maskFilter != null) paint.maskFilter = this.maskFilter; - if (this.filterQuality != FilterQuality.none) - paint.filterQuality = this.filterQuality; - if (this.shader != null) paint.shader = this.shader; - if (this.colorFilter != null) paint.colorFilter = this.colorFilter; - if (this.invertColors != false) paint.invertColors = this.invertColors; - return paint; - } -} diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/main.dart b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/main.dart index 72b4904..9d1a1c1 100755 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/main.dart +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/lib/main.dart @@ -1,6 +1,16 @@ -//flutter_bluetooth_serial_example -//https://github.com/edufolly/flutter_bluetooth_serial/tree/master/example +///////////////////////////////////////////////////////////////// +/* + ESP32 | BLUETOOTH CLASSIC | FLUTTER - Let's build BT Serial based on the examples. (Ft. Chat App) + Video Tutorial: https://youtu.be/WUw-_X66dLE + Created by Eric N. (ThatProject) +*/ +// Updated 06-21-2021 +// Due to Flutter's update, many parts have changed from the tutorial video. +// You need to keep @dart=2.9 before starting main to avoid null safety in Flutter 2 +///////////////////////////////////////////////////////////////// + +// @dart=2.9 import 'package:flutter/material.dart'; import './MainPage.dart'; @@ -10,6 +20,6 @@ void main() => runApp(new ExampleApplication()); class ExampleApplication extends StatelessWidget { @override Widget build(BuildContext context) { - return MaterialApp(home: MainPage()); + return MaterialApp(debugShowCheckedModeBanner: false, home: MainPage()); } } diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.lock b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.lock index a5520e2..746e949 100644 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.lock +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.lock @@ -7,35 +7,42 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.6.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" charcode: dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted - version: "1.1.3" + version: "1.2.0" clock: dependency: transitive description: name: clock url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.14.12" + version: "1.15.0" cupertino_icons: dependency: "direct main" description: @@ -49,7 +56,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -73,28 +80,21 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.6" + version: "0.12.10" meta: dependency: transitive description: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "1.3.0" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" - scoped_model: - dependency: "direct main" - description: - name: scoped_model - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.1" + version: "1.8.0" sky_engine: dependency: transitive description: flutter @@ -106,55 +106,55 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.1" stack_trace: dependency: transitive description: name: stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "1.10.0" stream_channel: dependency: transitive description: name: stream_channel url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.5" + version: "1.1.0" term_glyph: dependency: transitive description: name: term_glyph url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.15" + version: "0.3.0" typed_data: dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.3.0" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.0" sdks: - dart: ">=2.7.0 <3.0.0" + dart: ">=2.12.0 <3.0.0" diff --git a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.yaml b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.yaml index 621d6ce..e30569d 100644 --- a/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.yaml +++ b/ESP32_BT_CLASSIC/ESP32_BLUETOOTH_SERIAL_DEMO/android_bluetooth_serial_app/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" dependencies: flutter: @@ -29,7 +29,6 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.3 flutter_bluetooth_serial: ^0.2.2 - scoped_model: ^1.0.1 dev_dependencies: flutter_test: