From 88592304b499381f75d01899fd8c228f98798cb3 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:38:23 +0500 Subject: [PATCH 01/12] docs: update app information --- README.md | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6af107b..9b4ca38 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ -# remo_tooth +# Remo Tooth + +**An application to remotely control arduino devices via bluetooth technology.** + +- **Version:** *0.3a* (in-progress) +- **Development Stage:** alpha + + +## How it works? + +**It scans for nearby beacon devices to establish connection. Then it sends on/off signals to the connected device to perform operations.** + +## Development Branches: +- **development** (in-progress) + +## Development Progress: +![Progress](https://progress-bar.dev/80/?title=progress) + +## Task-List: +- [x] UI Rework +- [x] UI Responsiveness +- [ ] Unit Testing +- [ ] Integration Testing +- [ ] Regression Testing +- [ ] Refactoring + +## Dependencies: +- firebase_core: 2.4.1 +- firebase_auth: 4.2.5 +- google_sign_in: 5.4.3 +- flutter_bloc: 8.1.1 +- bloc: 8.1.0 +- equatable: 2.0.5 +- flutter_bluetooth_serial: 0.4.0 +- connectivity_plus: 3.0.2 +- lottie: 2.2.0 + + + -Under Development. From 0d8ac2e604ace3f6d508b38d1ea3fee977fec17a Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:41:18 +0500 Subject: [PATCH 02/12] chore: remove unused dependencies --- pubspec.lock | 44 ++++++++++++++++++++++++++++++++++++-------- pubspec.yaml | 3 ++- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index b5b61e8..7366556 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -8,6 +8,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.12" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.5" args: dependency: transitive description: @@ -71,6 +78,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.3" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" cupertino_icons: dependency: "direct main" description: @@ -184,13 +205,6 @@ packages: description: flutter source: sdk version: "0.0.0" - font_awesome_flutter: - dependency: "direct main" - description: - name: font_awesome_flutter - url: "https://pub.dartlang.org" - source: hosted - version: "10.3.0" google_sign_in: dependency: "direct main" description: @@ -254,6 +268,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + lottie: + dependency: "direct main" + description: + name: lottie + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" matcher: dependency: transitive description: @@ -310,6 +331,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.3" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.2" provider: dependency: transitive description: @@ -394,4 +422,4 @@ packages: version: "6.1.0" sdks: dart: ">=2.18.6 <3.0.0" - flutter: ">=2.11.0" + flutter: ">=3.3.0" diff --git a/pubspec.yaml b/pubspec.yaml index 293e5d0..2affe66 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -42,9 +42,9 @@ dependencies: bloc: ^8.1.0 equatable: ^2.0.5 google_sign_in: ^5.4.3 - font_awesome_flutter: ^10.3.0 flutter_bluetooth_serial: ^0.4.0 connectivity_plus: ^3.0.2 + lottie: ^2.2.0 dev_dependencies: flutter_test: @@ -71,6 +71,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - assets/animations/ # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see From 5f9a0938e19e5c97fc46e0f35cb50051f25f6f06 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:42:18 +0500 Subject: [PATCH 03/12] change `adb connection` sleep timeout to 200 --- wiConnect.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wiConnect.sh b/wiConnect.sh index a3db43c..74687d3 100644 --- a/wiConnect.sh +++ b/wiConnect.sh @@ -1,3 +1,3 @@ adb tcpip 5555 adb connect 192.168.18.5:5555 -Sleep 2000 +Sleep 200 From e14b124997de42d131edc552b7dbcd34dddbab3f Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:42:52 +0500 Subject: [PATCH 04/12] add scan animation --- assets/animations/radar.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 assets/animations/radar.json diff --git a/assets/animations/radar.json b/assets/animations/radar.json new file mode 100644 index 0000000..fbbfeb6 --- /dev/null +++ b/assets/animations/radar.json @@ -0,0 +1 @@ +{"nm":"RadarAll","mn":"","layers":[{"ty":0,"nm":"target07","mn":"","sr":1,"st":26,"op":98,"ip":26,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[150,150,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[400,589,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":26},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":27},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":36},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":62}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":200,"h":200,"refId":"comp_112","ind":1},{"ty":0,"nm":"target06","mn":"","sr":1,"st":24,"op":96,"ip":24,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[150,150,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[484,789,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":24},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":25},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":34},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":60}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":200,"h":200,"refId":"comp_112","ind":2},{"ty":0,"nm":"target05","mn":"","sr":1,"st":19,"op":91,"ip":19,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[150,150,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[456,1185,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":19},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":20},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":29},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":55}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":200,"h":200,"refId":"comp_112","ind":3},{"ty":0,"nm":"target04","mn":"","sr":1,"st":11,"op":83,"ip":11,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[150,150,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[1038,1167,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":11},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":12},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":21},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":47}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":200,"h":200,"refId":"comp_112","ind":4},{"ty":0,"nm":"target03","mn":"","sr":1,"st":6,"op":78,"ip":6,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[150,150,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[1364,933,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":6},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":7},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":16},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":42}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":200,"h":200,"refId":"comp_112","ind":5},{"ty":0,"nm":"target02","mn":"","sr":1,"st":1,"op":73,"ip":1,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[150,150,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[1126,615,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":1},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":2},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":11},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":37}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":200,"h":200,"refId":"comp_112","ind":6},{"ty":0,"nm":"target01","mn":"","sr":1,"st":0,"op":72,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[100,100,0],"ix":1},"s":{"a":0,"k":[150,150,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[1176,455,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":1},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":10},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":36}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":200,"h":200,"refId":"comp_112","ind":7},{"ty":0,"nm":"RadarComp","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[825,825,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[850,850,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[40],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[400],"t":36},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[720],"t":72}],"ix":10}},"ef":[],"w":1650,"h":1650,"refId":"comp_113","ind":8},{"ty":4,"nm":"BgColor","mn":"","sr":1,"st":0,"op":36,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[833.406,833.406,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"rc","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Rect","nm":"Rectangle Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"s":{"a":0,"k":[1733.188,1733.188],"ix":2}},{"ty":"st","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"d":[],"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.1098,0.1059,0.1216],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[16.594,16.594],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":9}],"ddd":0,"h":1700,"w":1700,"meta":{"a":"","k":"","d":"","g":"@lottiefiles/toolkit-js 0.21.3","tc":"#000000"},"v":"5.1.8","fr":24,"op":36,"ip":0,"assets":[{"nm":"","mn":"","layers":[{"ty":4,"nm":"main","mn":"","sr":1,"st":0,"op":77,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[9,-0.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[99.679,100.179,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":60,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[50,50],"ix":2}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.1922,0.9804,1],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[9.321,-0.679],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"grow","mn":"","sr":1,"st":0,"op":76,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[9,-0.5,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.145,"y":0.062},"i":{"x":0.695,"y":1},"s":[100,100,100],"t":0},{"o":{"x":0.167,"y":0},"i":{"x":0.695,"y":1},"s":[364.975,364.975,100],"t":11},{"o":{"x":0.167,"y":0},"i":{"x":0.667,"y":1},"s":[100,100,100],"t":12},{"o":{"x":0.167,"y":0},"i":{"x":0.695,"y":1},"s":[365,365,100],"t":23},{"o":{"x":0.167,"y":0},"i":{"x":0.667,"y":1},"s":[100,100,100],"t":24},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[365,365,100],"t":35}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[99.679,100.179,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[70],"t":5},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":12},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[70],"t":17},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":24},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[70],"t":29},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":36}],"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":2,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[50,50],"ix":2}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0,0.9608,1],"ix":4},"r":1,"o":{"a":0,"k":47,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[9.321,-0.679],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2}],"id":"comp_112","fr":30},{"nm":"","mn":"","layers":[{"ty":4,"nm":"Shape Layer 1","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[831.938,831.938,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[80.125,80.125],"ix":2}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.3882,0.8275,0.8],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-6.938,-6.938],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":0,"nm":"RadarLight1/4","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[825,825,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[825,825,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"w":1650,"h":1650,"refId":"comp_114","ind":2},{"ty":4,"nm":"InLine 2","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,827.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[433,433],"ix":2}},{"ty":"st","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13,"ix":5},"d":[],"c":{"a":0,"k":[0.1333,0.5294,0.5804],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-2.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"MiddleLine\r 2","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,827.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[1038,1038],"ix":2}},{"ty":"st","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":13,"ix":5},"d":[],"c":{"a":0,"k":[0.1333,0.5294,0.5804],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-2.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"OutLine 2","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,828.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[1635,1635],"ix":2}},{"ty":"st","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":15,"ix":5},"d":[],"c":{"a":0,"k":[0.1333,0.5294,0.5804],"ix":3}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-3.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5}],"id":"comp_113","fr":30},{"nm":"","mn":"","layers":[{"ty":0,"nm":"RadarLightAll","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[825,825,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[825,825,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"masksProperties":[{"nm":"Mask 1","mn":"","inv":false,"mode":"a","x":{"a":0,"k":0,"ix":4},"o":{"a":0,"k":100,"ix":3},"pt":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[827,0],[0,0],[0,827],[827,827]]},"ix":1}}],"w":1650,"h":1650,"refId":"comp_115","ind":1}],"id":"comp_114","fr":30},{"nm":"","mn":"","layers":[{"ty":4,"nm":"StarLine","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.717,828,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"rc","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Rect","nm":"Rectangle Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"s":{"a":0,"k":[12,825],"ix":2}},{"ty":"st","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"d":[],"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.3882,0.8275,0.8],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-6.717,-412.5],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":0,"nm":"InLineLight","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[825,825,0],"ix":1},"s":{"a":0,"k":[25.5,25.5,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[825,825,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"masksProperties":[{"nm":"Mask 1","mn":"","inv":false,"mode":"a","x":{"a":0,"k":0,"ix":4},"o":{"a":0,"k":100,"ix":3},"pt":{"a":0,"k":{"c":true,"i":[[455.682,0],[0,-455.682],[-455.682,0],[0,455.682]],"o":[[-455.682,0],[0,455.682],[455.682,0],[0,-455.682]],"v":[[825.086,0],[0,825.086],[825.086,1650.172],[1650.172,825.086]]},"ix":1}}],"w":1650,"h":1650,"refId":"comp_116","ind":2},{"ty":4,"nm":"InLineF","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,828.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[420,420],"ix":2}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.1765,0.4392,0.5255],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-3.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"InLineG","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,828.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[445,445],"ix":2}},{"ty":"gf","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[63.469,-308.094],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.216,0.13333333333333333,0.5294117647058824,0.5803921568627451,0.369,0.2627450980392157,0.6784313725490196,0.6901960784313725,0.638,0.38823529411764707,0.8274509803921568,0.8],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-189.914,-13.922],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-3.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":0,"nm":"MiddleLineLight ","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[825,825,0],"ix":1},"s":{"a":0,"k":[62.1,62.1,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[825,825,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"masksProperties":[{"nm":"Mask 1","mn":"","inv":false,"mode":"a","x":{"a":0,"k":0,"ix":4},"o":{"a":0,"k":100,"ix":3},"pt":{"a":0,"k":{"c":true,"i":[[455.682,0],[0,-455.682],[-455.682,0],[0,455.682]],"o":[[-455.682,0],[0,455.682],[455.682,0],[0,-455.682]],"v":[[825.086,0],[0,825.086],[825.086,1650.172],[1650.172,825.086]]},"ix":1}}],"w":1650,"h":1650,"refId":"comp_116","ind":5},{"ty":4,"nm":"MiddleLineF","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,828.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[1025,1025],"ix":2}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.1765,0.4392,0.5255],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-3.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6},{"ty":4,"nm":"MiddleLineG","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,828.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[1050,1050],"ix":2}},{"ty":"gf","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[11.562,-547.344],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.216,0.13333333333333333,0.5294117647058824,0.5803921568627451,0.369,0.2627450980392157,0.6784313725490196,0.6901960784313725,0.638,0.38823529411764707,0.8274509803921568,0.8],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-509.805,-0.148],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-3.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":7},{"ty":0,"nm":"OutLineLight","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[825,825,0],"ix":1},"s":{"a":0,"k":[98.4,98.4,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[825,824,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"masksProperties":[{"nm":"Mask 1","mn":"","inv":false,"mode":"a","x":{"a":0,"k":0,"ix":4},"o":{"a":0,"k":100,"ix":3},"pt":{"a":0,"k":{"c":true,"i":[[455.682,0],[0,-455.682],[-455.682,0],[0,455.682]],"o":[[-455.682,0],[0,455.682],[455.682,0],[0,-455.682]],"v":[[825.086,0],[0,825.086],[825.086,1650.172],[1650.172,825.086]]},"ix":1}}],"w":1650,"h":1650,"refId":"comp_116","ind":8},{"ty":4,"nm":"OutLineF","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,828.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[1622,1622],"ix":2}},{"ty":"fl","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[0.1765,0.4392,0.5255],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-3.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":9},{"ty":4,"nm":"OutLineG","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[827.832,828.832,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[1650,1650],"ix":2}},{"ty":"gf","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[532.828,-978.891],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.216,0.13333333333333333,0.5294117647058824,0.5803921568627451,0.369,0.2627450980392157,0.6784313725490196,0.6901960784313725,0.638,0.38823529411764707,0.8274509803921568,0.8],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-758.828,139.859],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-2.832,-3.832],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":10}],"id":"comp_115","fr":30},{"nm":"","mn":"","layers":[{"ty":4,"nm":"Light 2","mn":"","sr":1,"st":0,"op":144,"ip":0,"hd":false,"cl":"","ln":"","ddd":0,"bm":0,"hasMask":true,"ao":0,"ks":{"a":{"a":0,"k":[25.258,2,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[825,826.742,0],"ix":2},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10}},"ef":[],"masksProperties":[{"nm":"Mask 1","mn":"","inv":false,"mode":"a","x":{"a":0,"k":0,"ix":4},"o":{"a":0,"k":100,"ix":3},"pt":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[25.258,-832.742],[-799.742,-832.742],[-799.742,-7.742],[25.258,-7.742]]},"ix":1}}],"shapes":[{"ty":"gr","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[1650,1650],"ix":2}},{"ty":"st","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":0,"ix":5},"d":[],"c":{"a":0,"k":[1,1,1],"ix":3}},{"ty":"gf","bm":0,"cl":"","ln":"","hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[678.461,-2192.312],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.216,0.17647058823529413,0.4392156862745098,0.5254901960784314,0.369,0.2823529411764706,0.6313725490196078,0.6627450980392157,0.638,0.38823529411764707,0.8274509803921568,0.8],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-861.141,162.508],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[25.258,0.258],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}],"id":"comp_116","fr":30}]} \ No newline at end of file From 8115125be1be60a1748f299a1101b4e471ef6705 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:43:10 +0500 Subject: [PATCH 05/12] add google logo icon --- assets/images/google_logo.png | Bin 0 -> 957 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 assets/images/google_logo.png diff --git a/assets/images/google_logo.png b/assets/images/google_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..eaeefc9493ebfd0a9b10274ae576b177bbbb0615 GIT binary patch literal 957 zcmV;u148_XP)P000>X1^@s6#OZ}&00009a7bBm000XU z000XU0RWnu7ytkO0drDELIAGL9O(c600d`2O+f$vv5yP3^ituI&_jqsSVpKX z6`{L|MCMPK6eWa8xfoRb*Xr)fz1>-JT6br4Q$Luwch0%zesk_Q_Z)-((35B}n^1~X zkZvS^5eOgyf%g-N^V2F@XV+}@IFoWPDK0@qR)7e583Rdw2kd1EyW<3*W_82szJN*W zdt;*{16J_O6ChAH}FyITAE&-3pOYV0Y1GE#Q!9dAohV&2uhE5TLTibK= zY&8-|q(#6m+GlfwcS!MaxUIF(TQ|tFPDbGhUlZkzK!rOdj%N_wdE)>j8e#ESB zSwqJVEC7(%AV{X7!&Atdd*Z4SKky^kqRzi6A&@(=3qC96jJH`;PvAe0Tr$eDk!YvDS$l0)jceU0 zOaW@t@%hARI5(64J&FkgRBl_!(*mwx$t7dio&;{M0UFfNO`gGm9>vL-jy&R$cmUY~izdo_ZtvOW=Z)ys2gKc{p)} zfzh4^D2Hk!3M%o9`AeFnk*J8PI%Q#u*8r{DPZ4-RU#3?7pdV*I8rjE#Obe~oOxHav zz?X=sjVH=KiN~RM$)%rZMXxTNE%0Zd!BUwPEuwIX_w97wjhN2dJsUzKm)bHP--j7~ z3v|3X%qY9SFWO1{6{vQ^@4Ts%$>VZqM^4R<{;B|=-hT72aSsr-6)1)=WaETFpFn7P f^Xcl3v)TUv>mof@thc|800000NkvXXu0mjfSaq!N literal 0 HcmV?d00001 From 57248f855afe92d9e4c57e1b47a2ca0e4646e8b7 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:44:21 +0500 Subject: [PATCH 06/12] major `UI` rework and refactoring --- lib/config/app_colors.dart | 33 ++++++++ lib/config/app_routes.dart | 3 +- lib/config/app_strings.dart | 18 ++--- lib/main.dart | 10 ++- lib/theme/theme.dart | 149 ++++++++++++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 14 deletions(-) create mode 100644 lib/config/app_colors.dart create mode 100644 lib/theme/theme.dart diff --git a/lib/config/app_colors.dart b/lib/config/app_colors.dart new file mode 100644 index 0000000..1e3e85c --- /dev/null +++ b/lib/config/app_colors.dart @@ -0,0 +1,33 @@ +// ignore_for_file: constant_identifier_names + +import 'package:flutter/rendering.dart'; + +class AppColors { + AppColors._(); + + /// Widget colors.... + static const Color PRIMARY_COLOR = Color(0xFFD4C5F6); + static const Color SCAFFOLD_COLOR = Color(0xFF1C1B1F); + static const Color PROGRESS_INDICATOR_COLOR = Color(0xFFD0BCFF); + static const Color APP_BAR_COLOR = Color(0xFF2A2831); + static const Color ELEVATED_BUTTON_COLOR = Color(0xFFBEA9EE); + static const Color SNACKBAR_COLOR = Color(0xFF313033); + static const Color FLOATING_BUTTON_COLOR = Color(0xFF313034); + static const Color BOTTOM_SHEET_COLOR = Color(0xFF1C1B1F); + static const Color CARD_COLOR = Color(0xFF25232A); + static const Color CARD_BORDER_COLOR = Color(0xFF49454F); + static const Color LIST_TILE_COLOR = Color(0xFF25232A); + + /// Text Colors.... + + static const Color APP_BAR_TEXT_COLOR = Color(0xFFE2D9F8); + static const Color DISPLAY_MEDIUM_COLOR = Color(0xFFAC8EF0); + // static const Color DISPLAY_MEDIUM_COLOR = Color(0xFF63D3CC); + static const Color TITLE_SMALL_COLOR = Color(0xFFE6E1E5); + static const Color TITLE_MEDIUM_COLOR = Color(0xFFE2D9F8); + static const Color LABEL_SMALL_COLOR = Color(0xFF7A7A7A); + static const Color LABEL_MEDIUM_COLOR = Color(0xFFB7B7B7); + static const Color LABEL_LARGE_COLOR = Color(0xFFE6E1E5); + static const Color ELEVATED_BUTTON_TEXT_COLOR = Color(0xFF381E72); + static const Color SNACKBAR_CONTENT_COLOR = Color(0xFFF4EFF4); +} diff --git a/lib/config/app_routes.dart b/lib/config/app_routes.dart index 07a4bf0..7694ef8 100644 --- a/lib/config/app_routes.dart +++ b/lib/config/app_routes.dart @@ -3,6 +3,7 @@ class AppRoute { AppRoute._(); - static const String SIGN_UP = '/'; + static const String SIGN_IN = '/'; static const String HOME = '/home'; + static const String REMOTE = '/remote'; } diff --git a/lib/config/app_strings.dart b/lib/config/app_strings.dart index 8909a5b..e31fd80 100644 --- a/lib/config/app_strings.dart +++ b/lib/config/app_strings.dart @@ -6,16 +6,16 @@ class AppString { static const String APP_NAME = 'Remo Tooth'; static const String APP_VERSION = 'v0.1a'; - static const String LOGO = 'assets/images/logo.jpg'; + static const String APP_DESCRIPTION = 'Arduino board remote control'; + static const String GOOGLE_LOGO_IMAGE = 'assets/images/google_logo.png'; static const String SUSPEND_MSG = 'Your account has been suspended.'; - static const String ON_SCAN_MSG = 'Scanning for nearby devices . . .'; - static const String INTERNET_MSG = 'No Internet Connection!'; - static const String BLUE_TOOTH_SERVICE_MSG = 'Bluetooth service is off.'; - static const String DESCRIPTION = - 'An app to remotely connect to an arduino device via bluetooth.'; - static const String DEVICES_NOT_FOUND = + static const String DISCOVERING_MSG = 'Discovering nearby devices . . .'; + static const String NO_INTERNET_MSG = 'No Internet Connection!'; + static const String DISABLED_BLUETOOTH_MSG = 'Bluetooth service is off.'; + static const String UNDISCOVERED_DEVICES_MSG = 'No nearby device(s) available. Try Again!'; static const String DEVELOPER = 'IT & Robotics Engineering Team'; - - static const String GOOGLE_SIGN_IN_BTN = 'Sign in with Google'; + static const String GOOGLE_LABEL_BUTTON = 'Sign in with Google'; + static const String COPYRIGHT = + '(c) Copyright 2023 CUSIT IT & Robotics Engineering. All rights reserved.'; } diff --git a/lib/main.dart b/lib/main.dart index 46e2076..d6d3320 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,10 +8,11 @@ import 'dart:io' show Platform; import 'package:flutter/material.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:remo_tooth/firebase_options.dart'; +import 'package:remo_tooth/theme/theme.dart'; +import 'config/app_routes.dart'; import 'config/app_strings.dart'; -import '../config/route_generator.dart'; -import '../config/app_routes.dart'; +import 'config/route_generator.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -28,11 +29,12 @@ class RemoToothApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp( + return MaterialApp( title: AppString.APP_NAME, - initialRoute: AppRoute.SIGN_UP, + initialRoute: AppRoute.SIGN_IN, onGenerateRoute: RouteGenerator.generate, debugShowCheckedModeBanner: false, + theme: AppTheme.darkTheme(), ); } } diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart new file mode 100644 index 0000000..66d96aa --- /dev/null +++ b/lib/theme/theme.dart @@ -0,0 +1,149 @@ +import 'package:flutter/material.dart'; + +import '../config/app_colors.dart'; + +class AppTheme { + AppTheme._(); + + static ThemeData darkTheme() { + return ThemeData.dark(useMaterial3: true).copyWith( + primaryColor: AppColors.PRIMARY_COLOR, + + /** + * Scaffold theme... + */ + scaffoldBackgroundColor: AppColors.SCAFFOLD_COLOR, + + /** + * AppBar theme... + */ + appBarTheme: const AppBarTheme( + backgroundColor: AppColors.APP_BAR_COLOR, + titleTextStyle: TextStyle( + color: AppColors.APP_BAR_TEXT_COLOR, + fontWeight: FontWeight.w600, + fontSize: 24, + ), + ), + + /** + * Popup menu theme + */ + popupMenuTheme: const PopupMenuThemeData( + color: Color(0xFFE2D9F8), + ), + + /** + * Bottom Sheet theme data... + */ + bottomSheetTheme: const BottomSheetThemeData( + backgroundColor: AppColors.BOTTOM_SHEET_COLOR, + ), + + /** + * Progress Indicator theme... + */ + progressIndicatorTheme: const ProgressIndicatorThemeData( + color: AppColors.PROGRESS_INDICATOR_COLOR, + ), + + /** + * Card theme... + */ + cardTheme: CardTheme( + color: AppColors.CARD_COLOR, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + side: const BorderSide( + color: AppColors.CARD_BORDER_COLOR, + style: BorderStyle.solid, + width: 0.5, + ), + ), + ), + listTileTheme: const ListTileThemeData( + dense: true, + tileColor: AppColors.LIST_TILE_COLOR, + ), + + /** + * Elevated button theme.... + */ + elevatedButtonTheme: ElevatedButtonThemeData( + style: ButtonStyle( + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + ), + backgroundColor: MaterialStateProperty.all( + AppColors.ELEVATED_BUTTON_COLOR, + ), + foregroundColor: MaterialStateProperty.all( + AppColors.ELEVATED_BUTTON_TEXT_COLOR, + ), + ), + ), + + /** + * SnackBar theme... + */ + snackBarTheme: SnackBarThemeData( + backgroundColor: AppColors.SNACKBAR_COLOR, + contentTextStyle: const TextStyle( + color: AppColors.SNACKBAR_CONTENT_COLOR, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + ), + + /** + * Text Theme... + */ + textTheme: const TextTheme( + displayMedium: TextStyle( + color: AppColors.DISPLAY_MEDIUM_COLOR, + fontWeight: FontWeight.bold, + ), + titleSmall: TextStyle( + color: AppColors.TITLE_SMALL_COLOR, + fontWeight: FontWeight.w300, + ), + titleMedium: TextStyle( + color: AppColors.TITLE_MEDIUM_COLOR, + fontWeight: FontWeight.w600, + fontSize: 16, + ), + labelSmall: TextStyle( + color: AppColors.LABEL_SMALL_COLOR, + ), + labelMedium: TextStyle( + color: AppColors.LABEL_MEDIUM_COLOR, + ), + labelLarge: TextStyle( + color: AppColors.LABEL_LARGE_COLOR, + fontWeight: FontWeight.w500, + ), + ), + + /** + * + * Floating action button + */ + floatingActionButtonTheme: FloatingActionButtonThemeData( + backgroundColor: const Color(0xFF313034), + foregroundColor: const Color(0xFFB7B7B7), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(50), + side: const BorderSide( + color: Color(0xFF938F99), + style: BorderStyle.solid, + width: 0.5, + ), + ), + iconSize: 90, + ), + ); + } +} From 294b220e818faa2702900f1c0abd143f40abcd48 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:44:54 +0500 Subject: [PATCH 07/12] add `RemoteSreen` route in route generator --- lib/config/route_generator.dart | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/lib/config/route_generator.dart b/lib/config/route_generator.dart index 0d01a0e..ae388e3 100644 --- a/lib/config/route_generator.dart +++ b/lib/config/route_generator.dart @@ -1,7 +1,12 @@ -import 'package:firebase_auth/firebase_auth.dart'; +import 'package:flutter/cupertino.dart' show CupertinoPageRoute; +import 'package:firebase_auth/firebase_auth.dart' show User; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' + show MultiBlocProvider, BlocProvider; +import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; import 'package:remo_tooth/screens/home/cubit/home_cubit.dart'; +import 'package:remo_tooth/screens/remote/cubit/remote_cubit.dart'; +import 'package:remo_tooth/screens/remote/remote_screen.dart'; import 'package:remo_tooth/screens/sign_in/cubit/sign_in_cubit.dart'; import '../screens/sign_in/sign_in_screen.dart'; import 'app_routes.dart'; @@ -13,6 +18,14 @@ class RouteGenerator { static Route generate(RouteSettings routeSettings) { var arg = routeSettings.arguments; switch (routeSettings.name) { + case AppRoute.SIGN_IN: + return _pageTransition( + BlocProvider( + create: (_) => SignInCubit(), + child: const SignInScreen(), + ), + ); + case AppRoute.HOME: return _pageTransition( MultiBlocProvider( @@ -24,11 +37,12 @@ class RouteGenerator { ), ); - case AppRoute.SIGN_UP: + case AppRoute.REMOTE: return _pageTransition( BlocProvider( - create: (_) => SignInCubit(), - child: const SignInScreen(), + lazy: false, + create: (_) => RemoteCubit(), + child: RemoteScreen(device: (arg as BluetoothDevice)), ), ); @@ -38,7 +52,7 @@ class RouteGenerator { } static _pageTransition(Widget route) => - MaterialPageRoute(builder: (_) => route); + CupertinoPageRoute(builder: (_) => route); static _defaultRoute() { return const Scaffold( From 3668842c396bbc56ed3335158f919538701de937 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:45:59 +0500 Subject: [PATCH 08/12] refactoring and fix device pairing bug --- lib/screens/home/cubit/home_cubit.dart | 129 +++++++++++++------------ lib/screens/home/cubit/home_state.dart | 20 +++- 2 files changed, 81 insertions(+), 68 deletions(-) diff --git a/lib/screens/home/cubit/home_cubit.dart b/lib/screens/home/cubit/home_cubit.dart index 552bbdf..ff5b966 100644 --- a/lib/screens/home/cubit/home_cubit.dart +++ b/lib/screens/home/cubit/home_cubit.dart @@ -1,7 +1,4 @@ -import 'dart:convert'; - import 'package:bloc/bloc.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; import 'package:remo_tooth/config/app_strings.dart'; @@ -9,52 +6,19 @@ part 'home_state.dart'; class HomeCubit extends Cubit { final FlutterBluetoothSerial _bluetooth = FlutterBluetoothSerial.instance; - final List _foundedDevices = []; - BluetoothDevice? _connectedDevice; - HomeCubit() : super(Initial()) { - getPairedDevices(); - } - - Future get isBluetoothEnabled async => _bluetooth.isEnabled; + final List _foundedDevices = List.empty(growable: true); - Future establishConnectionToDevice(BluetoothDevice device) async { - if (!device.isBonded) { - emit(Loading(message: 'Connecting to ${device.name} . . .')); - await _bluetooth.bondDeviceAtAddress(device.address).then((connState) { - if (connState!) { - _connectedDevice = device; - emit(BluetoothResponse(message: 'Connected to ${device.name}!')); - emit(Connected()); - } else { - emit(BluetoothResponse( - message: 'Couldn`t connect to ${device.name}!')); - emit(ShowDevices( - totalDevices: _foundedDevices.length, - devices: _foundedDevices, - )); - } - }); - } + HomeCubit() : super(Initial(message: 'Scan for beacon devices')) { + _getPairedDevices(); } - Future unPairDevice(BluetoothDevice device) async { - _foundedDevices.removeWhere((element) => element.address == device.address); - if (device.isBonded) { - await _bluetooth - .removeDeviceBondWithAddress(device.address) - .then((isUnPairSucessful) { - if (isUnPairSucessful!) { - emit(BluetoothResponse( - message: 'Device ${device.name} has been unpaired!')); - } - }); - } - } + Future get isBluetoothEnabled async => _bluetooth.isEnabled; - Future getPairedDevices() async { + /// retrieves all paired devices. + Future _getPairedDevices() async { + _foundedDevices.clear(); if ((await isBluetoothEnabled)!) { - _foundedDevices.clear(); - emit(Loading(message: 'Getting paired devices . . .')); + emit(Discovering(message: 'Getting paired devices . . .')); await _bluetooth .getBondedDevices() .then((paired) => _foundedDevices.addAll(paired)) @@ -69,15 +33,22 @@ class HomeCubit extends Cubit { } }); } else { - await _bluetooth.requestEnable(); - emit(BluetoothResponse(message: AppString.BLUE_TOOTH_SERVICE_MSG)); + await _bluetooth.requestEnable().then((isBluetoothTurnedOn) { + if (isBluetoothTurnedOn!) { + _getPairedDevices(); + } else { + // emit(BluetoothResponse(message: AppString.DISABLED_BLUETOOTH_MSG)); + emit(Initial(message: 'Scan for beacon devices')); + } + }); } } - Future discoverDevices() async { + /// finds nearby beacon bluetooth devices for pairing. + Future discoverDevices() async { + _foundedDevices.clear(); if ((await isBluetoothEnabled)!) { - _foundedDevices.clear(); - emit(Loading(message: AppString.ON_SCAN_MSG)); + emit(Discovering(message: AppString.DISCOVERING_MSG)); _bluetooth.startDiscovery().listen((e) { _foundedDevices.add(e.device); }).onDone(() { @@ -87,28 +58,58 @@ class HomeCubit extends Cubit { devices: _foundedDevices, )); } else { - emit(BluetoothResponse(message: AppString.DEVICES_NOT_FOUND)); + emit(BluetoothResponse(message: AppString.UNDISCOVERED_DEVICES_MSG)); + emit(Initial(message: 'Scan for beacon devices')); } }); } else { - await _bluetooth.requestEnable(); - emit(BluetoothResponse(message: AppString.BLUE_TOOTH_SERVICE_MSG)); + await _bluetooth.requestEnable().then((isBluetoothTurnedOn) { + if (isBluetoothTurnedOn!) { + _getPairedDevices(); + } else { + emit(BluetoothResponse(message: AppString.DISABLED_BLUETOOTH_MSG)); + emit(Initial(message: 'Scan for beacon devices')); + } + }); } } - Future onMessage() async { - emit(Loading(message: 'Sending 1-bit status signal. . .')); - BluetoothConnection con = - await BluetoothConnection.toAddress(_connectedDevice!.address); - con.output.add(Uint8List.fromList(utf8.encode('1'))); - emit(BluetoothResponse(message: '1-bit status signal!')); + /// Tries to pair with discovered unpaired device. + Future pairDevice(BluetoothDevice device) async { + if (!device.isBonded) { + emit(Pairing( + message: 'Trying to pair with ${device.name}. Please be patient!')); + await _bluetooth.bondDeviceAtAddress(device.address).then((connState) { + if (connState!) { + device; + emit(BluetoothResponse(message: 'Paired to ${device.name}!')); + emit(Paired(device: device)); + } else { + emit( + BluetoothResponse(message: 'Couldn`t pair with ${device.name}!')); + emit(ShowDevices( + totalDevices: _foundedDevices.length, + devices: _foundedDevices, + )); + } + }); + } else if (device.isBonded) { + emit(Paired(device: device)); + } } - Future offMessage() async { - emit(Loading(message: 'Sending 1-bit status signal. . .')); - BluetoothConnection con = - await BluetoothConnection.toAddress(_connectedDevice!.address); - con.output.add(Uint8List.fromList(utf8.encode('0'))); - emit(BluetoothResponse(message: '0-bit status signal!')); + /// Unpairs a bonded/paired device. + Future unPairDevice(BluetoothDevice device) async { + _foundedDevices.removeWhere((element) => element.address == device.address); + if (device.isBonded) { + await _bluetooth + .removeDeviceBondWithAddress(device.address) + .then((isUnPairSucessful) { + if (isUnPairSucessful!) { + emit(BluetoothResponse( + message: 'Device ${device.name} has been unpaired!')); + } + }); + } } } diff --git a/lib/screens/home/cubit/home_state.dart b/lib/screens/home/cubit/home_state.dart index f8d9e51..c0f1fdc 100644 --- a/lib/screens/home/cubit/home_state.dart +++ b/lib/screens/home/cubit/home_state.dart @@ -2,13 +2,25 @@ part of 'home_cubit.dart'; abstract class HomeState {} -class Initial extends HomeState {} +class Initial extends HomeState { + final String message; + Initial({required this.message}); +} -class Connected extends HomeState {} +class Paired extends HomeState { + final BluetoothDevice device; + + Paired({required this.device}); +} + +class Pairing extends HomeState { + final String message; + Pairing({required this.message}); +} -class Loading extends HomeState { +class Discovering extends HomeState { final String message; - Loading({required this.message}); + Discovering({required this.message}); } class ShowDevices extends HomeState { From 0c3ec24c1e4f017b79c70ecd5b994f5bc9d65252 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:46:35 +0500 Subject: [PATCH 09/12] major `UI` rework and implementation --- lib/screens/home/home_screen.dart | 202 ++++++++++++------------ lib/screens/remote/remote_screen.dart | 107 +++++++++++++ lib/screens/sign_in/sign_in_screen.dart | 88 +++-------- 3 files changed, 228 insertions(+), 169 deletions(-) create mode 100644 lib/screens/remote/remote_screen.dart diff --git a/lib/screens/home/home_screen.dart b/lib/screens/home/home_screen.dart index aae828c..bd2cec1 100644 --- a/lib/screens/home/home_screen.dart +++ b/lib/screens/home/home_screen.dart @@ -1,11 +1,12 @@ -import 'package:firebase_auth/firebase_auth.dart'; +import 'package:firebase_auth/firebase_auth.dart' show User; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_bloc/flutter_bloc.dart' show BlocConsumer, BlocProvider; +import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart' + show BluetoothDevice; import 'package:remo_tooth/config/app_strings.dart'; - +import 'package:remo_tooth/screens/home/cubit/home_cubit.dart'; +import 'package:lottie/lottie.dart'; import '../../config/app_routes.dart'; -import '../sign_in/cubit/sign_in_cubit.dart' hide Initial, Loading; -import 'cubit/home_cubit.dart'; class HomeScreen extends StatelessWidget { final User userCredential; @@ -13,147 +14,94 @@ class HomeScreen extends StatelessWidget { @override Widget build(BuildContext context) { + var theme = Theme.of(context); + var mediaQuery = MediaQuery.of(context); + var event = BlocProvider.of(context); + return Scaffold( - floatingActionButton: FloatingActionButton.large( - child: const Icon(Icons.play_arrow_sharp), - onPressed: () => BlocProvider.of(context).discoverDevices(), + floatingActionButton: ElevatedButton( + style: theme.elevatedButtonTheme.style!.copyWith( + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(horizontal: 40), + ), + ), + child: const Text('Scan'), + onPressed: () => event.discoverDevices(), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, appBar: AppBar( title: const Text(AppString.APP_NAME), - backgroundColor: Colors.transparent, actions: [ PopupMenuButton( - onSelected: (value) { - if (value == 1) { - BlocProvider.of(context).signOut(); - Navigator.pushNamedAndRemoveUntil( - context, - AppRoute.SIGN_UP, - (route) => false, - ); - } else { - showAboutDialog( - context: context, - applicationName: AppString.APP_NAME, - applicationVersion: AppString.APP_VERSION, - children: [const Text(AppString.DEVELOPER)], - ); - } - }, itemBuilder: (context) { - return [ - const PopupMenuItem( - value: 1, - child: Text('Logout'), - ), - const PopupMenuItem( - value: 2, - child: Text('About'), - ), - ]; + return []; }, ), ], ), body: Container( - width: double.infinity, - height: double.infinity, - color: Colors.white, + padding: const EdgeInsets.all(5), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - /** - * Handling UI states here . . . - */ - BlocConsumer( listener: (context, state) { if (state is BluetoothResponse) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar(content: Text(state.message)), - ); + _showSnackBar(state.message, context); + } else if (state is Paired) { + Navigator.pushNamed(context, AppRoute.REMOTE, + arguments: state.device); } }, builder: (context, state) { - if (state is ShowDevices) { + if (state is Initial) { + return Center( + child: Text( + state.message, + style: theme.textTheme.titleSmall, + ), + ); + } else if (state is ShowDevices) { return Expanded( child: ListView.separated( itemCount: state.devices.length, - separatorBuilder: (_, index) => const Divider(), - itemBuilder: (_, index) { - return Card( - color: Colors.blue[50], - child: ListTile( - title: Text(state.devices[index].name!), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Type: ${state.devices[index].type.stringValue}'), - Text('MAC: ${state.devices[index].address}'), - ], - ), - trailing: const Icon(Icons.tap_and_play_rounded), - dense: true, - onLongPress: () { - BlocProvider.of(context) - .unPairDevice(state.devices[index]); - }, - onTap: () { - BlocProvider.of(context) - .establishConnectionToDevice( - state.devices[index]); - }, - ), + separatorBuilder: (context, __) => const Divider(), + itemBuilder: (context, i) { + return _CardTile( + device: state.devices[i], + theme: theme, + onLongPress: () => + event.unPairDevice(state.devices[i]), + onPressed: () => event.pairDevice(state.devices[i]), ); }, ), ); - } else if (state is Connected) { - return Expanded( + } else if (state is Discovering) { + return Center( child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, children: [ - FloatingActionButton( - onPressed: () => - BlocProvider.of(context).onMessage(), - backgroundColor: Colors.orange, - child: const Text('1'), - ), - const SizedBox(height: 20), - FloatingActionButton( - onPressed: () => - BlocProvider.of(context).offMessage(), - backgroundColor: Colors.orange, - child: const Text('0'), - ), - const SizedBox(height: 15), - const Text( - 'CAUTION: Unstable code here! The application may crash here...', - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.red, fontWeight: FontWeight.bold), + Lottie.asset( + 'assets/animations/radar.json', + height: mediaQuery.size.height / 5, ), + SizedBox(height: mediaQuery.size.height / 20), + Text(state.message, style: theme.textTheme.titleSmall), ], ), ); - } else if (state is Loading) { + } else if (state is Pairing) { return Center( child: Column( children: [ const CircularProgressIndicator(), - SizedBox( - height: MediaQuery.of(context).size.height / 20, - ), + SizedBox(height: mediaQuery.size.height / 20), Text( state.message, - style: const TextStyle( - color: Colors.black54, - ), - ) + style: theme.textTheme.titleSmall, + textAlign: TextAlign.center, + ), ], ), ); @@ -166,4 +114,50 @@ class HomeScreen extends StatelessWidget { ), ); } + + void _showSnackBar(String message, BuildContext context) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(message)), + ); + } +} + +class _CardTile extends StatelessWidget { + final BluetoothDevice device; + final void Function() onPressed; + final void Function() onLongPress; + const _CardTile({ + Key? key, + required this.theme, + required this.device, + required this.onPressed, + required this.onLongPress, + }) : super(key: key); + + final ThemeData theme; + + @override + Widget build(BuildContext context) { + return Card( + child: ListTile( + trailing: device.isBonded + ? const Icon(Icons.bluetooth_connected_rounded) + : const Icon(Icons.bluetooth_disabled_rounded), + title: Text(device.name!, style: theme.textTheme.titleMedium), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text('Type: ${device.type.stringValue}', + style: theme.textTheme.labelMedium), + Text('Paired: ${device.isBonded}', + style: theme.textTheme.labelMedium), + Text('MAC: ${device.address}', style: theme.textTheme.labelMedium), + ], + ), + onLongPress: onLongPress, + onTap: onPressed, + ), + ); + } } diff --git a/lib/screens/remote/remote_screen.dart b/lib/screens/remote/remote_screen.dart new file mode 100644 index 0000000..3f050d2 --- /dev/null +++ b/lib/screens/remote/remote_screen.dart @@ -0,0 +1,107 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; +import 'package:remo_tooth/screens/remote/cubit/remote_cubit.dart'; + +class RemoteScreen extends StatelessWidget { + final BluetoothDevice device; + const RemoteScreen({super.key, required this.device}); + + @override + Widget build(BuildContext context) { + var event = BlocProvider.of(context); + var mediaQuery = MediaQuery.of(context); + var theme = Theme.of(context); + var message = '0'; + + return Scaffold( + appBar: AppBar( + title: Text(device.name!), + actions: [ + PopupMenuButton( + itemBuilder: (context) { + return []; + }, + ), + ], + ), + body: Column( + children: [ + Expanded( + flex: 5, + child: SizedBox( + width: double.infinity, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + BlocConsumer( + listener: (context, state) { + if (state is ListenResponse) { + message = state.message; + } + }, + builder: (context, state) { + if (state is Loading) { + return FloatingActionButton.large( + child: const CircularProgressIndicator(), + onPressed: () => event.onMessage(device), + ); + } else if (state is OnSignal) { + return FloatingActionButton.large( + foregroundColor: + const Color.fromARGB(255, 131, 78, 255), + child: const Icon(Icons.power_settings_new_rounded), + onPressed: () => event.offMessage(device), + ); + } else if (state is OffSignal) { + return FloatingActionButton.large( + child: const Icon(Icons.power_settings_new_rounded), + onPressed: () => event.onMessage(device), + ); + } else { + return Container(); + } + }, + ) + ], + ), + ), + ), + Expanded( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + width: double.infinity, + decoration: const BoxDecoration( + color: Colors.black, + border: Border( + top: BorderSide( + color: Colors.grey, + width: 6, + ), + ), + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Console Log:', style: theme.textTheme.labelLarge), + SizedBox(height: mediaQuery.size.height / 150), + Text('Device: ${device.name}', + style: theme.textTheme.labelMedium), + Text('Connected: ${device.isConnected}', + style: theme.textTheme.labelMedium), + Text('MAC: ${device.address}', + style: theme.textTheme.labelMedium), + Text('Signal Status: $message', + style: theme.textTheme.labelSmall), + ], + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/screens/sign_in/sign_in_screen.dart b/lib/screens/sign_in/sign_in_screen.dart index aaf111e..f7d7369 100644 --- a/lib/screens/sign_in/sign_in_screen.dart +++ b/lib/screens/sign_in/sign_in_screen.dart @@ -1,73 +1,34 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:remo_tooth/config/app_routes.dart'; +import 'package:remo_tooth/config/app_strings.dart'; import 'package:remo_tooth/screens/sign_in/cubit/sign_in_cubit.dart'; -import '../../config/app_strings.dart'; +import '../../config/app_routes.dart'; class SignInScreen extends StatelessWidget { const SignInScreen({super.key}); @override Widget build(BuildContext context) { + var theme = Theme.of(context).textTheme; var mediaQuery = MediaQuery.of(context); + var event = BlocProvider.of(context); return Scaffold( - bottomSheet: const Padding( - padding: EdgeInsets.all(14), - child: Text( - 'Copyright (c) 2023 CUSIT - ${AppString.DEVELOPER}. All rights reserved.', - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.grey, - ), - ), + bottomSheet: Text( + AppString.COPYRIGHT, + style: theme.labelSmall, + textAlign: TextAlign.center, ), - body: Container( - height: double.infinity, + body: SizedBox( width: double.infinity, - margin: EdgeInsets.zero, - padding: const EdgeInsets.symmetric(horizontal: 20), - color: Colors.white, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Image.asset( - AppString.LOGO, - height: MediaQuery.of(context).size.height / 6, - ), - const Text( - AppString.APP_NAME, - textAlign: TextAlign.center, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 36, - ), - ), - const Text.rich( - textAlign: TextAlign.center, - TextSpan( - text: AppString.DESCRIPTION, - children: [ - TextSpan( - text: - "\nNOTE: This app is still under development and has not been fully tested yet.", - style: TextStyle(color: Colors.red), - ) - ], - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - ), - SizedBox(height: mediaQuery.size.height / 50), - - /** - * Handling UI states here . . . - */ + Text(AppString.APP_NAME, style: theme.displayMedium), + Text(AppString.APP_DESCRIPTION, style: theme.titleSmall), + SizedBox(height: mediaQuery.size.height / 20), BlocConsumer( listener: (_, state) { if (state is Authenticated) { @@ -82,26 +43,17 @@ class SignInScreen extends StatelessWidget { SnackBar(content: Text(state.message)), ); } else if (state is Error) { - ScaffoldMessenger.of(_).showSnackBar( - SnackBar(content: Text(state.message)), - ); + _showSnackBar(state.message, context); } else if (state is NoInternet) { - ScaffoldMessenger.of(_).showSnackBar( - SnackBar(content: Text(state.message)), - ); + _showSnackBar(state.message, context); } }, builder: (_, state) { if (state is Initial) { return ElevatedButton.icon( - label: const Text(AppString.GOOGLE_SIGN_IN_BTN), - icon: const Icon(FontAwesomeIcons.google), - style: ButtonStyle( - backgroundColor: MaterialStateProperty.all( - Colors.blueGrey, - ), - ), - onPressed: () => BlocProvider.of(_).signIn(), + icon: Image.asset(AppString.GOOGLE_LOGO_IMAGE), + label: const Text(AppString.GOOGLE_LABEL_BUTTON), + onPressed: () => event.signIn(), ); } else if (state is Loading) { return const Center( @@ -116,4 +68,10 @@ class SignInScreen extends StatelessWidget { ), ); } + + void _showSnackBar(String message, BuildContext context) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(message)), + ); + } } From fc479f8202480739de4c1916a7afb5675875632a Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:47:15 +0500 Subject: [PATCH 10/12] refactor and handle exception handling --- lib/screens/sign_in/cubit/sign_in_cubit.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/screens/sign_in/cubit/sign_in_cubit.dart b/lib/screens/sign_in/cubit/sign_in_cubit.dart index 05f4566..16f3ccb 100644 --- a/lib/screens/sign_in/cubit/sign_in_cubit.dart +++ b/lib/screens/sign_in/cubit/sign_in_cubit.dart @@ -1,3 +1,5 @@ +import 'dart:developer'; + import 'package:bloc/bloc.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:equatable/equatable.dart'; @@ -61,7 +63,7 @@ class SignInCubit extends Cubit { } } } else { - emit(NoInternet(message: AppString.INTERNET_MSG)); + emit(NoInternet(message: AppString.NO_INTERNET_MSG)); emit(Initial()); } } @@ -69,6 +71,8 @@ class SignInCubit extends Cubit { Future signOut() async { try { await _googleAuthentication.logOut(); - } catch (e) {} + } catch (e) { + log(e.toString()); + } } } From a96780103ebdb817ec923c6fb8b40cdb616e1b21 Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:47:57 +0500 Subject: [PATCH 11/12] feat: add remote signal functionality --- lib/screens/remote/cubit/remote_cubit.dart | 43 ++++++++++++++++++++++ lib/screens/remote/cubit/remote_state.dart | 17 +++++++++ 2 files changed, 60 insertions(+) create mode 100644 lib/screens/remote/cubit/remote_cubit.dart create mode 100644 lib/screens/remote/cubit/remote_state.dart diff --git a/lib/screens/remote/cubit/remote_cubit.dart b/lib/screens/remote/cubit/remote_cubit.dart new file mode 100644 index 0000000..d829362 --- /dev/null +++ b/lib/screens/remote/cubit/remote_cubit.dart @@ -0,0 +1,43 @@ +import 'dart:convert'; +import 'package:bloc/bloc.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; + +part 'remote_state.dart'; + +class RemoteCubit extends Cubit { + RemoteCubit() : super(OffSignal()); + + BluetoothDevice? device; + + Future onMessage(BluetoothDevice device) async { + emit(Loading()); + BluetoothConnection con = + await BluetoothConnection.toAddress(device.address); + con.output.add(Uint8List.fromList(utf8.encode('Hello'))); + con.dispose(); + listenResponse(device); + emit(OnSignal()); + } + + Future offMessage(BluetoothDevice device) async { + emit(Loading()); + BluetoothConnection con = + await BluetoothConnection.toAddress(device.address); + con.output.add(Uint8List.fromList(utf8.encode('World'))); + con.dispose(); + emit(OffSignal()); + } + + Future listenResponse(BluetoothDevice device) async { + emit(Loading()); + BluetoothConnection con = + await BluetoothConnection.toAddress(device.address); + con.input!.listen((event) { + ascii.decode(event); + }).onDone(() { + con.dispose(); + emit(OffSignal()); + }); + } +} diff --git a/lib/screens/remote/cubit/remote_state.dart b/lib/screens/remote/cubit/remote_state.dart new file mode 100644 index 0000000..9c99d4f --- /dev/null +++ b/lib/screens/remote/cubit/remote_state.dart @@ -0,0 +1,17 @@ +part of 'remote_cubit.dart'; + +abstract class RemoteState {} + +class Initial extends RemoteState {} + +class Loading extends RemoteState {} + +class OnSignal extends RemoteState {} + +class OffSignal extends RemoteState {} + +class ListenResponse extends RemoteState { + final String message; + + ListenResponse(this.message); +} From 9d6cdf6e0b5b2137c18c12a35118dbac24abf89d Mon Sep 17 00:00:00 2001 From: mediocre9 Date: Tue, 17 Jan 2023 23:48:19 +0500 Subject: [PATCH 12/12] refactor to separate widget --- lib/widgets/custom_image_button.dart | 43 ---------------------------- 1 file changed, 43 deletions(-) delete mode 100644 lib/widgets/custom_image_button.dart diff --git a/lib/widgets/custom_image_button.dart b/lib/widgets/custom_image_button.dart deleted file mode 100644 index 7ced6e9..0000000 --- a/lib/widgets/custom_image_button.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/material.dart'; - -class CustomImageButton extends StatelessWidget { - final Text label; - final Image image; - final void Function()? onPressed; - - const CustomImageButton({ - super.key, - required this.label, - required this.image, - this.onPressed, - }); - - @override - Widget build(BuildContext context) { - return SizedBox( - width: double.infinity, - child: ElevatedButton.icon( - label: label, - icon: CircleAvatar( - maxRadius: 15, - backgroundColor: Colors.white, - child: image, - ), - style: ButtonStyle( - // shape: MaterialStateProperty.all( - // RoundedRectangleBorder( - // borderRadius: BorderRadius.circular(50), - // ), - // ), - // padding: MaterialStateProperty.all( - // const EdgeInsets.all(15), - // ), - backgroundColor: MaterialStateProperty.all( - Colors.grey, - ), - ), - onPressed: onPressed, - ), - ); - } -}