├── .gitignore
├── .metadata
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── License
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── meshtastic_app
│ │ │ │ └── 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-night
│ │ │ └── styles.xml
│ │ │ └── values
│ │ │ └── styles.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
└── json
│ ├── command_groups.json
│ ├── commands.json
│ └── commands_old.json
├── docs
├── bluetooth_notes.md
└── sequence_diagrams.md
├── 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
├── application
│ ├── connect_device
│ │ ├── connect_device_bloc.dart
│ │ ├── connect_device_bloc.freezed.dart
│ │ ├── connect_device_event.dart
│ │ └── connect_device_state.dart
│ ├── find_device
│ │ ├── find_device_bloc.dart
│ │ ├── find_device_bloc.freezed.dart
│ │ ├── find_device_event.dart
│ │ └── find_device_state.dart
│ ├── setup_device
│ │ ├── setup_device_bloc.dart
│ │ ├── setup_device_bloc.freezed.dart
│ │ ├── setup_device_event.dart
│ │ └── setup_device_state.dart
│ └── simple_bloc_observer.dart
├── domain
│ ├── commands
│ │ ├── command.dart
│ │ ├── command_failure.dart
│ │ └── command_failure.freezed.dart
│ ├── connect_failure.dart
│ ├── connect_failure.freezed.dart
│ ├── core
│ │ ├── errors.dart
│ │ ├── failures.dart
│ │ ├── value_objects.dart
│ │ ├── value_transformers.dart
│ │ └── value_validators.dart
│ ├── device_repo.dart
│ └── value_objects.dart
├── main.dart
├── services
│ ├── bluetooth
│ │ ├── ble_api.dart
│ │ ├── ble_common.dart
│ │ ├── bluetooth.dart
│ │ └── service_uuids_index.dart
│ ├── mesh
│ │ ├── mesh.dart
│ │ ├── mesh_api.dart
│ │ ├── mesh_device.dart
│ │ ├── mesh_node.dart
│ │ └── mesh_preferences.dart
│ └── proto
│ │ ├── admin.options
│ │ ├── admin.pb.dart
│ │ ├── admin.pbenum.dart
│ │ ├── admin.pbjson.dart
│ │ ├── admin.pbserver.dart
│ │ ├── admin.proto
│ │ ├── apponly.pb.dart
│ │ ├── apponly.pbenum.dart
│ │ ├── apponly.pbjson.dart
│ │ ├── apponly.pbserver.dart
│ │ ├── apponly.proto
│ │ ├── channel.pb.dart
│ │ ├── channel.pbenum.dart
│ │ ├── channel.pbjson.dart
│ │ ├── channel.pbserver.dart
│ │ ├── channel.proto
│ │ ├── deviceonly.pb.dart
│ │ ├── deviceonly.pbenum.dart
│ │ ├── deviceonly.pbjson.dart
│ │ ├── deviceonly.pbserver.dart
│ │ ├── deviceonly.proto
│ │ ├── environmental_measurement.pb.dart
│ │ ├── environmental_measurement.pbenum.dart
│ │ ├── environmental_measurement.pbjson.dart
│ │ ├── environmental_measurement.pbserver.dart
│ │ ├── environmental_measurement.proto
│ │ ├── mesh.pb.dart
│ │ ├── mesh.pbenum.dart
│ │ ├── mesh.pbjson.dart
│ │ ├── mesh.pbserver.dart
│ │ ├── mesh.proto
│ │ ├── portnums.pb.dart
│ │ ├── portnums.pbenum.dart
│ │ ├── portnums.pbjson.dart
│ │ ├── portnums.pbserver.dart
│ │ ├── portnums.proto
│ │ ├── proto.dart
│ │ ├── protoc.exe
│ │ ├── radioconfig.pb.dart
│ │ ├── radioconfig.pbenum.dart
│ │ ├── radioconfig.pbjson.dart
│ │ ├── radioconfig.pbserver.dart
│ │ ├── radioconfig.proto
│ │ ├── remote_hardware.pb.dart
│ │ ├── remote_hardware.pbenum.dart
│ │ ├── remote_hardware.pbjson.dart
│ │ ├── remote_hardware.pbserver.dart
│ │ └── remote_hardware.proto
└── ui
│ ├── find_device
│ ├── find_device.dart
│ └── widgets
│ │ └── scan_result.dart
│ ├── menu
│ └── drawer.dart
│ ├── permissions.dart
│ ├── router
│ └── route_generator.dart
│ ├── settings
│ └── log_settings.dart
│ └── setup_device
│ ├── mesh_command.dart
│ ├── mesh_command_list.dart
│ └── widgets
│ ├── command_tiles.dart
│ └── gatt_service.dart
├── pubspec.yaml
├── test
└── widget_test.dart
├── todo_notes.md
└── where
/.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 | **/ios/Flutter/.last_build_id
26 | .dart_tool/
27 | .flutter-plugins
28 | .flutter-plugins-dependencies
29 | .packages
30 | .pub-cache/
31 | .pub/
32 | pubspec.lock
33 | /build/
34 |
35 | # Web related
36 | lib/generated_plugin_registrant.dart
37 |
38 | # Symbolication related
39 | app.*.symbols
40 |
41 | # Obfuscation related
42 | app.*.map.json
43 |
44 | # Android Studio will place build artifacts here
45 | /android/app/debug
46 | /android/app/profile
47 | /android/app/release
48 |
--------------------------------------------------------------------------------
/.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: 2783f8e2e14efec8b7e08f668dde61c40d128c24
8 | channel: dev
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "eriklynd.json-tools"
4 | ]
5 | }
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "meshtastic_app",
9 | "request": "launch",
10 | "type": "dart"
11 | }
12 | ]
13 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "launch": {
3 |
4 | "configurations": [ {
5 | "name": "Dart",
6 | "program": "bin/main.dart",
7 | "request": "launch",
8 | "type": "dart",
9 | "vmAdditionalArgs": [
10 | "--enable-experiment=non-nullable",
11 | ],
12 | }],
13 | "compounds": []
14 | }
15 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Meshtastic-Flutter
2 |
3 | A application to configure and manage Meshtastic devices over BLE.
4 |
5 | ## Getting Started
6 |
7 | Tested on Android only
8 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # include: package:effective_dart/analysis_options.yaml
2 | include: package:pedantic/analysis_options.yaml
3 | # include: package:very_good_analysis/analysis_options.yaml
4 |
5 | analyzer:
6 | exclude:
7 | build/**: true
8 | lib/services/proto/**: true
9 | lib/**/*.freezed.dart: true
10 | errors:
11 | avoid_void_async: error
12 | camel_case_types: error
13 | await_only_futures: error
14 | unawaited_futures: error
15 |
16 | strong-mode:
17 | implicit-casts: false
18 |
19 | linter:
20 | rules:
21 | avoid_void_async: true
22 | camel_case_types: true
23 | await_only_futures: true
24 | unawaited_futures: true
25 | lines_longer_than_80_chars: false
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/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 29
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.example.meshtastic_app"
42 | minSdkVersion 19
43 | targetSdkVersion 29
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | }
47 |
48 | buildTypes {
49 | release {
50 | minifyEnabled false
51 | shrinkResources false
52 | // TODO: Add your own signing config for the release build.
53 | // Signing with the debug keys for now, so `flutter run --release` works.
54 | signingConfig signingConfigs.debug
55 | }
56 | }
57 | }
58 |
59 | flutter {
60 | source '../..'
61 | }
62 |
63 | dependencies {
64 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
65 | }
66 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
13 |
17 |
21 |
26 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/example/meshtastic_app/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.meshtastic_app
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | class MainActivity: FlutterActivity() {
6 | }
7 |
--------------------------------------------------------------------------------
/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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.useAndroidX=true
3 | android.enableJetifier=true
4 | android.enableR8=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 localPropertiesFile = new File(rootProject.projectDir, "local.properties")
4 | def properties = new Properties()
5 |
6 | assert localPropertiesFile.exists()
7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
8 |
9 | def flutterSdkPath = properties.getProperty("flutter.sdk")
10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
12 |
--------------------------------------------------------------------------------
/assets/json/command_groups.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": 201,
4 | "group": "Sleep times",
5 | "command": "long_sleep_mode1",
6 | "commandDescription": "If set, this node will try to join the specified Wifi network and acquire an address via DHCP.",
7 | "params": [
8 | {
9 | "id": "screen_on_secs",
10 | "pValue": "2777",
11 | "pDescription": "Time (s)",
12 | "pDefault": "60",
13 | "pMax": 28800,
14 | "pMin": 60,
15 | "pEdit": "true",
16 | "pVisible": "true"
17 | },
18 | {
19 | "id": "wait_bluetooth_secs",
20 | "pValue": "2888",
21 | "pDescription": "Time (s)",
22 | "pDefault": "60",
23 | "pMax": 28800,
24 | "pMin": 60
25 | },
26 | {
27 | "id": "phone_timeout_secs",
28 | "pValue": "2999",
29 | "pDescription": "Time (s)",
30 | "pDefault": "60",
31 | "pMax": 28800,
32 | "pMin": 60
33 | }
34 | ]
35 | },
36 | {
37 | "id": 201,
38 | "group": "WiFi Setup",
39 | "command": "configure_wifi_station",
40 | "commandDescription": "This configuration gets the node to try to join the specified local Wifi network and acquire an address via DHCP.",
41 | "params": [
42 | {
43 | "id": "wifi_ap_mode",
44 | "pValue": "false",
45 | "pDescription": "If set true, the node will operate as an AP (and DHCP server), otherwise it will join a Wifi network as a station.",
46 | "pDefault": "false",
47 | "pType": "bool",
48 | "pEdit": "false"
49 | },
50 | {
51 | "id": "wifi_ssid",
52 | "pValue": "MyWiFiSSID",
53 | "pDescription": "Wifi SSID string. Used to join named network, or is advertised as AP SSID.",
54 | "pDefault": "",
55 | "pType": "string",
56 | "pEdit": "true",
57 | "pMax": 32
58 | },
59 | {
60 | "id": "wifi_password",
61 | "pValue": "MyWiFiPassword",
62 | "pDescription": "Wifi Password string. Used to join to the named wifi, or required by clients joining this AP.",
63 | "pDefault": "",
64 | "pType": "string",
65 | "pEdit": "true",
66 | "pMax": 63
67 | }
68 | ]
69 | },
70 | {
71 | "id": 202,
72 | "group": "WiFi Setup",
73 | "command": "configure_wifi_access_point",
74 | "commandDescription": "If set, this node will try to join the specified Wifi network and acquire an address via DHCP.",
75 | "params": [
76 | {
77 | "id": "wifi_ap_mode",
78 | "pValue": "true",
79 | "pDescription": "If set true, the node will operate as an AP (and DHCP server), otherwise it will join a Wifi network as a station.",
80 | "pDefault": "false",
81 | "pType": "bool",
82 | "pEdit": "false"
83 | },
84 | {
85 | "id": "wifi_ssid",
86 | "pValue": "",
87 | "pDescription": "Wifi SSID string. Used to join named network, or is advertised as AP SSID.",
88 | "pDefault": "",
89 | "pType": "string",
90 | "pMax": 32
91 | },
92 | {
93 | "id": "wifi_password",
94 | "pValue": "",
95 | "pDescription": "Wifi Password string. Used to join to the named wifi, or required by clients joining this AP.",
96 | "pDefault": "",
97 | "pType": "string",
98 | "pMax": 63
99 | }
100 | ]
101 | },
102 | {
103 | "id": 203,
104 | "group": "WiFi Setup",
105 | "command": "wifi_password",
106 | "commandDescription": "If set, will be use to authenticate to the named wifi .",
107 | "params": [
108 | {
109 | "id": "wifi_password",
110 | "pValue": "",
111 | "pDescription": "Wifi Password string",
112 | "pDefault": "",
113 | "pType": "string",
114 | "pMax": 63
115 | }
116 | ]
117 | },
118 | {
119 | "id": 204,
120 | "group": "WiFi Setup",
121 | "command": "disable_wifi",
122 | "commandDescription": " If set true, the node will operate as an AP (and DHCP server), otherwise it will be a station.",
123 | "params": [
124 | {
125 | "id": "wifi_ap_mode",
126 | "pValue": "false",
127 | "pDescription": "true/false",
128 | "pDefault": "false",
129 | "pType": "bool",
130 | "pEdit": "false"
131 | }
132 | ]
133 | }
134 | ]
--------------------------------------------------------------------------------
/docs/bluetooth_notes.md:
--------------------------------------------------------------------------------
1 | Disable/enable bluetooth on phone
2 |
3 | Restart phone
4 |
5 | Check with basic flutter_blue example
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## These lines repeating frequently, after device firmware upgrade
13 | https://github.com/NordicSemiconductor/Android-BLE-Library/issues/17
14 |
15 | D/BluetoothGatt(16240): onConnectionUpdated() - Device=C4:4F:33:6A:AC:47 interval=6 latency=0 timeout=500 status=0
16 | D/BluetoothGatt(16240): onConnectionUpdated() - Device=C4:4F:33:6A:AC:47 interval=39 latency=0 timeout=500 status=0
17 | D/BluetoothGatt(16240): onConnectionUpdated() - Device=C4:4F:33:6A:AC:47 interval=6 latency=0 timeout=500 status=0
18 | D/BluetoothGatt(16240): onConnectionUpdated() - Device=C4:4F:33:6A:AC:47 interval=39 latency=0 timeout=500 status=0
19 |
20 |
21 | onConnectionUpdated with interval 6 means that Android does service discovery. To make it as quick as possible, it switches the connection interval to lowest possible value. 6 means 7.5ms.
22 | When you don't get it, it means that services were obtained from the cache and no service discovery we performed.
23 |
24 | Tried
25 | - close Nordic, Meshtastic BLE apps,
26 | - unpair, re-pair device
27 |
28 |
29 |
30 | ## Build for release needs special setting:
31 | https://github.com/pauldemarco/flutter_blue/issues/662#issuecomment-741710564
32 |
33 | Fixed this issue on release build by disabling shrink resources and minifyEnabled at android/app/build.gradle
34 | But It's strange as It's disabling ProGuard. So what about android apk file source securities.
35 | So It must need a proactive solution for the same for It should work with ProGuard enable.
36 |
37 | flutter build apk --no-shrink
38 | worked for me.
39 |
40 |
41 | ## Sleep etc
42 | On wake we see
43 | D/FlutterBluePlugin(29790): [onConnectionStateChange] status: 0 newState: 2
44 | On device sleep (or BLE sleep)
45 | D/FlutterBluePlugin(19981): [onConnectionStateChange] status: 19 newState: 0
46 |
47 | https://stackoverflow.com/questions/45056566/android-ble-gatt-connection-change-statuses
48 | Programmatically disconnected - 0
49 | Device went out of range - 8
50 | Disconnected by device - 19
51 | Issue with bond - 22
52 | Device not found - 133(some phone it gives 62)
53 |
54 |
--------------------------------------------------------------------------------
/docs/sequence_diagrams.md:
--------------------------------------------------------------------------------
1 | see https://mermaid-js.github.io/mermaid/diagrams-and-syntax-and-examples/sequenceDiagram.html
2 | ````mermaid
3 | sequenceDiagram
4 | participant P as Page
5 | participant B as BLoc
6 | participant R as Repository
7 | participant S as Service
8 | Note over P: Initial
9 | P->>B: InitialiseRequest
10 | B->>R: Intialising
11 | Note over B: Intialising
12 | B-xP: Intialising
13 |
14 | alt Known device?
15 | R->>S: Connect device
16 | S-xR: Service List?
17 |
18 | else
19 | R->>S: StartScan
20 | S-xR: DeviceList
21 | R-xB: DeviceList
22 | B-xP: DeviceList
23 | end
24 |
25 | Note over P: Requested
26 | Note over P: Connected
27 | Note over P: NoDevice
28 | Note over P: KnownDevice
29 | Note over P: Initial
30 | Note over B: List
31 | Note over B: NoDevices
32 |
33 | Note over B: Selected
34 | ````
--------------------------------------------------------------------------------
/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 | 9.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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qurm/meshtastic-flutter/c294a86f6a6621721fd2ea80fb94c5e55c2ee478/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 | meshtastic_app
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"
2 |
--------------------------------------------------------------------------------
/lib/application/connect_device/connect_device_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:bloc/bloc.dart';
4 | import 'package:flutter/foundation.dart';
5 | import 'package:freezed_annotation/freezed_annotation.dart';
6 | // import 'package:injectable/injectable.dart';
7 | import 'package:meshtastic_app/services/bluetooth/ble_common.dart';
8 | // import 'package:meshtastic_app/bloc/find_device/bloc/find_device_bloc.dart';
9 | import 'package:meta/meta.dart';
10 | import 'package:get_it/get_it.dart';
11 |
12 | import '../../domain/connect_failure.dart';
13 | import '../../domain/device_repo.dart';
14 | import '../../services/bluetooth/ble_api.dart';
15 | import '../../services/mesh/mesh.dart';
16 |
17 | part 'connect_device_bloc.freezed.dart';
18 | part 'connect_device_event.dart';
19 | part 'connect_device_state.dart';
20 |
21 | // run this at terminal after changes to generate freezed code:
22 | // flutter pub run build_runner watch --delete-conflicting-outputs
23 | // also try:
24 | // flutter pub get && flutter pub run build_runner build --delete-conflicting-outputs
25 |
26 | /// ConnectDevice Bloc
27 | /// Purpose of this bloc is to manage BLE connection to the selected device
28 | /// chosen in [FindDeviceBloc] and providing connection state globally.
29 | /// See [setup_device] bloc for already connected device
30 | /// Application logic, and deals with UI and domain layers
31 | /// incoming events are transformed, yielded as States
32 | /// use of timer: https://stackoverflow.com/questions/61891062/flutter-bloc-using-timer-to-refetch-data
33 |
34 | class ConnectDeviceBloc extends Bloc {
35 | ConnectDeviceBloc() : super(const ConnectDeviceState.initial());
36 |
37 | /// BLE device repository
38 | DeviceConnect connectRepo = GetIt.I();
39 | StreamSubscription? _deviceSubscription;
40 | // StreamSubscription _periodicSubscription;
41 | List connectedDevices = [];
42 |
43 | // ConnectDeviceBloc(this.connectRepo)
44 | // : assert(connectRepo != null),
45 | // super(ConnectDeviceState.initial())
46 |
47 | // @override nothing to override here
48 | ConnectDeviceState get initialState => const ConnectDeviceState.initial();
49 |
50 | @override
51 | Stream mapEventToState(
52 | ConnectDeviceEvent event,
53 | ) async* {
54 | if (event is ConnectPressedEvent) {
55 | yield const ConnectingState();
56 | try {
57 | // final connectedDevices = await connectRepo.connectedDevices3;
58 | await event.device.connect();
59 | yield ConnectedState(event.device);
60 | add(const ConnectCompletedEvent());
61 | //then the UI can refresh to show the connected device(s)
62 |
63 | // on BLE device change state, raise a ConnectStateChanged event in this bloc
64 | // BLEDeviceState { disconnected, connecting, connected, disconnecting }
65 | _deviceSubscription = event.device.deviceState.listen((status) {
66 | //call back action:
67 | add(ConnectStateChangedEvent(status));
68 | });
69 | } catch (e) {
70 | rethrow;
71 | //handle Failures from the repo - i.e. BLE off, no location services etc?
72 | }
73 | }
74 |
75 | if (event is ConnectCompletedEvent) {
76 | try {
77 | //anything to do? }
78 | } catch (e) {
79 | //handle Failures from the repo - i.e. BLE off, no location services etc?
80 | rethrow;
81 | }
82 | }
83 |
84 | if (event is ConnectStateChangedEvent) {
85 | // yield Requested();
86 | // / BLEDeviceState { disconnected, connecting, connected, disconnecting }
87 | try {
88 | switch (event.deviceState) {
89 | case BLEDeviceState.disconnecting:
90 | yield const DeviceOfflineState();
91 | break;
92 | case BLEDeviceState.disconnected:
93 | yield const DeviceOfflineState();
94 | break;
95 | case BLEDeviceState.connecting:
96 | //what to od here
97 | // yield DeviceOffline();
98 | break;
99 | //resume after brief interruption, or...
100 | case BLEDeviceState.connected:
101 | // yield Connected(event.device);
102 | yield const DeviceOnlineState();
103 | break;
104 | }
105 | } catch (e) {
106 | //handle Failures from the repo - i.e. BLE off, no location services etc?
107 | rethrow;
108 | }
109 | }
110 | }
111 |
112 | @override
113 | Future close() {
114 | _deviceSubscription?.cancel();
115 | return super.close();
116 | }
117 | }
118 | // TODO: implement mapEventToState
119 | /// use Task() from dartz to wrap around Future>
120 | // see pattern at https://resocoder.com/2019/12/14/functional-error-handling-in-flutter-dart-2-either-task-fp/
121 |
122 | /// This below is the ResoCoder pattern - very abstract
123 | // yield* event.map(
124 | // // AF scan not important now, as can depend on already paired devices for Mesht
125 | // scan: (e) async* {
126 | // // converts the Future into a Task
127 | // final userOption = await Task(() => connectRepo.scan())
128 | // // execute function above, catches exceptions into Left
129 | // .attempt()
130 | // // results in a Either
131 | // .map(
132 | // // AF: do we need all of this, as connect is Either:
133 | // // Grab only the *left* side of Either