diff --git a/app/watt_wizard/android/app/build.gradle b/app/watt_wizard/android/app/build.gradle index 44823e4..ed1fa74 100644 --- a/app/watt_wizard/android/app/build.gradle +++ b/app/watt_wizard/android/app/build.gradle @@ -45,7 +45,7 @@ android { applicationId "com.example.watt_wizard" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion flutter.minSdkVersion + minSdkVersion 21 targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/app/watt_wizard/android/app/google-services.json b/app/watt_wizard/android/app/google-services.json index 34ac462..0bcd6db 100644 --- a/app/watt_wizard/android/app/google-services.json +++ b/app/watt_wizard/android/app/google-services.json @@ -1,29 +1,29 @@ { - "project_info": { - "project_number": "192909855910", - "project_id": "hackgt2023", - "storage_bucket": "hackgt2023.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:192909855910:android:a3092489a70c4c20873867", - "android_client_info": { - "package_name": "com.example.watt_wizard" - } - }, - "oauth_client": [], - "api_key": [ - { - "current_key": "AIzaSyATxM_RUX_OreCB3ftyZaI2ByYNNZTRqm4" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [] - } - } - } - ], - "configuration_version": "1" -} \ No newline at end of file + "project_info": { + "project_number": "192909855910", + "project_id": "hackgt2023", + "storage_bucket": "hackgt2023.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:192909855910:android:a3092489a70c4c20873867", + "android_client_info": { + "package_name": "com.example.watt_wizard" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyATxM_RUX_OreCB3ftyZaI2ByYNNZTRqm4" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} diff --git a/app/watt_wizard/android/app/src/main/AndroidManifest.xml b/app/watt_wizard/android/app/src/main/AndroidManifest.xml index 89fc457..68f4ad0 100644 --- a/app/watt_wizard/android/app/src/main/AndroidManifest.xml +++ b/app/watt_wizard/android/app/src/main/AndroidManifest.xml @@ -1,8 +1,24 @@ + + + + + + + + + + + + + + + android:icon="@mipmap/ic_launcher"> - + android:src="@mipmap/ic_launcher" /> + diff --git a/app/watt_wizard/android/app/src/main/res/drawable/launch_background.xml b/app/watt_wizard/android/app/src/main/res/drawable/launch_background.xml index 304732f..6a36c4f 100644 --- a/app/watt_wizard/android/app/src/main/res/drawable/launch_background.xml +++ b/app/watt_wizard/android/app/src/main/res/drawable/launch_background.xml @@ -4,9 +4,9 @@ - + android:src="@mipmap/ic_launcher" /> + diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/watt_wizard/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..90f9580 --- /dev/null +++ b/app/watt_wizard/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4..8d60cb9 100644 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_back.png b/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_back.png new file mode 100644 index 0000000..a05f3fc Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_back.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png b/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png new file mode 100644 index 0000000..4868daa Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/launcher_icon.png deleted file mode 100644 index 9420516..0000000 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-hdpi/launcher_icon.png and /dev/null differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b7..f86bc77 100644 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_back.png b/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_back.png new file mode 100644 index 0000000..3814b23 Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_back.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png b/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png new file mode 100644 index 0000000..78765d2 Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/launcher_icon.png deleted file mode 100644 index 6e9080a..0000000 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-mdpi/launcher_icon.png and /dev/null differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 09d4391..8b90d02 100644 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_back.png b/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_back.png new file mode 100644 index 0000000..2e1846f Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_back.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png b/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png new file mode 100644 index 0000000..d94be19 Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png deleted file mode 100644 index 9609f12..0000000 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png and /dev/null differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d..7ba67bf 100644 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png new file mode 100644 index 0000000..fe154c8 Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_back.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png new file mode 100644 index 0000000..793300a Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png deleted file mode 100644 index 8011323..0000000 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png and /dev/null differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372e..2b46da5 100644 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png new file mode 100644 index 0000000..b640524 Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_back.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png new file mode 100644 index 0000000..3109844 Binary files /dev/null and b/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png differ diff --git a/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png deleted file mode 100644 index b02f0bc..0000000 Binary files a/app/watt_wizard/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png and /dev/null differ diff --git a/app/watt_wizard/assets/icon/android_round.png b/app/watt_wizard/assets/icon/android_round.png new file mode 100644 index 0000000..2b46da5 Binary files /dev/null and b/app/watt_wizard/assets/icon/android_round.png differ diff --git a/app/watt_wizard/assets/icon/icon.png b/app/watt_wizard/assets/icon/icon.png deleted file mode 100644 index 4ec7599..0000000 Binary files a/app/watt_wizard/assets/icon/icon.png and /dev/null differ diff --git a/app/watt_wizard/assets/icon/ios_square.png b/app/watt_wizard/assets/icon/ios_square.png new file mode 100644 index 0000000..6473067 Binary files /dev/null and b/app/watt_wizard/assets/icon/ios_square.png differ diff --git a/app/watt_wizard/ios/Podfile.lock b/app/watt_wizard/ios/Podfile.lock index 9acc8dc..6f349b5 100644 --- a/app/watt_wizard/ios/Podfile.lock +++ b/app/watt_wizard/ios/Podfile.lock @@ -26,6 +26,8 @@ PODS: - FirebaseCoreInternal (10.16.0): - "GoogleUtilities/NSData+zlib (~> 7.8)" - Flutter (1.0.0) + - flutter_blue_plus (0.0.1): + - Flutter - GoogleUtilities/AppDelegateSwizzler (7.11.5): - GoogleUtilities/Environment - GoogleUtilities/Logger @@ -49,6 +51,7 @@ DEPENDENCIES: - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - Flutter (from `Flutter`) + - flutter_blue_plus (from `.symlinks/plugins/flutter_blue_plus/ios`) SPEC REPOS: trunk: @@ -69,6 +72,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_core/ios" Flutter: :path: Flutter + flutter_blue_plus: + :path: ".symlinks/plugins/flutter_blue_plus/ios" SPEC CHECKSUMS: Firebase: 66043bd4579e5b73811f96829c694c7af8d67435 @@ -79,6 +84,7 @@ SPEC CHECKSUMS: FirebaseCore: 2cec518b43635f96afe7ac3a9c513e47558abd2e FirebaseCoreInternal: 26233f705cc4531236818a07ac84d20c333e505a Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96 GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084 GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png index c785cf2..ca0e9d0 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png index aedadbf..b3e4329 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png index 8991902..11beb66 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png index 7fe4dff..af9b3b3 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png index dd674d2..4a3fbd4 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png index 99eb1df..4a22e7c 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png index eb9f218..7b7a156 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png index 8991902..11beb66 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png index 67640cb..01546c7 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png index 897667e..61ff470 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png index 6b5f9f6..e2ecf99 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png index 6257051..1bacdd3 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png index f4428ec..cb04fd3 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png index cdb0f7e..9fb4bef 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png index 897667e..61ff470 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png index cc71f68..3062241 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png index 9420516..4c2c84a 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png index 8011323..3038c76 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png index b153ff0..4794a57 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png index c337c4f..83ae483 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png index 96e7901..afb0d94 100644 Binary files a/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/app/watt_wizard/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/app/watt_wizard/ios/Runner/Info.plist b/app/watt_wizard/ios/Runner/Info.plist index 74b1ec4..83ff996 100644 --- a/app/watt_wizard/ios/Runner/Info.plist +++ b/app/watt_wizard/ios/Runner/Info.plist @@ -22,6 +22,16 @@ $(FLUTTER_BUILD_NAME) CFBundleSignature ???? + NSBluetoothAlwaysUsageDescription + Need BLE permission + NSBluetoothPeripheralUsageDescription + Need BLE permission + NSLocationAlwaysAndWhenInUseUsageDescription + Need Location permission + NSLocationAlwaysUsageDescription + Need Location permission + NSLocationWhenInUseUsageDescription + Need Location permission CFBundleURLTypes diff --git a/app/watt_wizard/lib/homescreen.dart b/app/watt_wizard/lib/homescreen.dart index 2db5da9..57d2bd9 100644 --- a/app/watt_wizard/lib/homescreen.dart +++ b/app/watt_wizard/lib/homescreen.dart @@ -1,5 +1,10 @@ +import 'dart:async'; +import 'dart:io'; + import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:watt_wizard/profile.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -10,6 +15,9 @@ class HomeScreen extends StatefulWidget { class _HomeScreenState extends State { late User user; + BluetoothAdapterState _adapterState = BluetoothAdapterState.unknown; + late StreamSubscription _adapterStateStateSubscription; + @override void initState() { user = FirebaseAuth.instance.currentUser!; @@ -20,11 +28,23 @@ class _HomeScreenState extends State { user = event; }); } + + _adapterStateStateSubscription = + FlutterBluePlus.adapterState.listen((state) { + _adapterState = state; + setState(() {}); + }); }); super.initState(); } + @override + void dispose() { + _adapterStateStateSubscription.cancel(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Scaffold( @@ -39,8 +59,17 @@ class _HomeScreenState extends State { }, ), title: const Text("Home Screen"), - actions: const [ - IconButton(onPressed: null, icon: Icon(Icons.account_circle)), + actions: [ + IconButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ProfileScreen(username: user.displayName!)), + ); + }, + icon: const Icon(Icons.account_circle)), ], ), body: Center( @@ -50,6 +79,16 @@ class _HomeScreenState extends State { Text( "Welcome ${user.displayName}", ), + _adapterState == BluetoothAdapterState.on + ? const Spacer() + : FilledButton( + onPressed: () async { + if (Platform.isAndroid) { + await FlutterBluePlus.turnOn(); + } else {} + }, + child: const Text("Turn Bluetooth On"), + ) ], )), ); diff --git a/app/watt_wizard/lib/main.dart b/app/watt_wizard/lib/main.dart index 0e7beec..af4300a 100644 --- a/app/watt_wizard/lib/main.dart +++ b/app/watt_wizard/lib/main.dart @@ -16,6 +16,10 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { + // if (Platform.isAndroid) { + // await FlutterBluePlus.turnOn(); + // } + return MaterialApp( title: 'Watt Wizard', theme: ThemeData( @@ -29,14 +33,13 @@ class MyApp extends StatelessWidget { Widget _landingPage() { return StreamBuilder( - stream: FirebaseAuth.instance.authStateChanges(), - builder: (BuildContext context, snapshot) { - if(snapshot.hasData) { - return const HomeScreen(); - } - return const MyHomePage(title: 'Sign in to Watt Wizard'); - } - ); + stream: FirebaseAuth.instance.authStateChanges(), + builder: (BuildContext context, snapshot) { + if (snapshot.hasData) { + return const HomeScreen(); + } + return const MyHomePage(title: 'Sign in to Watt Wizard'); + }); } class MyHomePage extends StatelessWidget { diff --git a/app/watt_wizard/lib/profile.dart b/app/watt_wizard/lib/profile.dart new file mode 100644 index 0000000..71f8151 --- /dev/null +++ b/app/watt_wizard/lib/profile.dart @@ -0,0 +1,154 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:watt_wizard/widgets/connected_device_tile.dart'; +import 'package:watt_wizard/widgets/scan_result_tile.dart'; +import 'package:watt_wizard/utils/extra.dart'; + +class ProfileScreen extends StatefulWidget { + const ProfileScreen({super.key, required this.username}); + + final String username; + + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + List _connectedDevices = []; + List _scanResults = []; + bool _isScanning = false; + late StreamSubscription> _scanResultsSubscription; + late StreamSubscription _isScanningSubscription; + + @override + void initState() { + super.initState(); + + FlutterBluePlus.connectedSystemDevices.then((devices) { + List device = []; + for (BluetoothDevice d in devices) { + if (d.platformName == "Light Control") { + device.add(d); + } + } + _connectedDevices = device; + setState(() {}); + }); + + _scanResultsSubscription = FlutterBluePlus.scanResults.listen((results) { + List result = []; + for (ScanResult r in results) { + if (r.device.platformName == "Light Control" && + !_connectedDevices.contains(r.device)) { + result.add(r); + } + } + _scanResults = result; + setState(() {}); + }); + + _isScanningSubscription = FlutterBluePlus.isScanning.listen((state) { + _isScanning = state; + setState(() {}); + }); + } + + @override + void dispose() { + _scanResultsSubscription.cancel(); + _isScanningSubscription.cancel(); + super.dispose(); + } + + Future onScanPressed() async { + await FlutterBluePlus.startScan(timeout: const Duration(seconds: 15)); + setState(() {}); // force refresh of connectedSystemDevices + } + + Future onStopPressed() async { + FlutterBluePlus.stopScan(); + } + + void onConnectPressed(BluetoothDevice device) { + device.connectAndUpdateStream(); + _connectedDevices.add(device); + setState(() {}); + } + + Future onRefresh() { + if (_isScanning == false) { + FlutterBluePlus.startScan(timeout: const Duration(seconds: 15)); + } + setState(() {}); + return Future.delayed(const Duration(milliseconds: 500)); + } + + List _buildConnectedDeviceTiles(BuildContext context) { + return _connectedDevices + .map( + (d) => ConnectedDeviceTile( + device: d, + onConnect: () => onConnectPressed(d), + ), + ) + .toList(); + } + + List _buildScanResultTiles(BuildContext context) { + return _scanResults + .map( + (r) => ScanResultTile( + result: r, + onTap: () { + _scanResults.remove(r); + setState(() {}); + onConnectPressed(r.device); + }, + ), + ) + .toList(); + } + + Widget buildScanButton(BuildContext context) { + if (FlutterBluePlus.isScanningNow) { + return FloatingActionButton( + onPressed: onStopPressed, + backgroundColor: Colors.red, + child: const Icon(Icons.stop), + ); + } else { + return FloatingActionButton( + onPressed: onScanPressed, child: const Text("SCAN")); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + leading: IconButton( + icon: const Icon(Icons.chevron_left), + onPressed: () { + Navigator.pop(context); + }, + ), + title: Text(widget.username), + ), + body: RefreshIndicator( + onRefresh: onRefresh, + child: ListView( + children: [ + const Text("Connected Devices"), + ..._buildConnectedDeviceTiles(context), + const Text("Scanned Devices:"), + ..._buildScanResultTiles(context), + ], + ), + ), + floatingActionButton: buildScanButton(context), + ); + } +} diff --git a/app/watt_wizard/lib/utils/extra.dart b/app/watt_wizard/lib/utils/extra.dart new file mode 100644 index 0000000..8a44c33 --- /dev/null +++ b/app/watt_wizard/lib/utils/extra.dart @@ -0,0 +1,39 @@ +import 'utils.dart'; + +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; + +final Map> _global = {}; + +/// connect & disconnect + update stream +extension Extra on BluetoothDevice { + // convenience + StreamControllerReemit get _stream { + _global[remoteId] ??= StreamControllerReemit(initialValue: false); + return _global[remoteId]!; + } + + // get stream + Stream get isConnectingOrDisconnecting { + return _stream.stream; + } + + // connect & update stream + Future connectAndUpdateStream() async { + _stream.add(true); + try { + await connect(); + } finally { + _stream.add(false); + } + } + + // disconnect & update stream + Future disconnectAndUpdateStream() async { + _stream.add(true); + try { + await disconnect(); + } finally { + _stream.add(false); + } + } +} diff --git a/app/watt_wizard/lib/utils/utils.dart b/app/watt_wizard/lib/utils/utils.dart new file mode 100644 index 0000000..048a5a5 --- /dev/null +++ b/app/watt_wizard/lib/utils/utils.dart @@ -0,0 +1,86 @@ +import 'dart:async'; + +// It is essentially a stream but: +// 1. we cache the latestValue of the stream +// 2. the "latestValue" is re-emitted whenever the stream is listened to +class StreamControllerReemit { + T? _latestValue; + + final StreamController _controller = StreamController.broadcast(); + + StreamControllerReemit({T? initialValue}) : _latestValue = initialValue; + + Stream get stream { + return _latestValue != null + ? _controller.stream.newStreamWithInitialValue(_latestValue!) + : _controller.stream; + } + + T? get value => _latestValue; + + void add(T newValue) { + _latestValue = newValue; + _controller.add(newValue); + } + + Future close() { + return _controller.close(); + } +} + +// return a new stream that imediately emits an initial value +extension _StreamNewStreamWithInitialValue on Stream { + Stream newStreamWithInitialValue(T initialValue) { + return transform(_NewStreamWithInitialValueTransformer(initialValue)); + } +} + +// Helper for 'newStreamWithInitialValue' method for streams. +class _NewStreamWithInitialValueTransformer + extends StreamTransformerBase { + final T initialValue; + + _NewStreamWithInitialValueTransformer(this.initialValue); + + @override + Stream bind(Stream stream) { + if (stream.isBroadcast) { + return _bind(stream).asBroadcastStream(); + } else { + return _bind(stream); + } + } + + Stream _bind(Stream stream) { + StreamController? controller; + StreamSubscription? subscription; + + controller = StreamController( + onListen: () { + // Emit the initial value + controller?.add(initialValue); + + subscription = stream.listen( + controller?.add, + onError: (Object error) { + controller?.addError(error); + controller?.close(); + }, + onDone: controller?.close, + ); + }, + onPause: ([Future? resumeSignal]) { + subscription?.pause(resumeSignal); + }, + onResume: () { + subscription?.resume(); + }, + onCancel: () { + return subscription?.cancel(); + }, + sync: true, + ); + + return controller.stream; + } +} diff --git a/app/watt_wizard/lib/widgets/connected_device_tile.dart b/app/watt_wizard/lib/widgets/connected_device_tile.dart new file mode 100644 index 0000000..4959b2b --- /dev/null +++ b/app/watt_wizard/lib/widgets/connected_device_tile.dart @@ -0,0 +1,59 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; + +class ConnectedDeviceTile extends StatefulWidget { + final BluetoothDevice device; + final VoidCallback onConnect; + + const ConnectedDeviceTile({ + required this.device, + required this.onConnect, + Key? key, + }) : super(key: key); + + @override + State createState() => _ConnectedDeviceTileState(); +} + +class _ConnectedDeviceTileState extends State { + BluetoothConnectionState _connectionState = + BluetoothConnectionState.disconnected; + + late StreamSubscription + _connectionStateSubscription; + + @override + void initState() { + super.initState(); + + _connectionStateSubscription = + widget.device.connectionState.listen((state) { + _connectionState = state; + setState(() {}); + }); + } + + @override + void dispose() { + _connectionStateSubscription.cancel(); + super.dispose(); + } + + bool get isConnected { + return _connectionState == BluetoothConnectionState.connected; + } + + @override + Widget build(BuildContext context) { + return ListTile( + title: Text(widget.device.platformName), + subtitle: Text(widget.device.remoteId.toString()), + trailing: ElevatedButton( + onPressed: isConnected ? null : widget.onConnect, + child: isConnected ? const Text('OPEN') : const Text('CONNECT'), + ), + ); + } +} diff --git a/app/watt_wizard/lib/widgets/scan_result_tile.dart b/app/watt_wizard/lib/widgets/scan_result_tile.dart new file mode 100644 index 0000000..10c01d4 --- /dev/null +++ b/app/watt_wizard/lib/widgets/scan_result_tile.dart @@ -0,0 +1,151 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_blue_plus/flutter_blue_plus.dart'; + +class ScanResultTile extends StatefulWidget { + const ScanResultTile({Key? key, required this.result, this.onTap}) + : super(key: key); + + final ScanResult result; + final VoidCallback? onTap; + + @override + State createState() => _ScanResultTileState(); +} + +class _ScanResultTileState extends State { + BluetoothConnectionState _connectionState = + BluetoothConnectionState.disconnected; + + late StreamSubscription + _connectionStateSubscription; + + @override + void initState() { + super.initState(); + + _connectionStateSubscription = + widget.result.device.connectionState.listen((state) { + _connectionState = state; + setState(() {}); + }); + } + + @override + void dispose() { + _connectionStateSubscription.cancel(); + super.dispose(); + } + + String getNiceHexArray(List bytes) { + return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'; + } + + String getNiceManufacturerData(Map> data) { + if (data.isEmpty) { + return 'N/A'; + } + return data.entries + .map((entry) => + '${entry.key.toRadixString(16)}: ${getNiceHexArray(entry.value)}') + .join(', ') + .toUpperCase(); + } + + String getNiceServiceData(Map> data) { + if (data.isEmpty) { + return 'N/A'; + } + return data.entries + .map((v) => '${v.key}: ${getNiceHexArray(v.value)}') + .join(', ') + .toUpperCase(); + } + + String getNiceServiceUuids(List serviceUuids) { + return serviceUuids.isEmpty ? 'N/A' : serviceUuids.join(', ').toUpperCase(); + } + + bool get isConnected { + return _connectionState == BluetoothConnectionState.connected; + } + + Widget _buildTitle(BuildContext context) { + if (widget.result.device.platformName.isNotEmpty) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.result.device.platformName, + overflow: TextOverflow.ellipsis, + ), + Text( + widget.result.device.remoteId.toString(), + style: Theme.of(context).textTheme.bodySmall, + ) + ], + ); + } else { + return Text(widget.result.device.remoteId.toString()); + } + } + + Widget _buildConnectButton(BuildContext context) { + return ElevatedButton( + child: isConnected ? const Text('OPEN') : const Text('CONNECT'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.black, + foregroundColor: Colors.white, + ), + onPressed: + (widget.result.advertisementData.connectable) ? widget.onTap : null, + ); + } + + Widget _buildAdvRow(BuildContext context, String title, String value) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(title, style: Theme.of(context).textTheme.bodySmall), + const SizedBox( + width: 12.0, + ), + Expanded( + child: Text( + value, + style: Theme.of(context) + .textTheme + .bodySmall + ?.apply(color: Colors.black), + softWrap: true, + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + var adv = widget.result.advertisementData; + return ExpansionTile( + title: _buildTitle(context), + leading: Text(widget.result.rssi.toString()), + trailing: _buildConnectButton(context), + children: [ + _buildAdvRow(context, 'Complete Local Name', adv.localName), + _buildAdvRow(context, 'Tx Power Level', '${adv.txPowerLevel ?? 'N/A'}'), + _buildAdvRow(context, 'Manufacturer Data', + getNiceManufacturerData(adv.manufacturerData)), + _buildAdvRow( + context, 'Service UUIDs', getNiceServiceUuids(adv.serviceUuids)), + _buildAdvRow( + context, 'Service Data', getNiceServiceData(adv.serviceData)), + ], + ); + } +} diff --git a/app/watt_wizard/macos/Flutter/GeneratedPluginRegistrant.swift b/app/watt_wizard/macos/Flutter/GeneratedPluginRegistrant.swift index 7b9be20..d3bda01 100644 --- a/app/watt_wizard/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/app/watt_wizard/macos/Flutter/GeneratedPluginRegistrant.swift @@ -7,8 +7,10 @@ import Foundation import firebase_auth import firebase_core +import flutter_blue_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin")) FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin")) + FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin")) } diff --git a/app/watt_wizard/pubspec.lock b/app/watt_wizard/pubspec.lock index 76411f2..68a5a3c 100644 --- a/app/watt_wizard/pubspec.lock +++ b/app/watt_wizard/pubspec.lock @@ -166,6 +166,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_blue_plus: + dependency: "direct main" + description: + name: flutter_blue_plus + sha256: d90c8cd9600d971a9e4007441e0f06b5134b6ba8329e28f255d68b02832ea2d4 + url: "https://pub.dev" + source: hosted + version: "1.18.3" flutter_launcher_icons: dependency: "direct main" description: diff --git a/app/watt_wizard/pubspec.yaml b/app/watt_wizard/pubspec.yaml index 3619be1..96660a2 100644 --- a/app/watt_wizard/pubspec.yaml +++ b/app/watt_wizard/pubspec.yaml @@ -37,6 +37,7 @@ dependencies: cupertino_icons: ^1.0.2 firebase_core: ^2.17.0 firebase_auth: ^4.10.1 + flutter_blue_plus: ^1.18.3 dev_dependencies: flutter_test: @@ -91,8 +92,6 @@ flutter: # see https://flutter.dev/custom-fonts/#from-packages flutter_launcher_icons: - android: "launcher_icon" ios: true - image_path_android: "assets/icon/icon.png" - image_path_ios: "assets/icon/icon.png" + image_path_ios: "assets/icon/ios_square.png" min_sdk_android: 21 # android min sdk min:16, default 21