Compare commits
23 Commits
758cc22a0f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2afc71e24c | ||
|
|
9bff11a0b1 | ||
|
|
cfebf74515 | ||
|
|
fe622d8af9 | ||
|
|
4ff2ad4396 | ||
|
|
cdbd5b7484 | ||
|
|
e6c536f380 | ||
|
|
bd73ba1b45 | ||
|
|
d7d565a36a | ||
|
|
2d53f2cdd3 | ||
|
|
22fef0e0a8 | ||
|
|
3a8fa3633c | ||
| 477646ab9d | |||
|
|
677a7c4d4a | ||
|
|
01ae020374 | ||
|
|
f80e234b1d | ||
|
|
b75635a801 | ||
|
|
c19cdec3cf | ||
|
|
07af3c344f | ||
|
|
8310451f6b | ||
|
|
da8eb3ae2d | ||
|
|
6af1baed32 | ||
| d5b323e158 |
2
.gitignore
vendored
@@ -5,9 +5,11 @@
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.build/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
.swiftpm/
|
||||
migrate_working_dir/
|
||||
|
||||
# IntelliJ related
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
analyzer:
|
||||
errors:
|
||||
use_build_context_synchronously: ignore
|
||||
avoid_print: ignore
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
@@ -22,8 +26,8 @@ linter:
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
- prefer_relative_imports: true
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
plugins {
|
||||
id "com.android.application"
|
||||
id "kotlin-android"
|
||||
id "dev.flutter.flutter-gradle-plugin"
|
||||
id 'com.google.gms.google-services'
|
||||
}
|
||||
|
||||
def localProperties = new Properties()
|
||||
def localPropertiesFile = rootProject.file('local.properties')
|
||||
if (localPropertiesFile.exists()) {
|
||||
@@ -6,11 +13,6 @@ if (localPropertiesFile.exists()) {
|
||||
}
|
||||
}
|
||||
|
||||
def flutterRoot = localProperties.getProperty('flutter.sdk')
|
||||
if (flutterRoot == null) {
|
||||
// throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
|
||||
}
|
||||
|
||||
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
|
||||
if (flutterVersionCode == null) {
|
||||
flutterVersionCode = '1'
|
||||
@@ -21,21 +23,12 @@ if (flutterVersionName == null) {
|
||||
flutterVersionName = '1.0'
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
// START: FlutterFire Configuration
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
// END: FlutterFire Configuration
|
||||
apply plugin: 'kotlin-android'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
if (keystorePropertiesFile.exists()) {
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
}
|
||||
|
||||
|
||||
android {
|
||||
namespace "vn.smatec.sfm"
|
||||
compileSdkVersion 35
|
||||
@@ -44,12 +37,12 @@ android {
|
||||
compileOptions {
|
||||
// Flag to enable support for the new language APIs
|
||||
coreLibraryDesugaringEnabled true
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
sourceCompatibility JavaVersion.VERSION_17
|
||||
targetCompatibility JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
jvmTarget = '17'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
@@ -102,9 +95,9 @@ flutter {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2'
|
||||
// implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation platform('com.google.firebase:firebase-bom:33.15.0')
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||
implementation 'androidx.window:window:1.0.0'
|
||||
implementation 'androidx.window:window-java:1.0.0'
|
||||
}
|
||||
|
||||
@@ -1,30 +1,36 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false"
|
||||
tools:targetApi="5" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<!-- <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" /> -->
|
||||
<!-- NOTE: the example app requests USE_EXACT_ALARM to make it easier to run the app.
|
||||
Developers will need to check if their own app needs to use SCHEDULE_EXACT_ALARM instead -->
|
||||
<!-- <uses-permission android:name="android.permission.USE_EXACT_ALARM" /> -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<!-- NOTE: Special use was selected as it's the closest match for this example app.
|
||||
apps should specify the appropriate permission for their use cases. -->
|
||||
<!-- <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" /> -->
|
||||
<!-- START Permissions Package -->
|
||||
<!-- Permissions options for the `camera` group -->
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<!-- Permissions options for the `location` group -->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<!-- Permissions options for the `alarm` group -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM"
|
||||
tools:ignore="ExactAlarm" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
|
||||
<!-- END Permissions Package -->
|
||||
<application
|
||||
android:label="SFM"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/launcher_icon">
|
||||
<meta-data android:name="com.google.android.geo.API_KEY"
|
||||
android:value="AIzaSyA9C7Pmxw6Gw3H2mM4WA_XGngRIIr2VS7k"/>
|
||||
android:value="AIzaSyDI8b-PUgKUgj5rHdtgEHCwWjUXYJrqYhE"/>
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTop"
|
||||
@@ -34,6 +40,7 @@
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:showWhenLocked="true"
|
||||
android:turnScreenOn="true"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:exported="true">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
@@ -60,7 +67,25 @@
|
||||
<service
|
||||
android:name="com.dexterous.flutterlocalnotifications.ForegroundService"
|
||||
android:exported="false"
|
||||
android:stopWithTask="false"/>
|
||||
android:stopWithTask="false"
|
||||
android:foregroundServiceType="specialUse" />
|
||||
<service android:name="com.gdelataillade.alarm.services.NotificationOnKillService" />
|
||||
|
||||
<service
|
||||
android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmService"
|
||||
android:permission="android.permission.BIND_JOB_SERVICE"
|
||||
android:exported="false"/>
|
||||
<receiver
|
||||
android:name="dev.fluttercommunity.plus.androidalarmmanager.AlarmBroadcastReceiver"
|
||||
android:exported="false"/>
|
||||
<receiver
|
||||
android:name="dev.fluttercommunity.plus.androidalarmmanager.RebootBroadcastReceiver"
|
||||
android:enabled="false"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ActionBroadcastReceiver" />
|
||||
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
|
||||
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
|
||||
|
||||
BIN
android/app/src/main/res/drawable/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 442 B |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -1,21 +1,9 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.8.22'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// START: FlutterFire Configuration
|
||||
classpath 'com.google.gms:google-services:4.3.15'
|
||||
// END: FlutterFire Configuration
|
||||
classpath 'com.android.tools.build:gradle:8.2.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
plugins {
|
||||
id 'com.google.gms.google-services' version '4.3.15' apply false
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
@@ -43,3 +31,7 @@ subprojects {
|
||||
tasks.register("clean", Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-all.zip
|
||||
|
||||
@@ -18,8 +18,11 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||
id "com.android.application" version "8.2.1" apply false
|
||||
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
|
||||
id "com.android.application" version "8.3.2" apply false
|
||||
// START: FlutterFire Configuration
|
||||
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||
// END: FlutterFire Configuration
|
||||
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
|
||||
}
|
||||
|
||||
include ":app"
|
||||
|
||||
1
assets/animations/component_loading.json
Normal file
1
assets/animations/loading.json
Normal file
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 54 KiB |
BIN
assets/sounds/warning_alarm.mp3
Normal file
3
devtools_options.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
||||
@@ -21,6 +21,6 @@
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>11.0</string>
|
||||
<string>12.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
39
ios/Podfile
@@ -1,3 +1,39 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
platform :ios, '15.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
use_modular_headers!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
@@ -30,5 +66,8 @@ post_install do |installer|
|
||||
]
|
||||
|
||||
end
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0'
|
||||
end
|
||||
end
|
||||
end
|
||||
197
ios/Podfile.lock
Normal file
@@ -0,0 +1,197 @@
|
||||
PODS:
|
||||
- alarm (0.0.1):
|
||||
- Flutter
|
||||
- app_settings (5.1.1):
|
||||
- Flutter
|
||||
- connectivity_plus (0.0.1):
|
||||
- Flutter
|
||||
- Firebase/CoreOnly (11.10.0):
|
||||
- FirebaseCore (~> 11.10.0)
|
||||
- Firebase/Messaging (11.10.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseMessaging (~> 11.10.0)
|
||||
- firebase_core (3.13.0):
|
||||
- Firebase/CoreOnly (= 11.10.0)
|
||||
- Flutter
|
||||
- firebase_messaging (15.2.5):
|
||||
- Firebase/Messaging (= 11.10.0)
|
||||
- firebase_core
|
||||
- Flutter
|
||||
- FirebaseCore (11.10.0):
|
||||
- FirebaseCoreInternal (~> 11.10.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/Logger (~> 8.0)
|
||||
- FirebaseCoreInternal (11.10.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.0)"
|
||||
- FirebaseInstallations (11.10.0):
|
||||
- FirebaseCore (~> 11.10.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- FirebaseMessaging (11.10.0):
|
||||
- FirebaseCore (~> 11.10.0)
|
||||
- FirebaseInstallations (~> 11.0)
|
||||
- GoogleDataTransport (~> 10.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.0)
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/Reachability (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- nanopb (~> 3.30910.0)
|
||||
- Flutter (1.0.0)
|
||||
- flutter_barcode_scanner_plus (3.0.7):
|
||||
- Flutter
|
||||
- flutter_fgbg (0.0.1):
|
||||
- Flutter
|
||||
- flutter_local_notifications (0.0.1):
|
||||
- Flutter
|
||||
- geolocator_apple (1.2.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- Google-Maps-iOS-Utils (5.0.0):
|
||||
- GoogleMaps (~> 8.0)
|
||||
- google_maps_flutter_ios (0.0.1):
|
||||
- Flutter
|
||||
- Google-Maps-iOS-Utils (< 7.0, >= 5.0)
|
||||
- GoogleMaps (< 10.0, >= 8.4)
|
||||
- GoogleDataTransport (10.1.0):
|
||||
- nanopb (~> 3.30910.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- GoogleMaps (8.4.0):
|
||||
- GoogleMaps/Maps (= 8.4.0)
|
||||
- GoogleMaps/Base (8.4.0)
|
||||
- GoogleMaps/Maps (8.4.0):
|
||||
- GoogleMaps/Base
|
||||
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Environment (8.1.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Logger (8.1.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Network (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (8.1.0)":
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Privacy (8.1.0)
|
||||
- GoogleUtilities/Reachability (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/UserDefaults (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- maps_launcher (0.0.1):
|
||||
- Flutter
|
||||
- nanopb (3.30910.0):
|
||||
- nanopb/decode (= 3.30910.0)
|
||||
- nanopb/encode (= 3.30910.0)
|
||||
- nanopb/decode (3.30910.0)
|
||||
- nanopb/encode (3.30910.0)
|
||||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- PromisesObjC (2.4.0)
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- url_launcher_ios (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- alarm (from `.symlinks/plugins/alarm/ios`)
|
||||
- app_settings (from `.symlinks/plugins/app_settings/ios`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_barcode_scanner_plus (from `.symlinks/plugins/flutter_barcode_scanner_plus/ios`)
|
||||
- flutter_fgbg (from `.symlinks/plugins/flutter_fgbg/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`)
|
||||
- google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`)
|
||||
- maps_launcher (from `.symlinks/plugins/maps_launcher/ios`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Firebase
|
||||
- FirebaseCore
|
||||
- FirebaseCoreInternal
|
||||
- FirebaseInstallations
|
||||
- FirebaseMessaging
|
||||
- Google-Maps-iOS-Utils
|
||||
- GoogleDataTransport
|
||||
- GoogleMaps
|
||||
- GoogleUtilities
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
alarm:
|
||||
:path: ".symlinks/plugins/alarm/ios"
|
||||
app_settings:
|
||||
:path: ".symlinks/plugins/app_settings/ios"
|
||||
connectivity_plus:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
firebase_core:
|
||||
:path: ".symlinks/plugins/firebase_core/ios"
|
||||
firebase_messaging:
|
||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_barcode_scanner_plus:
|
||||
:path: ".symlinks/plugins/flutter_barcode_scanner_plus/ios"
|
||||
flutter_fgbg:
|
||||
:path: ".symlinks/plugins/flutter_fgbg/ios"
|
||||
flutter_local_notifications:
|
||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||
geolocator_apple:
|
||||
:path: ".symlinks/plugins/geolocator_apple/darwin"
|
||||
google_maps_flutter_ios:
|
||||
:path: ".symlinks/plugins/google_maps_flutter_ios/ios"
|
||||
maps_launcher:
|
||||
:path: ".symlinks/plugins/maps_launcher/ios"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
url_launcher_ios:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
alarm: 9ff6d2dae9bd69c4022622f7e0a1e9c1dd70064e
|
||||
app_settings: 5127ae0678de1dcc19f2293271c51d37c89428b2
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
Firebase: 1fe1c0a7d9aaea32efe01fbea5f0ebd8d70e53a2
|
||||
firebase_core: 2d4534e7b489907dcede540c835b48981d890943
|
||||
firebase_messaging: 75bc93a4df25faccad67f6662ae872ac9ae69b64
|
||||
FirebaseCore: 8344daef5e2661eb004b177488d6f9f0f24251b7
|
||||
FirebaseCoreInternal: ef4505d2afb1d0ebbc33162cb3795382904b5679
|
||||
FirebaseInstallations: 9980995bdd06ec8081dfb6ab364162bdd64245c3
|
||||
FirebaseMessaging: 2b9f56aa4ed286e1f0ce2ee1d413aabb8f9f5cb9
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
flutter_barcode_scanner_plus: e5ef7f41cdbf3086e1b9348dce986dde3aa08696
|
||||
flutter_fgbg: d3da78df78454b1808f0829a5da9cd17dfe16444
|
||||
flutter_local_notifications: ad39620c743ea4c15127860f4b5641649a988100
|
||||
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
|
||||
Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321
|
||||
google_maps_flutter_ios: 0291eb2aa252298a769b04d075e4a9d747ff7264
|
||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
maps_launcher: edf829809ba9e894d70e569bab11c16352dedb45
|
||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
|
||||
PODFILE CHECKSUM: 72b62bbc58143b910914489c5ddbf2bfa99b3dd4
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
@@ -10,10 +10,14 @@
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
5EFD34A62DA7D89800351DB2 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5EFD34A52DA7D89800351DB2 /* GoogleService-Info.plist */; };
|
||||
634E6B9E5E8AF15560F03990 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 501AA52756E2B08A7E1FBE73 /* Pods_Runner.framework */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
A241E2BF2EAA2F1C00664284 /* warning_alarm.caf in Resources */ = {isa = PBXBuildFile; fileRef = A241E2BE2EAA2F1C00664284 /* warning_alarm.caf */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -42,10 +46,15 @@
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
22127402AC507377520FA076 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
25C6B6667708ECABC11CB63A /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||
30C8386A287397C265D21D0C /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
501AA52756E2B08A7E1FBE73 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
5EE624442DA6030500B7B650 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
5EFD34A52DA7D89800351DB2 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
@@ -56,6 +65,7 @@
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
A241E2BE2EAA2F1C00664284 /* warning_alarm.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = warning_alarm.caf; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -63,6 +73,8 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||
634E6B9E5E8AF15560F03990 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -77,6 +89,14 @@
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
7E17DC341A9804E98C0A4D9D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
501AA52756E2B08A7E1FBE73 /* Pods_Runner.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -91,10 +111,13 @@
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
A241E2BE2EAA2F1C00664284 /* warning_alarm.caf */,
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
E4B9BF767E8449E8CDAC1C45 /* Pods */,
|
||||
7E17DC341A9804E98C0A4D9D /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -114,6 +137,7 @@
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
5EFD34A52DA7D89800351DB2 /* GoogleService-Info.plist */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
@@ -123,6 +147,16 @@
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E4B9BF767E8449E8CDAC1C45 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
30C8386A287397C265D21D0C /* Pods-Runner.debug.xcconfig */,
|
||||
25C6B6667708ECABC11CB63A /* Pods-Runner.release.xcconfig */,
|
||||
22127402AC507377520FA076 /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -147,18 +181,24 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
63291DA6552A39BD8B950BE6 /* [CP] Check Pods Manifest.lock */,
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
6E40E7EA960942FA803CE7C6 /* [CP] Embed Pods Frameworks */,
|
||||
1DD8F2A74CC23CF717FB4664 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Runner;
|
||||
packageProductDependencies = (
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||
);
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
@@ -169,7 +209,7 @@
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1300;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C8080294A63A400263BE5 = {
|
||||
@@ -191,6 +231,9 @@
|
||||
Base,
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
packageReferences = (
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
|
||||
);
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
@@ -215,6 +258,8 @@
|
||||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
5EFD34A62DA7D89800351DB2 /* GoogleService-Info.plist in Resources */,
|
||||
A241E2BF2EAA2F1C00664284 /* warning_alarm.caf in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
@@ -223,6 +268,23 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
1DD8F2A74CC23CF717FB4664 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@@ -239,6 +301,45 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
63291DA6552A39BD8B950BE6 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputFileListPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
6E40E7EA960942FA803CE7C6 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
@@ -345,7 +446,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -361,15 +462,22 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = WM843WW2NF;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SmartFM;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = vn.smatec.sfm;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -470,7 +578,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
@@ -519,7 +627,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
@@ -537,15 +645,22 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = WM843WW2NF;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SmartFM;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = vn.smatec.sfm;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -560,15 +675,22 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = WM843WW2NF;
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = SmartFM;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = vn.smatec.sfm;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
@@ -609,6 +731,20 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCLocalSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<PreActions>
|
||||
<ExecutionAction
|
||||
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||
<ActionContent
|
||||
title = "Run Prepare Flutter Framework Script"
|
||||
scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</EnvironmentBuildable>
|
||||
</ActionContent>
|
||||
</ExecutionAction>
|
||||
</PreActions>
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -26,6 +44,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
@@ -54,11 +73,13 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
|
||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
import UIKit
|
||||
import Flutter
|
||||
import flutter_local_notifications
|
||||
import GoogleMaps
|
||||
import FirebaseCore
|
||||
import FirebaseMessaging
|
||||
import UserNotifications
|
||||
import alarm
|
||||
|
||||
@UIApplicationMain
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
// This is required to make any communication available in the action isolate.
|
||||
FlutterLocalNotificationsPlugin.setPluginRegistrantCallback { (registry) in
|
||||
GeneratedPluginRegistrant.register(with: registry)
|
||||
}
|
||||
GMSServices.provideAPIKey("AIzaSyDI8b-PUgKUgj5rHdtgEHCwWjUXYJrqYhE")
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
|
||||
if #available(iOS 10.0, *) {
|
||||
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
|
||||
}
|
||||
|
||||
SwiftAlarmPlugin.registerBackgroundTasks()
|
||||
FirebaseApp.configure()
|
||||
GMSServices.provideAPIKey("AIzaSyA9C7Pmxw6Gw3H2mM4WA_XGngRIIr2VS7k")
|
||||
GeneratedPluginRegistrant.register(with: self)
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 120 KiB After Width: | Height: | Size: 133 KiB |
|
Before Width: | Height: | Size: 755 B After Width: | Height: | Size: 729 B |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.6 KiB |
@@ -1,8 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Flutter View Controller-->
|
||||
@@ -14,13 +16,14 @@
|
||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="121" y="-34"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
|
||||
30
ios/Runner/GoogleService-Info.plist
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyDkCAxj9W1HNpi-bBdDH6lmid6WIlMsiO8</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>926568447136</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>vn.smatec.sfm</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>smart-fire-monitoring</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>smart-fire-monitoring.firebasestorage.app</string>
|
||||
<key>IS_ADS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_ANALYTICS_ENABLED</key>
|
||||
<false></false>
|
||||
<key>IS_APPINVITE_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_GCM_ENABLED</key>
|
||||
<true></true>
|
||||
<key>IS_SIGNIN_ENABLED</key>
|
||||
<true></true>
|
||||
<key>GOOGLE_APP_ID</key>
|
||||
<string>1:926568447136:ios:e14244264188362114ddc5</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Sfm App</string>
|
||||
<string>SmartFM</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -39,6 +39,7 @@
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>audio</string>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
@@ -60,5 +61,9 @@
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.gdelataillade.fetch</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
BIN
ios/Runner/Sounds/warning_alarm.caf
Normal file
BIN
ios/warning_alarm.caf
Normal file
@@ -4,7 +4,6 @@ import '../product/base/bloc/base_bloc.dart';
|
||||
import '../feature/bell/bell_model.dart';
|
||||
|
||||
class BellBloc extends BlocBase {
|
||||
|
||||
final bellItems = StreamController<List<BellItems>>.broadcast();
|
||||
StreamSink<List<BellItems>> get sinkBellItems => bellItems.sink;
|
||||
Stream<List<BellItems>> get streamBellItems => bellItems.stream;
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:sfm_app/product/services/api_services.dart';
|
||||
import 'package:sfm_app/product/utils/device_utils.dart';
|
||||
|
||||
import '../product/services/api_services.dart';
|
||||
import '../product/utils/date_time_utils.dart';
|
||||
import '../feature/device_log/device_logs_model.dart';
|
||||
import '../feature/devices/device_model.dart';
|
||||
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
import '../product/utils/device_utils.dart';
|
||||
|
||||
class DetailDeviceBloc extends BlocBase {
|
||||
APIServices apiServices = APIServices();
|
||||
@@ -42,14 +38,12 @@ class DetailDeviceBloc extends BlocBase {
|
||||
String thingID,
|
||||
Completer<GoogleMapController> controller,
|
||||
) async {
|
||||
String body = await apiServices.getDeviceInfomation(thingID);
|
||||
if (body != "") {
|
||||
final data = jsonDecode(body);
|
||||
Device device = Device.fromJson(data);
|
||||
await apiServices.execute(context, () async {
|
||||
Device device = await apiServices.getDeviceInformation(thingID);
|
||||
sinkDeviceInfo.add(device);
|
||||
if (device.areaPath != null) {
|
||||
String fullLocation = await DeviceUtils.instance
|
||||
.getFullDeviceLocation(context, device.areaPath!);
|
||||
.getFullDeviceLocation(context, device.areaPath!, "");
|
||||
log("Location: $fullLocation");
|
||||
sinkDeviceLocation.add(fullLocation);
|
||||
}
|
||||
@@ -74,20 +68,56 @@ class DetailDeviceBloc extends BlocBase {
|
||||
mapController
|
||||
.animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
|
||||
}
|
||||
}
|
||||
});
|
||||
// try {
|
||||
// Device device = await apiServices.getDeviceInformation(thingID);
|
||||
// sinkDeviceInfo.add(device);
|
||||
// if (device.areaPath != null) {
|
||||
// String fullLocation = await DeviceUtils.instance
|
||||
// .getFullDeviceLocation(context, device.areaPath!, "");
|
||||
// log("Location: $fullLocation");
|
||||
// sinkDeviceLocation.add(fullLocation);
|
||||
// }
|
||||
// Map<String, dynamic> sensorMap = {};
|
||||
// if (device.status!.sensors != null) {
|
||||
// sensorMap = DeviceUtils.instance
|
||||
// .getDeviceSensors(context, device.status!.sensors!);
|
||||
// } else {
|
||||
// sensorMap = DeviceUtils.instance.getDeviceSensors(context, []);
|
||||
// }
|
||||
// sinkDeviceSensor.add(sensorMap);
|
||||
// if (device.settings!.latitude! != "" &&
|
||||
// device.settings!.longitude! != "") {
|
||||
// final CameraPosition cameraPosition = CameraPosition(
|
||||
// target: LatLng(
|
||||
// double.parse(device.settings!.latitude!),
|
||||
// double.parse(device.settings!.longitude!),
|
||||
// ),
|
||||
// zoom: 13,
|
||||
// );
|
||||
// final GoogleMapController mapController = await controller.future;
|
||||
// mapController
|
||||
// .animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
|
||||
// }
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
void findLocation(BuildContext context, String areaPath) async {
|
||||
String fullLocation =
|
||||
await DeviceUtils.instance.getFullDeviceLocation(context, areaPath);
|
||||
await DeviceUtils.instance.getFullDeviceLocation(context, areaPath, "");
|
||||
sinkDeviceLocation.add(fullLocation);
|
||||
}
|
||||
|
||||
void getNearerSensorValue(String thingID) async {
|
||||
void getNearerSensorValue(BuildContext context, String thingID) async {
|
||||
apiServices.execute(context, () async {
|
||||
List<SensorLogs> sensorTemps = [];
|
||||
DateTime twoDaysAgo = DateTime.now().subtract(const Duration(days: 2));
|
||||
String from = DateTimeUtils.instance.formatDateTimeToString(twoDaysAgo);
|
||||
String now = DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
|
||||
String now =
|
||||
DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
|
||||
Map<String, dynamic> params = {
|
||||
'thing_id': thingID,
|
||||
'from': from,
|
||||
@@ -95,19 +125,46 @@ class DetailDeviceBloc extends BlocBase {
|
||||
'limit': '100',
|
||||
'n': '7',
|
||||
};
|
||||
final body = await apiServices.getLogsOfDevice(thingID, params);
|
||||
if (body != "") {
|
||||
final data = jsonDecode(body);
|
||||
DeviceLog devicesListLog = DeviceLog.fromJson(data);
|
||||
DeviceLog devicesListLog =
|
||||
await apiServices.getLogsOfDevice(thingID, params);
|
||||
if (devicesListLog.sensors!.isNotEmpty) {
|
||||
for (var sensor in devicesListLog.sensors!) {
|
||||
sensorTemps.add(sensor);
|
||||
}
|
||||
sensorTemps = sensorTemps.reversed.toList();
|
||||
sinkSensorTemps.add(sensorTemps);
|
||||
} else{
|
||||
} else {
|
||||
sinkSensorTemps.add([]);
|
||||
}
|
||||
}
|
||||
});
|
||||
// try {
|
||||
// List<SensorLogs> sensorTemps = [];
|
||||
// DateTime twoDaysAgo = DateTime.now().subtract(const Duration(days: 2));
|
||||
// String from = DateTimeUtils.instance.formatDateTimeToString(twoDaysAgo);
|
||||
// String now =
|
||||
// DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
|
||||
// Map<String, dynamic> params = {
|
||||
// 'thing_id': thingID,
|
||||
// 'from': from,
|
||||
// 'to': now,
|
||||
// 'limit': '100',
|
||||
// 'n': '7',
|
||||
// };
|
||||
// DeviceLog devicesListLog =
|
||||
// await apiServices.getLogsOfDevice(thingID, params);
|
||||
// if (devicesListLog.sensors!.isNotEmpty) {
|
||||
// for (var sensor in devicesListLog.sensors!) {
|
||||
// sensorTemps.add(sensor);
|
||||
// }
|
||||
// sensorTemps = sensorTemps.reversed.toList();
|
||||
// sinkSensorTemps.add(sensorTemps);
|
||||
// } else {
|
||||
// sinkSensorTemps.add([]);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// sinkSensorTemps.add([]);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../feature/devices/device_model.dart';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
import '../product/constant/app/app_constants.dart';
|
||||
import '../product/services/api_services.dart';
|
||||
import '../product/utils/date_time_utils.dart';
|
||||
|
||||
import '../product/utils/device_utils.dart';
|
||||
import '../feature/device_log/device_logs_model.dart';
|
||||
|
||||
@@ -35,28 +34,28 @@ class DeviceLogsBloc extends BlocBase {
|
||||
@override
|
||||
void dispose() {}
|
||||
|
||||
void getAllDevices() async {
|
||||
String body = await apiServices.getOwnerDevices();
|
||||
if (body != "") {
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data['items'];
|
||||
List<Device> originalDevices = Device.fromJsonDynamicList(items);
|
||||
void getAllDevices(BuildContext context) async {
|
||||
await apiServices.execute(context, () async {
|
||||
List<Device> originalDevices = await apiServices.getOwnerDevices();
|
||||
List<Device> devices =
|
||||
DeviceUtils.instance.sortDeviceByState(originalDevices);
|
||||
sinkAllDevices.add(devices);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void getDeviceLogByThingID(
|
||||
BuildContext context,
|
||||
int offset,
|
||||
String thingID,
|
||||
DateTime fromDate,
|
||||
List<SensorLogs> sensors,
|
||||
) async {
|
||||
await apiServices.execute(context, () async {
|
||||
sinkmessage.add(ApplicationConstants.LOADING);
|
||||
String fromDateString =
|
||||
DateTimeUtils.instance.formatDateTimeToString(fromDate);
|
||||
String now = DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
|
||||
String now =
|
||||
DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
|
||||
Map<String, dynamic> params = {
|
||||
'thing_id': thingID,
|
||||
'from': fromDateString,
|
||||
@@ -65,10 +64,8 @@ class DeviceLogsBloc extends BlocBase {
|
||||
"offset": offset.toString(),
|
||||
"asc": "true"
|
||||
};
|
||||
final body = await apiServices.getLogsOfDevice(thingID, params);
|
||||
if (body != "") {
|
||||
final data = jsonDecode(body);
|
||||
DeviceLog devicesListLog = DeviceLog.fromJson(data);
|
||||
DeviceLog devicesListLog =
|
||||
await apiServices.getLogsOfDevice(thingID, params);
|
||||
if (devicesListLog.sensors!.isEmpty) {
|
||||
bool hasMore = false;
|
||||
sinkHasMore.add(hasMore);
|
||||
@@ -81,6 +78,38 @@ class DeviceLogsBloc extends BlocBase {
|
||||
sinkmessage.add(ApplicationConstants.NO_DATA);
|
||||
}
|
||||
sinkSensors.add(sensors);
|
||||
}
|
||||
});
|
||||
// try {
|
||||
// sinkmessage.add(ApplicationConstants.LOADING);
|
||||
// String fromDateString =
|
||||
// DateTimeUtils.instance.formatDateTimeToString(fromDate);
|
||||
// String now =
|
||||
// DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
|
||||
// Map<String, dynamic> params = {
|
||||
// 'thing_id': thingID,
|
||||
// 'from': fromDateString,
|
||||
// 'to': now,
|
||||
// 'limit': '30',
|
||||
// "offset": offset.toString(),
|
||||
// "asc": "true"
|
||||
// };
|
||||
// DeviceLog devicesListLog =
|
||||
// await apiServices.getLogsOfDevice(thingID, params);
|
||||
// if (devicesListLog.sensors!.isEmpty) {
|
||||
// bool hasMore = false;
|
||||
// sinkHasMore.add(hasMore);
|
||||
// }
|
||||
// if (devicesListLog.sensors!.isNotEmpty) {
|
||||
// for (var sensor in devicesListLog.sensors!) {
|
||||
// sensors.add(sensor);
|
||||
// }
|
||||
// } else {
|
||||
// sinkmessage.add(ApplicationConstants.NO_DATA);
|
||||
// }
|
||||
// sinkSensors.add(sensors);
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../feature/settings/device_notification_settings/device_notification_settings_model.dart';
|
||||
@@ -36,7 +35,6 @@ class DeviceNotificationSettingsBloc extends BlocBase {
|
||||
StreamSink<String> get sinkMessageChange => messageChange.sink;
|
||||
Stream<String> get streaMmessageChange => messageChange.stream;
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'dart:developer';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../product/services/api_services.dart';
|
||||
import '../product/services/language_services.dart';
|
||||
import '../product/shared/model/ward_model.dart';
|
||||
import '../product/shared/shared_snack_bar.dart';
|
||||
import '../product/utils/response_status_utils.dart';
|
||||
|
||||
import '../product/shared/model/district_model.dart';
|
||||
import '../product/shared/model/province_model.dart';
|
||||
import '../feature/devices/device_model.dart';
|
||||
@@ -75,151 +75,281 @@ class DeviceUpdateBloc extends BlocBase {
|
||||
// deviceInfo.done;
|
||||
}
|
||||
|
||||
Future<void> getAllProvinces() async {
|
||||
Future<void> getAllProvinces(BuildContext context) async {
|
||||
List<DropdownMenuItem<Province>> provincesData = [];
|
||||
provincesData.clear();
|
||||
sinkListProvinces.add(provincesData);
|
||||
final body = await apiServices.getAllProvinces();
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data["items"];
|
||||
|
||||
final provinces = Province.fromJsonDynamicList(items);
|
||||
await apiServices.execute(context, () async {
|
||||
List<Province> provinces = await apiServices.getAllProvinces();
|
||||
for (var province in provinces) {
|
||||
provincesData.add(
|
||||
DropdownMenuItem(value: province, child: Text(province.fullName!)));
|
||||
}
|
||||
sinkListProvinces.add(provincesData);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getAllDistricts(String provinceID) async {
|
||||
Future<void> getAllDistricts(BuildContext context, String provinceID) async {
|
||||
List<DropdownMenuItem<District>> districtsData = [];
|
||||
districtsData.clear();
|
||||
sinkListDistricts.add(districtsData);
|
||||
final body = await apiServices.getAllDistricts(provinceID);
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data["items"];
|
||||
final districts = District.fromJsonDynamicList(items);
|
||||
await apiServices.execute(context, () async {
|
||||
final districts = await apiServices.getAllDistricts(provinceID);
|
||||
for (var district in districts) {
|
||||
districtsData.add(
|
||||
DropdownMenuItem(value: district, child: Text(district.fullName!)));
|
||||
}
|
||||
sinkListDistricts.add(districtsData);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getAllWards(String districtID) async {
|
||||
Future<void> getAllWards(BuildContext context, String districtID) async {
|
||||
List<DropdownMenuItem<Ward>> wardsData = [];
|
||||
wardsData.clear();
|
||||
sinkListWards.add(wardsData);
|
||||
final body = await apiServices.getAllWards(districtID);
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data["items"];
|
||||
final wards = Ward.fromJsonDynamicList(items);
|
||||
await apiServices.execute(context, () async {
|
||||
final wards = await apiServices.getAllWards(districtID);
|
||||
for (var ward in wards) {
|
||||
wardsData.add(DropdownMenuItem(value: ward, child: Text(ward.fullName!)));
|
||||
wardsData
|
||||
.add(DropdownMenuItem(value: ward, child: Text(ward.fullName!)));
|
||||
}
|
||||
sinkListWards.add(wardsData);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> getDeviceInfomation(
|
||||
Future<void> getDeviceInformation(
|
||||
BuildContext context,
|
||||
String thingID,
|
||||
List<DropdownMenuItem<District>> districtsData,
|
||||
List<DropdownMenuItem<Ward>> wardsData,
|
||||
TextEditingController deviceNameController,
|
||||
TextEditingController latitudeController,
|
||||
TextEditingController longitudeController) async {
|
||||
String body = await apiServices.getDeviceInfomation(thingID);
|
||||
final data = jsonDecode(body);
|
||||
Device device = Device.fromJson(data);
|
||||
await apiServices.execute(context, () async {
|
||||
Device device = await apiServices.getDeviceInformation(thingID);
|
||||
sinkDeviceInfo.add(device);
|
||||
deviceNameController.text = device.name ?? "";
|
||||
latitudeController.text = device.settings!.latitude ?? "";
|
||||
longitudeController.text = device.settings!.longitude ?? "";
|
||||
if (device.areaPath != "") {
|
||||
|
||||
if (device.areaPath != null && device.areaPath!.isNotEmpty) {
|
||||
List<String> areaPath = device.areaPath!.split('_');
|
||||
|
||||
// Kiểm tra độ dài của areaPath
|
||||
if (areaPath.length >= 3) {
|
||||
String provinceCode = areaPath[0];
|
||||
String districtCode = areaPath[1];
|
||||
String wardCode = areaPath[2];
|
||||
getAllDistricts(provinceCode);
|
||||
getAllWards(districtCode);
|
||||
final provinceResponse = await apiServices.getProvinceByID(provinceCode);
|
||||
final provincesData = jsonDecode(provinceResponse);
|
||||
Province province = Province.fromJson(provincesData['data']);
|
||||
final districtResponse = await apiServices.getDistrictByID(districtCode);
|
||||
final districtData = jsonDecode(districtResponse);
|
||||
District district = District.fromJson(districtData['data']);
|
||||
final wardResponse = await apiServices.getWardByID(wardCode);
|
||||
final wardData = jsonDecode(wardResponse);
|
||||
Ward ward = Ward.fromJson(wardData['data']);
|
||||
|
||||
// Kiểm tra các mã có hợp lệ không (không rỗng)
|
||||
if (provinceCode.isNotEmpty &&
|
||||
districtCode.isNotEmpty &&
|
||||
wardCode.isNotEmpty) {
|
||||
try {
|
||||
// Lấy danh sách districts và wards
|
||||
await getAllDistricts(context, provinceCode);
|
||||
await getAllWards(context, districtCode);
|
||||
|
||||
// Xử lý Province
|
||||
try {
|
||||
Province province =
|
||||
await apiServices.getProvinceByID(provinceCode);
|
||||
Map<String, String> provinceData = {
|
||||
"name": province.fullName!,
|
||||
"code": province.code!
|
||||
"name": province.fullName ?? "Unknown Province",
|
||||
"code": province.code ?? provinceCode
|
||||
};
|
||||
sinkProvinceData.add(provinceData);
|
||||
} catch (e) {
|
||||
// Thêm dữ liệu mặc định khi lỗi
|
||||
Map<String, String> provinceData = {
|
||||
"name": "Error Loading Province",
|
||||
"code": provinceCode
|
||||
};
|
||||
sinkProvinceData.add(provinceData);
|
||||
if (!context.mounted) return;
|
||||
showErrorTopSnackBarCustom(context, e.toString());
|
||||
}
|
||||
|
||||
// Xử lý District
|
||||
try {
|
||||
District district =
|
||||
await apiServices.getDistrictByID(districtCode);
|
||||
Map<String, String> districData = {
|
||||
"name": district.fullName!,
|
||||
"code": district.code!,
|
||||
"name": district.fullName ?? "Unknown District",
|
||||
"code": district.code ?? districtCode,
|
||||
};
|
||||
sinkDistrictData.add(districData);
|
||||
} catch (e) {
|
||||
log("Lỗi khi lấy thông tin district ($districtCode): $e");
|
||||
Map<String, String> districData = {
|
||||
"name": "Error Loading District",
|
||||
"code": districtCode,
|
||||
};
|
||||
sinkDistrictData.add(districData);
|
||||
}
|
||||
|
||||
// Xử lý Ward
|
||||
try {
|
||||
Ward ward = await apiServices.getWardByID(wardCode);
|
||||
Map<String, String> wardMap = {
|
||||
"name": ward.fullName!,
|
||||
"code": ward.code!,
|
||||
"name": ward.fullName ?? "Unknown Ward",
|
||||
"code": ward.code ?? wardCode,
|
||||
};
|
||||
sinkWardData.add(wardMap);
|
||||
} catch (e) {
|
||||
log("Lỗi khi lấy thông tin ward ($wardCode): $e");
|
||||
Map<String, String> wardMap = {
|
||||
"name": "Error Loading Ward",
|
||||
"code": wardCode,
|
||||
};
|
||||
sinkWardData.add(wardMap);
|
||||
}
|
||||
} catch (e) {
|
||||
log("Lỗi khi gọi getAllDistricts hoặc getAllWards: $e");
|
||||
}
|
||||
} else {
|
||||
await getAllProvinces(context);
|
||||
log("Một hoặc nhiều mã địa phương trống: Province: $provinceCode, District: $districtCode, Ward: $wardCode");
|
||||
}
|
||||
} else {
|
||||
showNoIconTopSnackBar(
|
||||
context,
|
||||
"AreaPath không đủ thông tin: ${device.areaPath}",
|
||||
Colors.orangeAccent,
|
||||
Colors.white);
|
||||
}
|
||||
}
|
||||
});
|
||||
// try {
|
||||
// Device device = await apiServices.getDeviceInformation(thingID);
|
||||
// sinkDeviceInfo.add(device);
|
||||
// deviceNameController.text = device.name ?? "";
|
||||
// latitudeController.text = device.settings!.latitude ?? "";
|
||||
// longitudeController.text = device.settings!.longitude ?? "";
|
||||
|
||||
// if (device.areaPath != null && device.areaPath!.isNotEmpty) {
|
||||
// List<String> areaPath = device.areaPath!.split('_');
|
||||
|
||||
// // Kiểm tra độ dài của areaPath
|
||||
// if (areaPath.length >= 3) {
|
||||
// String provinceCode = areaPath[0];
|
||||
// String districtCode = areaPath[1];
|
||||
// String wardCode = areaPath[2];
|
||||
|
||||
// // Kiểm tra các mã có hợp lệ không (không rỗng)
|
||||
// if (provinceCode.isNotEmpty &&
|
||||
// districtCode.isNotEmpty &&
|
||||
// wardCode.isNotEmpty) {
|
||||
// try {
|
||||
// // Lấy danh sách districts và wards
|
||||
// await getAllDistricts(context, provinceCode);
|
||||
// await getAllWards(context, districtCode);
|
||||
|
||||
// // Xử lý Province
|
||||
// try {
|
||||
// Province province =
|
||||
// await apiServices.getProvinceByID(provinceCode);
|
||||
// Map<String, String> provinceData = {
|
||||
// "name": province.fullName ?? "Unknown Province",
|
||||
// "code": province.code ?? provinceCode
|
||||
// };
|
||||
// sinkProvinceData.add(provinceData);
|
||||
// } catch (e) {
|
||||
// // Thêm dữ liệu mặc định khi lỗi
|
||||
// Map<String, String> provinceData = {
|
||||
// "name": "Error Loading Province",
|
||||
// "code": provinceCode
|
||||
// };
|
||||
// sinkProvinceData.add(provinceData);
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
|
||||
// // Xử lý District
|
||||
// try {
|
||||
// District district =
|
||||
// await apiServices.getDistrictByID(districtCode);
|
||||
// Map<String, String> districData = {
|
||||
// "name": district.fullName ?? "Unknown District",
|
||||
// "code": district.code ?? districtCode,
|
||||
// };
|
||||
// sinkDistrictData.add(districData);
|
||||
// } catch (e) {
|
||||
// log("Lỗi khi lấy thông tin district ($districtCode): $e");
|
||||
// Map<String, String> districData = {
|
||||
// "name": "Error Loading District",
|
||||
// "code": districtCode,
|
||||
// };
|
||||
// sinkDistrictData.add(districData);
|
||||
// }
|
||||
|
||||
// // Xử lý Ward
|
||||
// try {
|
||||
// Ward ward = await apiServices.getWardByID(wardCode);
|
||||
// Map<String, String> wardMap = {
|
||||
// "name": ward.fullName ?? "Unknown Ward",
|
||||
// "code": ward.code ?? wardCode,
|
||||
// };
|
||||
// sinkWardData.add(wardMap);
|
||||
// } catch (e) {
|
||||
// print("Lỗi khi lấy thông tin ward ($wardCode): $e");
|
||||
// Map<String, String> wardMap = {
|
||||
// "name": "Error Loading Ward",
|
||||
// "code": wardCode,
|
||||
// };
|
||||
// sinkWardData.add(wardMap);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// print("Lỗi khi gọi getAllDistricts hoặc getAllWards: $e");
|
||||
// }
|
||||
// } else {
|
||||
// await getAllProvinces(context);
|
||||
// print(
|
||||
// "Một hoặc nhiều mã địa phương trống: Province: $provinceCode, District: $districtCode, Ward: $wardCode");
|
||||
// }
|
||||
// } else {
|
||||
// showNoIconTopSnackBar(
|
||||
// context,
|
||||
// "AreaPath không đủ thông tin: ${device.areaPath}",
|
||||
// Colors.orangeAccent,
|
||||
// Colors.white);
|
||||
// }
|
||||
// }
|
||||
// } catch (e) {
|
||||
// showNoIconTopSnackBar(context, "Lỗi trong getDeviceInfomation: $e",
|
||||
// Colors.orangeAccent, Colors.white);
|
||||
// }
|
||||
}
|
||||
|
||||
Future<Province> getProvinceByName(String name) async {
|
||||
final response = await apiServices.getProvincesByName(name);
|
||||
final data = jsonDecode(response);
|
||||
if (data != null &&
|
||||
data.containsKey('items') &&
|
||||
data['items'] != null &&
|
||||
data['items'].isNotEmpty) {
|
||||
List<dynamic> items = data['items'];
|
||||
List<Province> provinces = Province.fromJsonDynamicList(items);
|
||||
Future<Province> getProvinceByName(BuildContext context, String name) async {
|
||||
return await apiServices.execute(context, () async {
|
||||
List<Province> provinces = await apiServices.getProvincesByName(name);
|
||||
if (provinces.isNotEmpty) {
|
||||
return provinces[0];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Province(name: "null");
|
||||
}
|
||||
|
||||
Future<District> getDistrictByName(String name, String provinceCode) async {
|
||||
final response = await apiServices.getDistrictsByName(name);
|
||||
if (response != "") {
|
||||
final data = jsonDecode(response);
|
||||
List<dynamic> items = data['items'];
|
||||
if (items.isNotEmpty) {
|
||||
List<District> districts = District.fromJsonDynamicList(items);
|
||||
if (districts.isNotEmpty) {
|
||||
for (var district in districts) {
|
||||
if (district.provinceCode == provinceCode) {
|
||||
return district;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return District(name: "null");
|
||||
});
|
||||
}
|
||||
|
||||
Future<Ward> getWardByName(String name, String districtCode) async {
|
||||
final response = await apiServices.getWarsdByName(name);
|
||||
final data = jsonDecode(response);
|
||||
if (data != null && data['items'] != null) {
|
||||
List<dynamic> items = data['items'];
|
||||
if (items.isNotEmpty) {
|
||||
List<Ward> wards = Ward.fromJsonDynamicList(items);
|
||||
if (wards.isNotEmpty) {
|
||||
for (var ward in wards) {
|
||||
if (ward.districtCode == districtCode) {
|
||||
return ward;
|
||||
Future<District> getDistrictByName(
|
||||
BuildContext context, String name, String provinceCode) async {
|
||||
return apiServices.execute(context, () async {
|
||||
final districts = await apiServices.getDistrictsByName(name);
|
||||
return districts.firstWhere(
|
||||
(district) => district.provinceCode == provinceCode,
|
||||
orElse: () => District(name: "null"),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ward(name: "null");
|
||||
|
||||
Future<Ward> getWardByName(
|
||||
BuildContext context, String name, String districtCode) async {
|
||||
return apiServices.execute(context, () async {
|
||||
final wards = await apiServices.getWardsByName(name);
|
||||
return wards.firstWhere(
|
||||
(ward) => ward.districtCode == districtCode,
|
||||
orElse: () => Ward(name: "null"),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> updateDevice(
|
||||
@@ -232,6 +362,7 @@ class DeviceUpdateBloc extends BlocBase {
|
||||
String districtCode,
|
||||
String wardCode,
|
||||
) async {
|
||||
await apiServices.execute(context, () async {
|
||||
DateTime dateTime = DateTime.now();
|
||||
String formattedDateTime =
|
||||
DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
|
||||
@@ -251,5 +382,30 @@ class DeviceUpdateBloc extends BlocBase {
|
||||
appLocalization(context).notification_update_device_success,
|
||||
appLocalization(context).notification_update_device_failed,
|
||||
);
|
||||
});
|
||||
// try {
|
||||
// DateTime dateTime = DateTime.now();
|
||||
// String formattedDateTime =
|
||||
// DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
|
||||
// Map<String, dynamic> body = {
|
||||
// "name": name,
|
||||
// "area_province": provinceCode,
|
||||
// "area_district": districtCode,
|
||||
// "area_ward": wardCode,
|
||||
// "latitude": latitude,
|
||||
// "longitude": longitude,
|
||||
// "note": "User updated device infomation at $formattedDateTime",
|
||||
// };
|
||||
// int statusCode = await apiServices.updateOwnerDevice(thingID, body);
|
||||
// showSnackBarResponseByStatusCodeNoIcon(
|
||||
// context,
|
||||
// statusCode,
|
||||
// appLocalization(context).notification_update_device_success,
|
||||
// appLocalization(context).notification_update_device_failed,
|
||||
// );
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import '../feature/devices/device_model.dart';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
import '../product/constant/app/app_constants.dart';
|
||||
import '../product/services/api_services.dart';
|
||||
|
||||
import '../product/shared/shared_snack_bar.dart';
|
||||
import '../product/utils/device_utils.dart';
|
||||
|
||||
class DevicesManagerBloc extends BlocBase {
|
||||
@@ -73,7 +73,8 @@ class DevicesManagerBloc extends BlocBase {
|
||||
// }
|
||||
// }
|
||||
|
||||
void getDeviceByState(int state) async {
|
||||
void getDeviceByState(BuildContext context, int state) async {
|
||||
try {
|
||||
sinkTagStates.add([state]);
|
||||
|
||||
Map<String, List<Device>> deviceByState = {
|
||||
@@ -85,34 +86,38 @@ class DevicesManagerBloc extends BlocBase {
|
||||
};
|
||||
|
||||
List<Device> devices = [];
|
||||
String body;
|
||||
|
||||
List<Device> originalDevices = [];
|
||||
if (state != -2) {
|
||||
body =
|
||||
await apiServices.getOwnerDeviceByState({"state": state.toString()});
|
||||
originalDevices = await apiServices
|
||||
.getOwnerDeviceByState({"state": state.toString()});
|
||||
} else {
|
||||
body = await apiServices.getOwnerDevices();
|
||||
originalDevices = await apiServices.getOwnerDevices();
|
||||
}
|
||||
|
||||
if (body.isNotEmpty) {
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data['items'];
|
||||
List<Device> originalDevices = Device.fromJsonDynamicList(items);
|
||||
List<Device> publicDevices = [];
|
||||
|
||||
for (var device in originalDevices) {
|
||||
if (device.visibility == "PUBLIC") {
|
||||
publicDevices.add(device);
|
||||
}
|
||||
}
|
||||
devices = (state != -2)
|
||||
? DeviceUtils.instance.sortDeviceAZByName(originalDevices)
|
||||
: DeviceUtils.instance.sortDeviceByState(originalDevices);
|
||||
? DeviceUtils.instance.sortDeviceAZByName(publicDevices)
|
||||
: DeviceUtils.instance.sortDeviceByState(publicDevices);
|
||||
|
||||
if (state == -2) {
|
||||
for (var device in originalDevices) {
|
||||
for (var device in publicDevices) {
|
||||
String stateKey = _getStateKey(device.state!);
|
||||
deviceByState[stateKey]!.add(device);
|
||||
}
|
||||
sinkDeviceByState.add(deviceByState);
|
||||
}
|
||||
}
|
||||
|
||||
sinkAllDevices.add(devices);
|
||||
} catch (e) {
|
||||
if (!context.mounted) return;
|
||||
showErrorTopSnackBarCustom(context, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
String _getStateKey(int state) {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import '../feature/devices/device_model.dart';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
import '../product/services/api_services.dart';
|
||||
import '../product/services/language_services.dart';
|
||||
import '../product/utils/response_status_utils.dart';
|
||||
|
||||
import '../feature/inter_family/group_detail/group_detail_model.dart';
|
||||
|
||||
class DetailGroupBloc extends BlocBase {
|
||||
@@ -29,12 +27,10 @@ class DetailGroupBloc extends BlocBase {
|
||||
@override
|
||||
void dispose() {}
|
||||
|
||||
Future<void> getGroupDetail(String groupID) async {
|
||||
final body = await apiServices.getGroupDetail(groupID);
|
||||
final data = jsonDecode(body);
|
||||
Future<void> getGroupDetail(BuildContext context, String groupID) async {
|
||||
await apiServices.execute(context, () async {
|
||||
List<DeviceOfGroup> warningDevices = [];
|
||||
if (data != null) {
|
||||
GroupDetail group = GroupDetail.fromJson(data);
|
||||
GroupDetail group = await apiServices.getGroupDetail(groupID);
|
||||
sinkDetailGroup.add(group);
|
||||
if (group.devices != null) {
|
||||
for (var device in group.devices!) {
|
||||
@@ -44,43 +40,104 @@ class DetailGroupBloc extends BlocBase {
|
||||
}
|
||||
sinkWarningDevice.add(warningDevices);
|
||||
}
|
||||
}
|
||||
});
|
||||
// try {
|
||||
// List<DeviceOfGroup> warningDevices = [];
|
||||
// GroupDetail group = await apiServices.getGroupDetail(groupID);
|
||||
// sinkDetailGroup.add(group);
|
||||
// if (group.devices != null) {
|
||||
// for (var device in group.devices!) {
|
||||
// if (device.state == 1) {
|
||||
// warningDevices.add(device);
|
||||
// }
|
||||
// }
|
||||
// sinkWarningDevice.add(warningDevices);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future<void> approveUserToGroup(BuildContext context, String groupID,
|
||||
String userID, String userName) async {
|
||||
await apiServices.execute(context, () async {
|
||||
Map<String, dynamic> body = {"group_id": groupID, "user_id": userID};
|
||||
int statusCode = await apiServices.approveGroup(body);
|
||||
showSnackBarResponseByStatusCode(context, statusCode,
|
||||
"Đã duyệt $userName vào nhóm!", "Duyệt $userName thất bại!");
|
||||
});
|
||||
// try {
|
||||
// Map<String, dynamic> body = {"group_id": groupID, "user_id": userID};
|
||||
// int statusCode = await apiServices.approveGroup(body);
|
||||
// showSnackBarResponseByStatusCode(context, statusCode,
|
||||
// "Đã duyệt $userName vào nhóm!", "Duyệt $userName thất bại!");
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future<void> deleteOrUnapproveUser(BuildContext context, String groupID,
|
||||
String userID, String userName) async {
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
|
||||
showSnackBarResponseByStatusCode(context, statusCode,
|
||||
"Đã xóa người dùng $userName", "Xóa người dùng $userName thất bại");
|
||||
});
|
||||
// try {
|
||||
// int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
|
||||
// showSnackBarResponseByStatusCode(context, statusCode,
|
||||
// "Đã xóa người dùng $userName", "Xóa người dùng $userName thất bại");
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future<void> deleteDevice(BuildContext context, String groupID,
|
||||
String thingID, String deviceName) async {
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.deleteDeviceInGroup(groupID, thingID);
|
||||
showSnackBarResponseByStatusCode(context, statusCode,
|
||||
"Đã xóa thiết bị $deviceName", "Xóa thiết bị $deviceName thất bại");
|
||||
});
|
||||
// try {
|
||||
// int statusCode = await apiServices.deleteDeviceInGroup(groupID, thingID);
|
||||
// showSnackBarResponseByStatusCode(context, statusCode,
|
||||
// "Đã xóa thiết bị $deviceName", "Xóa thiết bị $deviceName thất bại");
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future<void> leaveGroup(
|
||||
BuildContext context, String groupID, String userID) async {
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_leave_group_success,
|
||||
appLocalization(context).notification_leave_group_failed);
|
||||
});
|
||||
// try {
|
||||
// int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
|
||||
// showSnackBarResponseByStatusCode(
|
||||
// context,
|
||||
// statusCode,
|
||||
// appLocalization(context).notification_leave_group_success,
|
||||
// appLocalization(context).notification_leave_group_failed);
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future<void> updateDeviceNameInGroup(
|
||||
BuildContext context, String thingID, String newAlias) async {
|
||||
await apiServices.execute(context, () async {
|
||||
Map<String, dynamic> body = {"thing_id": thingID, "alias": newAlias};
|
||||
int statusCode = await apiServices.updateDeviceAlias(body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
@@ -89,17 +146,29 @@ class DetailGroupBloc extends BlocBase {
|
||||
appLocalization(context).notification_update_device_success,
|
||||
appLocalization(context).notification_update_device_failed,
|
||||
);
|
||||
});
|
||||
// try {
|
||||
// Map<String, dynamic> body = {"thing_id": thingID, "alias": newAlias};
|
||||
// int statusCode = await apiServices.updateDeviceAlias(body);
|
||||
// showSnackBarResponseByStatusCode(
|
||||
// context,
|
||||
// statusCode,
|
||||
// appLocalization(context).notification_update_device_success,
|
||||
// appLocalization(context).notification_update_device_failed,
|
||||
// );
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
|
||||
Future<List<Device>> getOwnerDevices() async {
|
||||
List<Device> allDevices = [];
|
||||
String body = await apiServices.getOwnerDevices();
|
||||
if (body != "") {
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data['items'];
|
||||
allDevices = Device.fromJsonDynamicList(items);
|
||||
}
|
||||
return allDevices;
|
||||
Future<List<Device>> getOwnerDevices(BuildContext context) {
|
||||
return apiServices.execute(context, () async {
|
||||
final originalDevices = await apiServices.getOwnerDevices();
|
||||
return originalDevices
|
||||
.where((device) => device.visibility == "PUBLIC")
|
||||
.toList();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> addDeviceToGroup(
|
||||
@@ -107,6 +176,7 @@ class DetailGroupBloc extends BlocBase {
|
||||
Map<String, dynamic> body = {
|
||||
"thing_id": thingID,
|
||||
};
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.addDeviceToGroup(groupID, body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
@@ -114,5 +184,18 @@ class DetailGroupBloc extends BlocBase {
|
||||
appLocalization(context).notification_add_device_success,
|
||||
appLocalization(context).notification_add_device_failed,
|
||||
);
|
||||
});
|
||||
// try {
|
||||
// int statusCode = await apiServices.addDeviceToGroup(groupID, body);
|
||||
// showSnackBarResponseByStatusCode(
|
||||
// context,
|
||||
// statusCode,
|
||||
// appLocalization(context).notification_add_device_success,
|
||||
// appLocalization(context).notification_add_device_failed,
|
||||
// );
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,143 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../product/extension/context_extension.dart';
|
||||
import '../product/services/api_services.dart';
|
||||
import '../feature/home/device_alias_model.dart';
|
||||
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
import '../product/services/language_services.dart';
|
||||
import '../product/utils/device_utils.dart';
|
||||
|
||||
class HomeBloc extends BlocBase {
|
||||
APIServices apiServices = APIServices();
|
||||
|
||||
final allDevicesAliasMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast();
|
||||
StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasMap =>
|
||||
final allDevicesAliasMap =
|
||||
StreamController<Map<String, List<DeviceWithAlias>>?>.broadcast();
|
||||
StreamSink<Map<String, List<DeviceWithAlias>>?> get sinkAllDevicesAliasMap =>
|
||||
allDevicesAliasMap.sink;
|
||||
Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasMap =>
|
||||
Stream<Map<String, List<DeviceWithAlias>>?> get streamAllDevicesAliasMap =>
|
||||
allDevicesAliasMap.stream;
|
||||
|
||||
final allDevicesAliasJoinedMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast();
|
||||
StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasJoinedMap =>
|
||||
allDevicesAliasJoinedMap.sink;
|
||||
Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasJoinedMap =>
|
||||
allDevicesAliasJoinedMap.stream;
|
||||
// final allDevicesAliasJoinedMap =
|
||||
// StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
|
||||
// StreamSink<Map<String, List<DeviceWithAlias>>>
|
||||
// get sinkAllDevicesAliasJoinedMap => allDevicesAliasJoinedMap.sink;
|
||||
// Stream<Map<String, List<DeviceWithAlias>>>
|
||||
// get streamAllDevicesAliasJoinedMap => allDevicesAliasJoinedMap.stream;
|
||||
|
||||
final countNotification = StreamController<int>.broadcast();
|
||||
StreamSink<int> get sinkCountNotification => countNotification.sink;
|
||||
Stream<int> get streamCountNotification => countNotification.stream;
|
||||
|
||||
final hasJoinedDevice = StreamController<bool?>.broadcast();
|
||||
StreamSink<bool?> get sinkHasJoinedDevice => hasJoinedDevice.sink;
|
||||
Stream<bool?> get streamHasJoinedDevice => hasJoinedDevice.stream;
|
||||
|
||||
final ownerDevicesStatus =
|
||||
StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
|
||||
StreamSink<Map<String, List<DeviceWithAlias>>>
|
||||
get sinkOwnerDevicesStatus => ownerDevicesStatus.sink;
|
||||
StreamSink<Map<String, List<DeviceWithAlias>>> get sinkOwnerDevicesStatus =>
|
||||
ownerDevicesStatus.sink;
|
||||
Stream<Map<String, List<DeviceWithAlias>>> get streamOwnerDevicesStatus =>
|
||||
ownerDevicesStatus.stream;
|
||||
|
||||
|
||||
final aliasDevices = StreamController<List<DeviceWithAlias>?>.broadcast();
|
||||
StreamSink<List<DeviceWithAlias>?> get sinkAliasDevices => aliasDevices.sink;
|
||||
Stream<List<DeviceWithAlias>?> get streamAliasDevices => aliasDevices.stream;
|
||||
|
||||
void getOwnerAndJoinedDevices(BuildContext context) async {
|
||||
await apiServices.execute(context, () async {
|
||||
List<DeviceWithAlias> devices = await apiServices.getDashBoardDevices().handleApiError();
|
||||
List<DeviceWithAlias> publicDevices = [];
|
||||
for (var device in devices) {
|
||||
if (device.visibility == "PUBLIC") {
|
||||
publicDevices.add(device);
|
||||
}
|
||||
}
|
||||
// getDeviceStatusAliasMap(publicDevices);
|
||||
sinkAllDevicesAliasMap.add(null);
|
||||
sinkAliasDevices.add(publicDevices);
|
||||
if (!context.mounted) return;
|
||||
getOwnerDeviceState(context, publicDevices);
|
||||
});
|
||||
}
|
||||
void getOwnerDeviceState(BuildContext context,List<DeviceWithAlias> allDevices) async {
|
||||
// int notificationCount = 0;
|
||||
Map<String, List<DeviceWithAlias>> ownerDevicesStatus = {};
|
||||
|
||||
if (!context.mounted) return;
|
||||
sinkOwnerDevicesStatus.add(ownerDevicesStatus);
|
||||
|
||||
int count = 0;
|
||||
for (var device in allDevices) {
|
||||
// if (device.isOwner != true) continue;
|
||||
|
||||
if (!context.mounted) return;
|
||||
Map<String, dynamic> sensorMap = DeviceUtils.instance
|
||||
.getDeviceSensors(context, device.status?.sensors ?? []);
|
||||
|
||||
if (device.state == 1 || device.state == 3) {
|
||||
ownerDevicesStatus["state"] ??= [];
|
||||
ownerDevicesStatus["state"]!.add(device);
|
||||
if (!context.mounted) return;
|
||||
sinkOwnerDevicesStatus.add(ownerDevicesStatus);
|
||||
count++;
|
||||
}
|
||||
|
||||
final noDataMessage = appLocalization(context).no_data_message;
|
||||
if (sensorMap['sensorBattery'] != noDataMessage) {
|
||||
if (double.parse(sensorMap['sensorBattery']) <= 20) {
|
||||
ownerDevicesStatus['battery'] ??= [];
|
||||
ownerDevicesStatus['battery']!.add(device);
|
||||
if (!context.mounted) return;
|
||||
sinkOwnerDevicesStatus.add(ownerDevicesStatus);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
sinkCountNotification.add(count);
|
||||
}
|
||||
|
||||
void getDeviceStatusAliasMap(List<DeviceWithAlias> devices) {
|
||||
Map<String, List<DeviceWithAlias>> allDevicesAliasMap = {};
|
||||
for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) {
|
||||
allDevicesAliasMap[key] = [];
|
||||
}
|
||||
|
||||
for (DeviceWithAlias device in devices) {
|
||||
allDevicesAliasMap['all']!.add(device);
|
||||
if (device.state == 0 || device.state == 1) {
|
||||
allDevicesAliasMap['online']!.add(device);
|
||||
}
|
||||
if (device.state == -1) {
|
||||
allDevicesAliasMap['offline']!.add(device);
|
||||
}
|
||||
if (device.state == 1) {
|
||||
allDevicesAliasMap['warning']!.add(device);
|
||||
}
|
||||
if (device.state == -2) {
|
||||
allDevicesAliasMap['not-use']!.add(device);
|
||||
}
|
||||
|
||||
}
|
||||
sinkAllDevicesAliasMap.add(allDevicesAliasMap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {}
|
||||
void dispose() {
|
||||
allDevicesAliasMap.close();
|
||||
// allDevicesAliasJoinedMap.close();
|
||||
countNotification.close();
|
||||
hasJoinedDevice.close();
|
||||
ownerDevicesStatus.close();
|
||||
aliasDevices.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../product/constant/app/app_constants.dart';
|
||||
|
||||
import '../product/constant/app/app_constants.dart';
|
||||
import '../product/services/api_services.dart';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
import '../product/services/language_services.dart';
|
||||
@@ -35,43 +32,32 @@ class InterFamilyBloc extends BlocBase {
|
||||
@override
|
||||
void dispose() {}
|
||||
|
||||
void getAllGroup(String role) async {
|
||||
void getAllGroup(BuildContext context, String role) async {
|
||||
List<Group> groups = [];
|
||||
sinkCurrentGroups.add(groups);
|
||||
final body = await apiServices.getAllGroups();
|
||||
|
||||
if (body.isNotEmpty) {
|
||||
final data = jsonDecode(body);
|
||||
List<dynamic> items = data["items"];
|
||||
groups = Group.fromJsonDynamicList(items);
|
||||
await apiServices.execute(context, () async {
|
||||
groups = await apiServices.getAllGroups();
|
||||
groups = sortGroupByName(groups);
|
||||
|
||||
List<Group> currentGroups = groups.where(
|
||||
(group) {
|
||||
bool isPublic = group.visibility == "PUBLIC";
|
||||
|
||||
if (role == ApplicationConstants.OWNER_GROUP) {
|
||||
return group.isOwner == true && isPublic;
|
||||
}
|
||||
|
||||
if (role == ApplicationConstants.PARTICIPANT_GROUP) {
|
||||
return group.isOwner == null && isPublic;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
).toList();
|
||||
|
||||
sinkCurrentGroups.add(currentGroups);
|
||||
} else {
|
||||
log("Get groups from API failed");
|
||||
}
|
||||
log("Inter Family Role: $role");
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> createGroup(
|
||||
BuildContext context, String name, String description) async {
|
||||
APIServices apiServices = APIServices();
|
||||
await apiServices.execute(context, () async {
|
||||
Map<String, dynamic> body = {"name": name, "description": description};
|
||||
int? statusCode = await apiServices.createGroup(body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
@@ -79,10 +65,12 @@ class InterFamilyBloc extends BlocBase {
|
||||
statusCode,
|
||||
appLocalization(context).notification_add_group_success,
|
||||
appLocalization(context).notification_add_group_failed);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> changeGroupInfomation(BuildContext context, String groupID,
|
||||
Future<void> changeGroupInformation(BuildContext context, String groupID,
|
||||
String name, String description) async {
|
||||
await apiServices.execute(context, () async {
|
||||
Map<String, dynamic> body = {"name": name, "description": description};
|
||||
int statusCode = await apiServices.updateGroup(body, groupID);
|
||||
showSnackBarResponseByStatusCode(
|
||||
@@ -90,27 +78,32 @@ class InterFamilyBloc extends BlocBase {
|
||||
statusCode,
|
||||
appLocalization(context).notification_update_group_success,
|
||||
appLocalization(context).notification_update_group_failed);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> joinGroup(BuildContext context, String groupID) async {
|
||||
Map<String, dynamic> body = {
|
||||
"group_id": groupID,
|
||||
};
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.joinGroup(groupID, body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_join_request_group_success,
|
||||
appLocalization(context).notification_join_request_group_failed);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> deleteGroup(BuildContext context, String groupID) async {
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.deleteGroup(groupID);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_delete_group_success,
|
||||
appLocalization(context).notification_delete_group_failed);
|
||||
});
|
||||
}
|
||||
|
||||
List<Group> sortGroupByName(List<Group> groups) {
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import 'dart:async';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
|
||||
class LoginBloc extends BlocBase{
|
||||
|
||||
final loginRequest = StreamController<Map<String,dynamic>>.broadcast();
|
||||
StreamSink<Map<String,dynamic>> get sinkLoginRequest => loginRequest.sink;
|
||||
Stream<Map<String,dynamic>> get streamLoginRequest => loginRequest.stream;
|
||||
class LoginBloc extends BlocBase {
|
||||
final loginRequest = StreamController<Map<String, dynamic>>.broadcast();
|
||||
StreamSink<Map<String, dynamic>> get sinkLoginRequest => loginRequest.sink;
|
||||
Stream<Map<String, dynamic>> get streamLoginRequest => loginRequest.stream;
|
||||
|
||||
final isShowPassword = StreamController<bool>.broadcast();
|
||||
StreamSink<bool> get sinkIsShowPassword => isShowPassword.sink;
|
||||
Stream<bool> get streamIsShowPassword => isShowPassword.stream;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
}
|
||||
|
||||
void dispose() {}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'dart:developer';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../product/cache/local_manager.dart';
|
||||
import '../product/constant/app/api_path_constant.dart';
|
||||
import '../product/constant/enums/local_keys_enums.dart';
|
||||
import '../product/network/network_manager.dart';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
import '../product/services/api_services.dart';
|
||||
import '../feature/bell/bell_model.dart';
|
||||
@@ -36,9 +41,34 @@ class MainBloc extends BlocBase {
|
||||
@override
|
||||
void dispose() {}
|
||||
|
||||
void getUserProfile() async {
|
||||
String data = await apiServices.getUserDetail();
|
||||
User user = User.fromJson(jsonDecode(data));
|
||||
void getUserProfile(BuildContext context) async {
|
||||
await apiServices.execute(context, () async {
|
||||
User user = await apiServices.getUserDetail();
|
||||
sinkUserProfile.add(user);
|
||||
});
|
||||
}
|
||||
|
||||
getFCMTokenAndPresentations() async {
|
||||
String? firebaseAppToken = await FirebaseMessaging.instance.getToken();
|
||||
|
||||
if (firebaseAppToken != null) {
|
||||
log("FCM TOKEN: $firebaseAppToken");
|
||||
sendNotificationToken(firebaseAppToken);
|
||||
} else {
|
||||
log("FCM TOKEN: null");
|
||||
}
|
||||
}
|
||||
|
||||
Future<int> sendNotificationToken(String token) async {
|
||||
String uid = await getUID();
|
||||
Map<String, dynamic> body = {"user_id": uid, "app_token": token};
|
||||
int statusCode = await NetworkManager.instance!
|
||||
.updateDataInServer(APIPathConstants.NOTIFICATION_TOKEN_PATH, body);
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
Future<String> getUID() async {
|
||||
String uid = LocaleManager.instance.getStringValue(PreferencesKeys.UID);
|
||||
return uid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
import '../product/services/map_services.dart';
|
||||
import '../product/shared/shared_snack_bar.dart';
|
||||
import '../feature/devices/device_model.dart';
|
||||
@@ -75,6 +75,4 @@ class MapBloc extends BlocBase {
|
||||
context, "Không tìm thấy đường", Colors.orange, Colors.white);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import '../product/services/api_services.dart';
|
||||
import '../feature/settings/profile/profile_model.dart';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
|
||||
class SettingsBloc extends BlocBase {
|
||||
// Settings Screen
|
||||
APIServices apiServices = APIServices();
|
||||
final userProfile = StreamController<User>.broadcast();
|
||||
StreamSink<User> get sinkUserProfile => userProfile.sink;
|
||||
Stream<User> get streamUserProfile => userProfile.stream;
|
||||
|
||||
|
||||
// Profile Screen
|
||||
final isChangeProfileInfomation = StreamController<bool>.broadcast();
|
||||
StreamSink<bool> get sinkIsChangeProfileInfomation =>
|
||||
@@ -17,9 +19,13 @@ class SettingsBloc extends BlocBase {
|
||||
Stream<bool> get streamIsChangeProfileInfomation =>
|
||||
isChangeProfileInfomation.stream;
|
||||
|
||||
|
||||
void getUserProfile(BuildContext context) async {
|
||||
await apiServices.execute(context, () async {
|
||||
User user = await apiServices.getUserDetail();
|
||||
sinkUserProfile.add(user);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
}
|
||||
void dispose() {}
|
||||
}
|
||||
|
||||
34
lib/bloc/sim_data_bloc.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../product/services/api_services.dart';
|
||||
import '../feature/devices/device_model.dart';
|
||||
import '../product/base/bloc/base_bloc.dart';
|
||||
|
||||
class SimDataBloc extends BlocBase{
|
||||
|
||||
APIServices apiServices = APIServices();
|
||||
|
||||
final devices = StreamController<List<Device>>.broadcast();
|
||||
StreamSink<List<Device>> get sinkDevices => devices.sink;
|
||||
Stream<List<Device>> get streamDevices => devices.stream;
|
||||
|
||||
@override
|
||||
void dispose() {}
|
||||
|
||||
void getOwnerDevices(BuildContext context) async {
|
||||
await apiServices.execute(context, () async {
|
||||
List<Device> devices = [];
|
||||
devices = await apiServices.getOwnerDevices();
|
||||
|
||||
List<Device> publicDevices = [];
|
||||
for (var device in devices) {
|
||||
if (device.visibility == "PUBLIC") {
|
||||
publicDevices.add(device);
|
||||
}
|
||||
}
|
||||
sinkDevices.add(publicDevices);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../product/extension/context_extension.dart';
|
||||
|
||||
import '../../product/services/language_services.dart';
|
||||
import '../../bloc/bell_bloc.dart';
|
||||
import '../../product/base/bloc/base_bloc.dart';
|
||||
import '../../product/services/api_services.dart';
|
||||
import '../../product/shared/shared_component_loading_animation.dart';
|
||||
import '../../product/shared/shared_loading_animation.dart';
|
||||
import 'bell_model.dart';
|
||||
|
||||
class BellScreen extends StatefulWidget {
|
||||
@@ -56,11 +57,7 @@ class _BellScreenState extends State<BellScreen> {
|
||||
initialData: items,
|
||||
builder: (context, bellSnapshot) {
|
||||
return check
|
||||
? Center(
|
||||
child: CircularProgressIndicator(
|
||||
value: context.highValue,
|
||||
),
|
||||
)
|
||||
? const SharedLoadingAnimation()
|
||||
: bellSnapshot.data?.isEmpty ?? true
|
||||
? Center(
|
||||
child: Text(
|
||||
@@ -78,16 +75,8 @@ class _BellScreenState extends State<BellScreen> {
|
||||
if (index < bellSnapshot.data!.length) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
List<String> read = [];
|
||||
read.add(bellSnapshot.data![index].id!);
|
||||
int code = await apiServices
|
||||
.updateStatusOfNotification(read);
|
||||
if (code == 200) {
|
||||
read.clear();
|
||||
} else {
|
||||
read.clear();
|
||||
}
|
||||
refresh();
|
||||
readNotification(
|
||||
bellSnapshot.data![index].id!);
|
||||
},
|
||||
child: Column(
|
||||
children: [
|
||||
@@ -143,7 +132,7 @@ class _BellScreenState extends State<BellScreen> {
|
||||
builder: (context, hasMoreSnapshot) {
|
||||
return Center(
|
||||
child: hasMoreSnapshot.data ?? hasMore
|
||||
? const CircularProgressIndicator()
|
||||
? const SharedComponentLoadingAnimation()
|
||||
: Text(
|
||||
appLocalization(context)
|
||||
.bell_read_all,
|
||||
@@ -173,10 +162,20 @@ class _BellScreenState extends State<BellScreen> {
|
||||
getBellNotification(offset);
|
||||
}
|
||||
|
||||
void readNotification(String id) async {
|
||||
await apiServices.execute(context, () async {
|
||||
List<String> read = [];
|
||||
read.add(id);
|
||||
await apiServices.updateStatusOfNotification(read);
|
||||
read.clear();
|
||||
});
|
||||
refresh();
|
||||
}
|
||||
|
||||
Future<void> getBellNotification(int offset) async {
|
||||
apiServices.execute(context, () async {
|
||||
bell = await apiServices.getBellNotifications(
|
||||
offset.toString(), (offset + 20).toString());
|
||||
|
||||
if (bell.items!.isEmpty) {
|
||||
hasMore = false;
|
||||
bellBloc.sinkHasMore.add(hasMore);
|
||||
@@ -187,6 +186,7 @@ class _BellScreenState extends State<BellScreen> {
|
||||
}
|
||||
bellBloc.bellItems.add(items);
|
||||
check = false;
|
||||
});
|
||||
}
|
||||
|
||||
String timeAgo(BuildContext context, DateTime dateTime) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../product/shared/shared_component_loading_animation.dart';
|
||||
import '../../product/shared/shared_loading_animation.dart';
|
||||
import 'widgets/tag_widget.dart';
|
||||
import '../devices/device_model.dart';
|
||||
import '../../bloc/device_logs_bloc.dart';
|
||||
@@ -12,7 +15,6 @@ import '../../product/services/language_services.dart';
|
||||
import '../../product/shared/shared_snack_bar.dart';
|
||||
import '../../product/utils/date_time_utils.dart';
|
||||
import '../../product/utils/device_utils.dart';
|
||||
|
||||
import '../../product/base/bloc/base_bloc.dart';
|
||||
import 'device_logs_model.dart';
|
||||
|
||||
@@ -42,7 +44,7 @@ class _DeviceLogsScreenState extends State<DeviceLogsScreen> {
|
||||
() {
|
||||
if (controller.position.maxScrollExtent == controller.offset) {
|
||||
offset += 30;
|
||||
deviceLogsBloc.getDeviceLogByThingID(
|
||||
deviceLogsBloc.getDeviceLogByThingID(context,
|
||||
offset, thingID, dateTime!, sensors);
|
||||
}
|
||||
},
|
||||
@@ -63,11 +65,9 @@ class _DeviceLogsScreenState extends State<DeviceLogsScreen> {
|
||||
body: StreamBuilder<List<Device>>(
|
||||
stream: deviceLogsBloc.streamAllDevices,
|
||||
builder: (context, allDevicesSnapshot) {
|
||||
if (allDevicesSnapshot.data?[0].thingId == null) {
|
||||
deviceLogsBloc.getAllDevices();
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
if (allDevicesSnapshot.data == null) {
|
||||
deviceLogsBloc.getAllDevices(context);
|
||||
return const SharedLoadingAnimation();
|
||||
} else {
|
||||
return StreamBuilder<List<SensorLogs>>(
|
||||
stream: deviceLogsBloc.streamSensors,
|
||||
@@ -90,9 +90,7 @@ class _DeviceLogsScreenState extends State<DeviceLogsScreen> {
|
||||
hint: Text(
|
||||
appLocalization(context)
|
||||
.choose_device_dropdownButton,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
),
|
||||
style: context.responsiveBodySmall
|
||||
),
|
||||
items: allDevicesSnapshot.data?.isNotEmpty ?? false
|
||||
? allDevicesSnapshot.data!
|
||||
@@ -101,9 +99,7 @@ class _DeviceLogsScreenState extends State<DeviceLogsScreen> {
|
||||
value: device.thingId,
|
||||
child: Text(
|
||||
device.name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
),
|
||||
style: context.responsiveBodySmall
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -192,6 +188,7 @@ class _DeviceLogsScreenState extends State<DeviceLogsScreen> {
|
||||
);
|
||||
} else {
|
||||
deviceLogsBloc.getDeviceLogByThingID(
|
||||
context,
|
||||
offset,
|
||||
thingID,
|
||||
dateTime!,
|
||||
@@ -250,7 +247,7 @@ class _DeviceLogsScreenState extends State<DeviceLogsScreen> {
|
||||
return Center(
|
||||
child: hasMoreSnapshot.data ??
|
||||
hasMore
|
||||
? const CircularProgressIndicator()
|
||||
? const SharedComponentLoadingAnimation()
|
||||
: Text(
|
||||
appLocalization(context)
|
||||
.main_no_data),
|
||||
@@ -314,7 +311,7 @@ class _DeviceLogsScreenState extends State<DeviceLogsScreen> {
|
||||
deviceLogsBloc.sensors.add(sensors);
|
||||
hasMore = true;
|
||||
deviceLogsBloc.sinkHasMore.add(hasMore);
|
||||
deviceLogsBloc.getDeviceLogByThingID(offset, thingID, dateTime!, sensors);
|
||||
deviceLogsBloc.getDeviceLogByThingID(context,offset, thingID, dateTime!, sensors);
|
||||
}
|
||||
|
||||
Widget leadingList(SensorLogs sensor) {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:sfm_app/product/shared/shared_snack_bar.dart';
|
||||
|
||||
import '../../bloc/devices_manager_bloc.dart';
|
||||
import '../../product/shared/shared_snack_bar.dart';
|
||||
import '../../product/utils/response_status_utils.dart';
|
||||
import '../../product/constant/enums/role_enums.dart';
|
||||
import '../../product/services/api_services.dart';
|
||||
@@ -10,7 +12,8 @@ import '../../product/constant/icon/icon_constants.dart';
|
||||
import '../../product/extension/context_extension.dart';
|
||||
import '../../product/services/language_services.dart';
|
||||
|
||||
addNewDevice(BuildContext context, String role) async {
|
||||
addNewDevice(BuildContext context, String role,
|
||||
DevicesManagerBloc deviceManagerBloc) async {
|
||||
TextEditingController extIDController = TextEditingController(text: "");
|
||||
TextEditingController deviceNameController = TextEditingController(text: "");
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
@@ -25,8 +28,7 @@ addNewDevice(BuildContext context, String role) async {
|
||||
children: [
|
||||
Text(
|
||||
'${appLocalization(context).add_device_title}: ',
|
||||
style:
|
||||
const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: context.responsiveBodyLargeWithBold,
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.centerRight,
|
||||
@@ -77,7 +79,8 @@ addNewDevice(BuildContext context, String role) async {
|
||||
Colors.white);
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
} else {
|
||||
addDevices(context, role, extID, deviceName);
|
||||
addDevices(
|
||||
context, role, extID, deviceName, deviceManagerBloc);
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
}
|
||||
},
|
||||
@@ -90,11 +93,12 @@ addNewDevice(BuildContext context, String role) async {
|
||||
);
|
||||
}
|
||||
|
||||
void addDevices(
|
||||
BuildContext context, String role, String extID, String deviceName) async {
|
||||
void addDevices(BuildContext context, String role, String extID,
|
||||
String deviceName, DevicesManagerBloc deviceManagerBloc) async {
|
||||
APIServices apiServices = APIServices();
|
||||
Map<String, dynamic> body = {};
|
||||
if (role == RoleEnums.ADMIN.name) {
|
||||
await apiServices.execute(context,() async {
|
||||
body = {"ext_id": extID, "name": deviceName};
|
||||
int statusCode = await apiServices.createDeviceByAdmin(body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
@@ -102,7 +106,10 @@ void addDevices(
|
||||
statusCode,
|
||||
appLocalization(context).notification_create_device_success,
|
||||
appLocalization(context).notification_create_device_failed);
|
||||
deviceManagerBloc.getDeviceByState(context, -2);
|
||||
});
|
||||
} else {
|
||||
await apiServices.execute(context,() async {
|
||||
body = {"ext_id": extID};
|
||||
int statusCode = await apiServices.registerDevice(body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
@@ -110,5 +117,7 @@ void addDevices(
|
||||
statusCode,
|
||||
appLocalization(context).notification_add_device_success,
|
||||
appLocalization(context).notification_device_not_exist);
|
||||
deviceManagerBloc.getDeviceByState(context, -2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../bloc/devices_manager_bloc.dart';
|
||||
import '../../product/constant/enums/role_enums.dart';
|
||||
import '../../product/services/api_services.dart';
|
||||
@@ -47,20 +48,24 @@ deleteOrUnregisterDevice(BuildContext context, DevicesManagerBloc devicesBloc,
|
||||
Map<String, dynamic> body = {
|
||||
"ext_id": extID,
|
||||
};
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.unregisterDevice(body);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_delete_device_success,
|
||||
appLocalization(context).notification_delete_device_failed);
|
||||
devicesBloc.getDeviceByState(-2);
|
||||
devicesBloc.getDeviceByState(context, -2);
|
||||
});
|
||||
} else {
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.deleteDeviceByAdmin(extID);
|
||||
showSnackBarResponseByStatusCode(
|
||||
context,
|
||||
statusCode,
|
||||
appLocalization(context).notification_delete_device_success,
|
||||
appLocalization(context).notification_delete_device_failed);
|
||||
devicesBloc.getDeviceByState(-2);
|
||||
devicesBloc.getDeviceByState(context, -2);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:simple_ripple_animation/simple_ripple_animation.dart';
|
||||
import 'package:sfm_app/feature/device_log/device_logs_model.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
import '../../../product/shared/shared_component_loading_animation.dart';
|
||||
import '../../../product/constant/image/image_constants.dart';
|
||||
import '../../../product/shared/shared_line_chart.dart';
|
||||
import '../../../product/shared/shared_curve.dart';
|
||||
import '../../../product/shared/shared_loading_animation.dart';
|
||||
import '../../device_log/device_logs_model.dart';
|
||||
import '../device_model.dart';
|
||||
import '../../../product/base/bloc/base_bloc.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../bloc/device_detail_bloc.dart';
|
||||
|
||||
@@ -46,8 +47,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
|
||||
late DetailDeviceBloc detailDeviceBloc;
|
||||
Completer<GoogleMapController> controller = Completer();
|
||||
CameraPosition initialCamera =
|
||||
const CameraPosition(target: LatLng(20.966048511844402, 105.74977710843086), zoom: 15);
|
||||
CameraPosition initialCamera = const CameraPosition(
|
||||
target: LatLng(20.966048511844402, 105.74977710843086), zoom: 15);
|
||||
Timer? getDeviceDetailTimer;
|
||||
|
||||
@override
|
||||
@@ -68,6 +69,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
@override
|
||||
void dispose() {
|
||||
getDeviceDetailTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
BoxDecoration boxDecoration = BoxDecoration(
|
||||
@@ -84,20 +86,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
return StreamBuilder<Device>(
|
||||
stream: detailDeviceBloc.streamDeviceInfo,
|
||||
builder: (context, deviceSnapshot) {
|
||||
if (deviceSnapshot.data?.extId == null) {
|
||||
detailDeviceBloc.getDeviceDetail(
|
||||
context,
|
||||
widget.thingID,
|
||||
controller,
|
||||
);
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
} else {
|
||||
return StreamBuilder<Map<String, dynamic>>(
|
||||
stream: detailDeviceBloc.streamDeviceSensor,
|
||||
builder: (context, sensorSnapshot) {
|
||||
if (sensorSnapshot.data != null) {
|
||||
if (sensorSnapshot.data != null ) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(deviceSnapshot.data?.name ?? ""),
|
||||
@@ -118,32 +110,11 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Image.asset(
|
||||
ImageConstants.instance.getImage('smoke-detector'),
|
||||
ImageConstants.instance
|
||||
.getImage('smoke-detector'),
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
),
|
||||
// Center(
|
||||
// child: Container(
|
||||
// height: 50,
|
||||
// width: 400,
|
||||
// // color: Colors.blueAccent,
|
||||
// alignment: Alignment.centerRight,
|
||||
// margin: const EdgeInsets.fromLTRB(0, 0, 0, 50),
|
||||
// child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// children: [
|
||||
// const SizedBox(),
|
||||
// Text(
|
||||
// deviceSnapshot.data?.name ?? "",
|
||||
// style: const TextStyle(
|
||||
// fontSize: 25,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -156,13 +127,14 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
height: context.dynamicHeight(0.08),
|
||||
width: context.dynamicWidth(0.5),
|
||||
decoration: BoxDecoration(
|
||||
color: DeviceUtils.instance
|
||||
.getTableRowColor(context,deviceSnapshot.data?.state ?? 3),
|
||||
color: DeviceUtils.instance.getTableRowColor(
|
||||
context, deviceSnapshot.data?.state ?? 3),
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
),
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: context.mediumValue,
|
||||
@@ -170,17 +142,20 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
child: deviceSnapshot.data?.state == 1
|
||||
? RippleAnimation(
|
||||
color: Colors.red,
|
||||
delay: context.dynamicMilliSecondDuration(
|
||||
delay: context
|
||||
.dynamicMilliSecondDuration(
|
||||
800,
|
||||
),
|
||||
repeat: true,
|
||||
minRadius: 10,
|
||||
ripplesCount: 5,
|
||||
duration: context.dynamicMilliSecondDuration(
|
||||
duration: context
|
||||
.dynamicMilliSecondDuration(
|
||||
1800,
|
||||
),
|
||||
child: CircleAvatar(
|
||||
backgroundColor: Colors.transparent,
|
||||
backgroundColor:
|
||||
Colors.transparent,
|
||||
minRadius: context.mediumValue,
|
||||
maxRadius: context.mediumValue,
|
||||
backgroundImage: AssetImage(
|
||||
@@ -191,8 +166,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
),
|
||||
)
|
||||
: CircleAvatar(
|
||||
backgroundColor:
|
||||
DeviceUtils.instance.getTableRowColor(context,
|
||||
backgroundColor: DeviceUtils
|
||||
.instance
|
||||
.getTableRowColor(
|
||||
context,
|
||||
deviceSnapshot.data?.state ?? 3,
|
||||
),
|
||||
minRadius: context.mediumValue,
|
||||
@@ -237,19 +214,18 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
child: Padding(
|
||||
padding: context.paddingLow,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
appLocalization(context)
|
||||
.paginated_data_table_column_deviceSignal,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
style: context
|
||||
.responsiveBodyLargeWithBold),
|
||||
SizedBox(
|
||||
height: context.dynamicWidth(0.12),
|
||||
width: context.dynamicWidth(0.12),
|
||||
@@ -259,7 +235,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
sensorSnapshot.data!['sensorCsq'],
|
||||
),
|
||||
size: 30,
|
||||
color: DeviceUtils.instance.getSignalIconColor(
|
||||
color: DeviceUtils.instance
|
||||
.getSignalIconColor(
|
||||
context,
|
||||
sensorSnapshot.data!['sensorCsq'],
|
||||
),
|
||||
@@ -268,8 +245,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: context.dynamicHeight(0.09),
|
||||
@@ -277,9 +256,11 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
child: Text(
|
||||
sensorSnapshot.data!['sensorCsq'],
|
||||
style: TextStyle(
|
||||
color: DeviceUtils.instance.getSignalIconColor(
|
||||
color: DeviceUtils.instance
|
||||
.getSignalIconColor(
|
||||
context,
|
||||
sensorSnapshot.data!['sensorCsq'],
|
||||
sensorSnapshot
|
||||
.data!['sensorCsq'],
|
||||
),
|
||||
fontSize: 40,
|
||||
fontWeight: FontWeight.w900,
|
||||
@@ -299,10 +280,12 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
child: Padding(
|
||||
padding: context.paddingLow,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
appLocalization(context)
|
||||
@@ -316,14 +299,18 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
height: context.dynamicWidth(0.12),
|
||||
width: context.dynamicWidth(0.12),
|
||||
child: Image.asset(
|
||||
DeviceUtils.instance.getDeviceBatteryImg(
|
||||
DeviceUtils.instance
|
||||
.getDeviceBatteryImg(
|
||||
int.parse(
|
||||
sensorSnapshot.data!['sensorBattery'],
|
||||
sensorSnapshot
|
||||
.data!['sensorBattery'],
|
||||
),
|
||||
),
|
||||
color: DeviceUtils.instance.getDeviceBatteryColor(
|
||||
color: DeviceUtils.instance
|
||||
.getDeviceBatteryColor(
|
||||
int.parse(
|
||||
sensorSnapshot.data!['sensorBattery'],
|
||||
sensorSnapshot
|
||||
.data!['sensorBattery'],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -331,18 +318,23 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
height: context.dynamicHeight(0.09),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
sensorSnapshot.data!['sensorBattery'],
|
||||
sensorSnapshot
|
||||
.data!['sensorBattery'],
|
||||
style: TextStyle(
|
||||
color: DeviceUtils.instance.getDeviceBatteryColor(
|
||||
color: DeviceUtils.instance
|
||||
.getDeviceBatteryColor(
|
||||
int.parse(
|
||||
sensorSnapshot.data!['sensorBattery'],
|
||||
sensorSnapshot
|
||||
.data!['sensorBattery'],
|
||||
),
|
||||
),
|
||||
fontSize: 50,
|
||||
@@ -360,9 +352,11 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
child: Text(
|
||||
'%',
|
||||
style: TextStyle(
|
||||
color: DeviceUtils.instance.getDeviceBatteryColor(
|
||||
color: DeviceUtils.instance
|
||||
.getDeviceBatteryColor(
|
||||
int.parse(
|
||||
sensorSnapshot.data!['sensorBattery'],
|
||||
sensorSnapshot
|
||||
.data!['sensorBattery'],
|
||||
),
|
||||
),
|
||||
fontSize: 30,
|
||||
@@ -390,7 +384,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
appLocalization(context)
|
||||
@@ -405,9 +400,11 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
width: context.dynamicWidth(0.12),
|
||||
child: Image.asset(
|
||||
'assets/icons/temperature.png',
|
||||
color: DeviceUtils.instance.getDeviceTempColor(
|
||||
color: DeviceUtils.instance
|
||||
.getDeviceTempColor(
|
||||
int.parse(
|
||||
sensorSnapshot.data!['sensorTemp'],
|
||||
sensorSnapshot
|
||||
.data!['sensorTemp'],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -423,20 +420,28 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
width: double.infinity,
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.withValues(alpha: 0.3),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Colors.grey
|
||||
.withValues(alpha: 0.3),
|
||||
borderRadius:
|
||||
BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
LayoutBuilder(
|
||||
builder: (context, constraints) => Container(
|
||||
builder: (context, constraints) =>
|
||||
Container(
|
||||
width: constraints.maxWidth *
|
||||
(int.parse(sensorSnapshot.data!['sensorTemp']) / 75),
|
||||
(int.parse(sensorSnapshot
|
||||
.data!['sensorTemp']) /
|
||||
75),
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: DeviceUtils.instance.getDeviceTempColor(
|
||||
int.parse(sensorSnapshot.data!['sensorTemp']),
|
||||
color: DeviceUtils.instance
|
||||
.getDeviceTempColor(
|
||||
int.parse(sensorSnapshot
|
||||
.data!['sensorTemp']),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderRadius:
|
||||
BorderRadius.circular(10),
|
||||
),
|
||||
),
|
||||
)
|
||||
@@ -446,25 +451,26 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
height: 5,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"${sensorSnapshot.data!['sensorTemp']} °C",
|
||||
style: TextStyle(
|
||||
color: DeviceUtils.instance.getDeviceTempColor(
|
||||
color: DeviceUtils.instance
|
||||
.getDeviceTempColor(
|
||||
int.parse(
|
||||
sensorSnapshot.data!['sensorTemp'],
|
||||
sensorSnapshot
|
||||
.data!['sensorTemp'],
|
||||
),
|
||||
),
|
||||
fontSize: 30,
|
||||
fontWeight: FontWeight.w900,
|
||||
),
|
||||
),
|
||||
const Text(
|
||||
Text(
|
||||
"75 °C",
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
),
|
||||
style: context.responsiveBodyLarge
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -480,11 +486,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
appLocalization(context).paginated_data_table_column_devicePower,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
appLocalization(context)
|
||||
.paginated_data_table_column_devicePower,
|
||||
style: context.responsiveBodyLargeWithBold
|
||||
),
|
||||
SizedBox(
|
||||
height: context.dynamicWidth(0.12),
|
||||
@@ -504,12 +508,11 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
stream: detailDeviceBloc.streamSensorTemps,
|
||||
builder: (context, sensorTempsSnapshot) {
|
||||
if (sensorTempsSnapshot.data == null) {
|
||||
detailDeviceBloc.getNearerSensorValue(widget.thingID);
|
||||
detailDeviceBloc
|
||||
.getNearerSensorValue(context,widget.thingID);
|
||||
return const AspectRatio(
|
||||
aspectRatio: 3,
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
child: SharedComponentLoadingAnimation(),
|
||||
);
|
||||
} else if (sensorTempsSnapshot.data!.isEmpty) {
|
||||
return Center(
|
||||
@@ -523,7 +526,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
child: Container(
|
||||
margin: context.paddingLow,
|
||||
child: sharedLineChart(
|
||||
appLocalization(context).detail_device_volt_message,
|
||||
appLocalization(context)
|
||||
.detail_device_volt_message,
|
||||
sensorTempsSnapshot.data ?? [],
|
||||
),
|
||||
),
|
||||
@@ -550,33 +554,48 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
Radius.circular(15),
|
||||
),
|
||||
),
|
||||
child: deviceSnapshot.data!.settings!.latitude != ""
|
||||
child: deviceSnapshot
|
||||
.data!.settings!.latitude !=
|
||||
""
|
||||
? StreamBuilder<String>(
|
||||
stream: detailDeviceBloc.streamDeviceLocation,
|
||||
stream: detailDeviceBloc
|
||||
.streamDeviceLocation,
|
||||
builder: (context, locationSnapshot) {
|
||||
if (locationSnapshot.data == null) {
|
||||
detailDeviceBloc.findLocation(
|
||||
context, deviceSnapshot.data!.areaPath!);
|
||||
context,
|
||||
deviceSnapshot
|
||||
.data!.areaPath!);
|
||||
}
|
||||
return GoogleMap(
|
||||
initialCameraPosition: initialCamera,
|
||||
initialCameraPosition:
|
||||
initialCamera,
|
||||
mapType: MapType.normal,
|
||||
markers: {
|
||||
Marker(
|
||||
infoWindow: InfoWindow(
|
||||
title: locationSnapshot.data ?? "",
|
||||
title:
|
||||
locationSnapshot.data ??
|
||||
"",
|
||||
),
|
||||
markerId: MarkerId(deviceSnapshot.data!.thingId!),
|
||||
markerId: MarkerId(
|
||||
deviceSnapshot
|
||||
.data!.thingId!),
|
||||
position: LatLng(
|
||||
double.parse(
|
||||
deviceSnapshot.data!.settings!.latitude!),
|
||||
double.parse(
|
||||
deviceSnapshot.data!.settings!.longitude!),
|
||||
double.parse(deviceSnapshot
|
||||
.data!
|
||||
.settings!
|
||||
.latitude!),
|
||||
double.parse(deviceSnapshot
|
||||
.data!
|
||||
.settings!
|
||||
.longitude!),
|
||||
),
|
||||
),
|
||||
},
|
||||
onMapCreated: (mapcontroller) {
|
||||
controller.complete(mapcontroller);
|
||||
controller
|
||||
.complete(mapcontroller);
|
||||
},
|
||||
mapToolbarEnabled: false,
|
||||
zoomControlsEnabled: false,
|
||||
@@ -591,11 +610,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
),
|
||||
),
|
||||
Text(
|
||||
appLocalization(context).device_update_location,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
appLocalization(context)
|
||||
.device_update_location,
|
||||
style: context.responsiveBodyLargeWithBold
|
||||
)
|
||||
],
|
||||
),
|
||||
@@ -605,18 +622,26 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
detailDeviceBloc.getDeviceDetail(
|
||||
context,
|
||||
widget.thingID,
|
||||
controller,
|
||||
);
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
appBar: AppBar(),
|
||||
body: const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
child: SharedLoadingAnimation(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:search_choices/search_choices.dart';
|
||||
|
||||
import '../../../product/shared/shared_loading_animation.dart';
|
||||
import '../device_model.dart';
|
||||
import '../../../bloc/device_update_bloc.dart';
|
||||
import 'map_dialog.dart';
|
||||
@@ -8,7 +9,6 @@ import '../../../product/base/bloc/base_bloc.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/api_services.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import '../../../product/shared/model/district_model.dart';
|
||||
import '../../../product/shared/model/province_model.dart';
|
||||
import '../../../product/shared/model/ward_model.dart';
|
||||
@@ -47,7 +47,7 @@ class _DeviceUpdateScreenState extends State<DeviceUpdateScreen> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
deviceUpdateBloc = BlocProvider.of(context);
|
||||
deviceUpdateBloc.getAllProvinces();
|
||||
deviceUpdateBloc.getAllProvinces(context);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -72,16 +72,16 @@ class _DeviceUpdateScreenState extends State<DeviceUpdateScreen> {
|
||||
initialData: device,
|
||||
builder: (context, deviceInfoSnapshot) {
|
||||
if (deviceInfoSnapshot.data!.thingId == null) {
|
||||
deviceUpdateBloc.getDeviceInfomation(
|
||||
deviceUpdateBloc.getDeviceInformation(
|
||||
context,
|
||||
widget.thingID,
|
||||
districtsData,
|
||||
wardsData,
|
||||
// provincesData,
|
||||
// districtsData,
|
||||
// wardsData,
|
||||
deviceNameController,
|
||||
deviceLatitudeController,
|
||||
deviceLongitudeController);
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
return const SharedLoadingAnimation();
|
||||
} else {
|
||||
return StreamBuilder<bool>(
|
||||
stream: deviceUpdateBloc.streamIsChanged,
|
||||
@@ -245,7 +245,7 @@ class _DeviceUpdateScreenState extends State<DeviceUpdateScreen> {
|
||||
.sinkProvinceData
|
||||
.add(provinceData);
|
||||
deviceUpdateBloc
|
||||
.getAllDistricts(
|
||||
.getAllDistricts(context,
|
||||
value.code);
|
||||
selectedDistrict = "";
|
||||
districtData['name'] =
|
||||
@@ -318,7 +318,7 @@ class _DeviceUpdateScreenState extends State<DeviceUpdateScreen> {
|
||||
.sinkDistrictData
|
||||
.add(districtData);
|
||||
deviceUpdateBloc
|
||||
.getAllWards(value.code);
|
||||
.getAllWards(context,value.code);
|
||||
selectedWard = "";
|
||||
wardData['name'] =
|
||||
selectedWard!;
|
||||
|
||||
@@ -2,15 +2,14 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart' ;
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
import '../../../bloc/device_update_bloc.dart';
|
||||
import '../../../product/constant/app/app_constants.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/shared/find_location_maps/shared_map_search_location.dart';
|
||||
|
||||
import '../../../product/shared/find_location_maps/model/prediction_model.dart';
|
||||
import '../../../product/shared/shared_transition.dart';
|
||||
import 'geocode_model.dart';
|
||||
@@ -64,7 +63,8 @@ showMapDialog(
|
||||
String latitude = mapDialogLatitudeController.text;
|
||||
String longitude = mapDialogLongitudeController.text;
|
||||
log("Finish -- Latitude: $latitude, longitude: $longitude --");
|
||||
getDataFromApi(latitude, longitude, deviceUpdateBloc);
|
||||
getDataFromApi(
|
||||
context, latitude, longitude, deviceUpdateBloc);
|
||||
latitudeController.text =
|
||||
mapDialogLatitudeController.text;
|
||||
longitudeController.text =
|
||||
@@ -184,7 +184,7 @@ addMarker(
|
||||
updateCameraPosition(position, 14, mapController);
|
||||
}
|
||||
|
||||
void getDataFromApi(String latitude, String longitude,
|
||||
void getDataFromApi(BuildContext context, String latitude, String longitude,
|
||||
DeviceUpdateBloc deviceUpdateBloc) async {
|
||||
String path =
|
||||
"maps/api/geocode/json?latlng=$latitude,$longitude&language=vi&result_type=political&key=${ApplicationConstants.MAP_KEY}";
|
||||
@@ -215,7 +215,7 @@ void getDataFromApi(String latitude, String longitude,
|
||||
log("$key: $value");
|
||||
});
|
||||
|
||||
await _processLocations(locations, deviceUpdateBloc);
|
||||
await _processLocations(context, locations, deviceUpdateBloc);
|
||||
}
|
||||
|
||||
Map<String, String> _extractLocationComponents(
|
||||
@@ -241,31 +241,31 @@ Map<String, String> _extractLocationComponents(
|
||||
return locations;
|
||||
}
|
||||
|
||||
Future<void> _processLocations(
|
||||
Future<void> _processLocations(BuildContext context,
|
||||
Map<String, String> locations, DeviceUpdateBloc deviceUpdateBloc) async {
|
||||
String provinceNameFromAPI = locations['provincekey'] ?? "";
|
||||
String districtNameFromAPI = locations['districtkey'] ?? "";
|
||||
String wardNameFromAPI = locations['wardkey'] ?? "";
|
||||
|
||||
final province =
|
||||
await deviceUpdateBloc.getProvinceByName(provinceNameFromAPI);
|
||||
await deviceUpdateBloc.getProvinceByName(context, provinceNameFromAPI);
|
||||
if (province.name != "null") {
|
||||
log("Province: ${province.fullName}, ProvinceCode: ${province.code}");
|
||||
deviceUpdateBloc.sinkProvinceData
|
||||
.add({"code": province.code!, "name": province.fullName!});
|
||||
deviceUpdateBloc.getAllProvinces();
|
||||
deviceUpdateBloc.getAllProvinces(context);
|
||||
|
||||
final district = await deviceUpdateBloc.getDistrictByName(
|
||||
districtNameFromAPI, province.code!);
|
||||
context, districtNameFromAPI, province.code!);
|
||||
log("Districtname: ${district.fullName}, districtCode: ${district.code}");
|
||||
deviceUpdateBloc.getAllDistricts(province.code!);
|
||||
deviceUpdateBloc.getAllDistricts(context, province.code!);
|
||||
if (district.name != "null") {
|
||||
deviceUpdateBloc.sinkDistrictData
|
||||
.add({"code": district.code!, "name": district.fullName!});
|
||||
final ward =
|
||||
await deviceUpdateBloc.getWardByName(wardNameFromAPI, district.code!);
|
||||
final ward = await deviceUpdateBloc.getWardByName(
|
||||
context, wardNameFromAPI, district.code!);
|
||||
log("Wardname: ${ward.fullName}, WardCode: ${ward.code}");
|
||||
deviceUpdateBloc.getAllWards(district.code!);
|
||||
deviceUpdateBloc.getAllWards(context, district.code!);
|
||||
if (ward.name != "null") {
|
||||
log("Xac dinh duoc het thong tin tu toa do");
|
||||
deviceUpdateBloc.sinkWardData
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:data_table_2/data_table_2.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../product/shared/shared_component_loading_animation.dart';
|
||||
import '../../product/shared/shared_loading_animation.dart';
|
||||
import 'add_new_device_widget.dart';
|
||||
import 'delete_device_widget.dart';
|
||||
import 'device_model.dart';
|
||||
@@ -29,7 +31,7 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
late DevicesManagerBloc devicesManagerBloc;
|
||||
String role = "Undefine";
|
||||
APIServices apiServices = APIServices();
|
||||
List<Device> devices = [];
|
||||
// List<Device> devices = [];
|
||||
Timer? getAllDevicesTimer;
|
||||
List<Widget> tags = [];
|
||||
int tagIndex = -2;
|
||||
@@ -41,7 +43,7 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
const duration = Duration(seconds: 10);
|
||||
getAllDevicesTimer = Timer.periodic(
|
||||
duration,
|
||||
(Timer t) => devicesManagerBloc.getDeviceByState(tagIndex),
|
||||
(Timer t) => devicesManagerBloc.getDeviceByState(context,tagIndex),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -58,15 +60,43 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
body: StreamBuilder<List<int>>(
|
||||
stream: devicesManagerBloc.streamTagStates,
|
||||
builder: (context, tagSnapshot) {
|
||||
return StreamBuilder<String>(
|
||||
stream: devicesManagerBloc.streamUserRole,
|
||||
initialData: role,
|
||||
builder: (context, roleSnapshot) {
|
||||
return SafeArea(
|
||||
child: StreamBuilder<List<Device>>(
|
||||
stream: devicesManagerBloc.streamAllDevices,
|
||||
initialData: devices,
|
||||
builder: (context, allDeviceSnapshot) {
|
||||
if (allDeviceSnapshot.data?.isEmpty ?? devices.isEmpty) {
|
||||
if(allDeviceSnapshot.data == null){
|
||||
devicesManagerBloc
|
||||
.getDeviceByState(tagSnapshot.data?[0] ?? -2);
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
.getDeviceByState(context,tagSnapshot.data?[0] ?? -2);
|
||||
return const SharedLoadingAnimation();
|
||||
}
|
||||
if (allDeviceSnapshot.data!.isEmpty) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: 100,
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Theme.of(context).colorScheme.primary),
|
||||
borderRadius: BorderRadius.circular(50)
|
||||
),
|
||||
child: IconButton(onPressed: (){
|
||||
ScaffoldMessenger.of(context)
|
||||
.clearSnackBars();
|
||||
addNewDevice(context,
|
||||
roleSnapshot.data ?? role, devicesManagerBloc);
|
||||
}, iconSize: 50, icon: const Icon(Icons.add),),),
|
||||
SizedBox(height: context.mediumValue,),
|
||||
Text(appLocalization(context).dont_have_device, style: context.responsiveBodyMediumWithBold,)
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (tagSnapshot.data!.isNotEmpty) {
|
||||
tagIndex = tagSnapshot.data![0];
|
||||
@@ -83,11 +113,7 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
devicesManagerBloc: devicesManagerBloc,
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
StreamBuilder<String>(
|
||||
stream: devicesManagerBloc.streamUserRole,
|
||||
initialData: role,
|
||||
builder: (context, roleSnapshot) {
|
||||
return SizedBox(
|
||||
SizedBox(
|
||||
height: getTableHeight(allDeviceSnapshot.data?.length ?? 1),
|
||||
child: PaginatedDataTable2(
|
||||
wrapInCard: false,
|
||||
@@ -103,7 +129,7 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.paginated_data_table_title,
|
||||
style: context.headlineMediumTextStyle,
|
||||
style: context.responsiveBodyLargeWithBold,
|
||||
),
|
||||
),
|
||||
columns: [
|
||||
@@ -111,7 +137,8 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
RoleEnums.ADMIN.name ||
|
||||
roleSnapshot.data ==
|
||||
RoleEnums.USER.name)
|
||||
DataColumn(
|
||||
DataColumn2(
|
||||
fixedWidth: context.dynamicWidth(0.3),
|
||||
label: Text(appLocalization(context)
|
||||
.paginated_data_table_column_deviceName),
|
||||
),
|
||||
@@ -172,37 +199,31 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
ScaffoldMessenger.of(context)
|
||||
.clearSnackBars();
|
||||
addNewDevice(context,
|
||||
roleSnapshot.data ?? role);
|
||||
roleSnapshot.data ?? role, devicesManagerBloc);
|
||||
},
|
||||
icon: IconConstants.instance
|
||||
.getMaterialIcon(Icons.add))
|
||||
],
|
||||
source: DeviceSource(
|
||||
devices: allDeviceSnapshot.data ?? devices,
|
||||
devices: allDeviceSnapshot.data ?? [],
|
||||
context: context,
|
||||
devicesBloc: devicesManagerBloc,
|
||||
role: role,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
Text(
|
||||
appLocalization(context).overview_message,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: context.responsiveBodyLargeWithBold
|
||||
),
|
||||
StreamBuilder<Map<String, List<Device>>>(
|
||||
stream: devicesManagerBloc.streamDeviceByState,
|
||||
builder: (context, devicesByStateSnapshot) {
|
||||
if (devicesByStateSnapshot.data == null) {
|
||||
devicesManagerBloc.getDeviceByState(
|
||||
devicesManagerBloc.getDeviceByState(context,
|
||||
tagSnapshot.data?[0] ?? -2);
|
||||
return const Center(
|
||||
child: CircularProgressIndicator());
|
||||
return const SharedComponentLoadingAnimation();
|
||||
} else {
|
||||
return SharedPieChart(
|
||||
deviceByState:
|
||||
@@ -219,6 +240,8 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
@@ -230,7 +253,7 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
|
||||
|
||||
double getTableHeight(int dataLength){
|
||||
if(dataLength < 3){
|
||||
return context.dynamicHeight(0.3);
|
||||
return context.dynamicHeight(0.35);
|
||||
}else {
|
||||
return context.dynamicHeight(0.4);
|
||||
}
|
||||
@@ -370,7 +393,7 @@ class TagState extends StatelessWidget {
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
devicesManagerBloc.getDeviceByState(-2);
|
||||
devicesManagerBloc.getDeviceByState(context,-2);
|
||||
},
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:sfm_app/product/constant/enums/app_route_enums.dart';
|
||||
import 'package:sfm_app/product/constant/image/image_constants.dart';
|
||||
|
||||
import '../../product/constant/enums/app_route_enums.dart';
|
||||
import '../../product/constant/image/image_constants.dart';
|
||||
|
||||
class NotFoundScreen extends StatelessWidget {
|
||||
const NotFoundScreen({super.key});
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:alarm/alarm.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../product/shared/shared_loading_animation.dart';
|
||||
import '../../product/shared/shared_component_loading_animation.dart';
|
||||
import 'shared/alert_card.dart';
|
||||
import 'shared/warning_card.dart';
|
||||
import '../../product/utils/device_utils.dart';
|
||||
import 'device_alias_model.dart';
|
||||
import 'shared/overview_card.dart';
|
||||
import '../settings/device_notification_settings/device_notification_settings_model.dart';
|
||||
@@ -17,7 +18,6 @@ import '../../product/base/bloc/base_bloc.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
State<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
@@ -25,33 +25,54 @@ class HomeScreen extends StatefulWidget {
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
late HomeBloc homeBloc;
|
||||
APIServices apiServices = APIServices();
|
||||
Map<String, List<DeviceWithAlias>> allDevicesAliasMap = {};
|
||||
Map<String, List<DeviceWithAlias>> allDevicesAliasJoinedMap = {};
|
||||
List<DeviceWithAlias> devices = [];
|
||||
bool isFunctionCall = false;
|
||||
Timer? getAllDevicesTimer;
|
||||
int notificationCount = 0;
|
||||
Map<String, List<DeviceWithAlias>> ownerDevicesStatus = {};
|
||||
List<String> ownerDevicesState = [];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
homeBloc = BlocProvider.of(context);
|
||||
getOwnerAndJoinedDevices();
|
||||
const duration = Duration(seconds: 10);
|
||||
getAllDevicesTimer = Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices());
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// Code ở đây chạy sau khi giao diện render xong
|
||||
getAllDevicesTimer = Timer.periodic(
|
||||
duration, (Timer t) => homeBloc.getOwnerAndJoinedDevices(context));
|
||||
// Ví dụ: gọi API, scroll tới vị trí nào đó, v.v.
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> loadAlarms() async {
|
||||
final alarms = await Alarm.getAlarms();
|
||||
log("Alarms: $alarms");
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
getAllDevicesTimer?.cancel();
|
||||
homeBloc.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StreamBuilder<List<DeviceWithAlias>?>(
|
||||
stream: homeBloc.streamAliasDevices,
|
||||
builder: (context, aliasDevicesSnapshot) {
|
||||
if (aliasDevicesSnapshot.data == null) {
|
||||
homeBloc.getOwnerAndJoinedDevices(context);
|
||||
return const SharedLoadingAnimation();
|
||||
} else {
|
||||
homeBloc.getOwnerDeviceState(
|
||||
context, aliasDevicesSnapshot.data ?? []);
|
||||
homeBloc.getDeviceStatusAliasMap(aliasDevicesSnapshot.data ?? []);
|
||||
checkSettingDevice(aliasDevicesSnapshot.data ?? []);
|
||||
return Scaffold(
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () {
|
||||
loadAlarms();
|
||||
},
|
||||
child: const Icon(Icons.alarm),
|
||||
),
|
||||
body: Padding(
|
||||
padding: context.paddingLow,
|
||||
child: SingleChildScrollView(
|
||||
@@ -67,10 +88,16 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
StreamBuilder<int>(
|
||||
stream: homeBloc.streamCountNotification,
|
||||
builder: (context, countSnapshot) {
|
||||
if (countSnapshot.data == null) {
|
||||
homeBloc.getOwnerDeviceState(
|
||||
context, aliasDevicesSnapshot.data ?? []);
|
||||
return const Text("0");
|
||||
} else {
|
||||
return Text(
|
||||
"(${countSnapshot.data ?? 0})",
|
||||
style: context.titleMediumTextStyle,
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
@@ -78,46 +105,109 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
SizedBox(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: StreamBuilder<Map<String, List<DeviceWithAlias>>>(
|
||||
child:
|
||||
StreamBuilder<Map<String, List<DeviceWithAlias>>>(
|
||||
stream: homeBloc.streamOwnerDevicesStatus,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data?['state'] != null || snapshot.data?['battery'] != null) {
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: MediaQuery.of(context).size.width),
|
||||
builder: (context, ownerDevicesStatusSnapshot) {
|
||||
if (ownerDevicesStatusSnapshot.data == null) {
|
||||
homeBloc.getOwnerDeviceState(
|
||||
context, aliasDevicesSnapshot.data ?? []);
|
||||
return const SharedComponentLoadingAnimation();
|
||||
} else {
|
||||
return AnimatedSwitcher(
|
||||
duration: context.lowDuration,
|
||||
transitionBuilder: (Widget child,
|
||||
Animation<double> animation) {
|
||||
final offsetAnimation = Tween<Offset>(
|
||||
begin: const Offset(0.0, 0.2),
|
||||
end: Offset.zero,
|
||||
).animate(CurvedAnimation(
|
||||
parent: animation,
|
||||
curve: Curves.easeInOut,
|
||||
));
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: SlideTransition(
|
||||
position: offsetAnimation,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: ownerDevicesStatusSnapshot
|
||||
.data?['state'] !=
|
||||
null ||
|
||||
ownerDevicesStatusSnapshot
|
||||
.data?['battery'] !=
|
||||
null
|
||||
? ConstrainedBox(
|
||||
key: const ValueKey('data'),
|
||||
constraints: BoxConstraints(
|
||||
minWidth: MediaQuery.of(context)
|
||||
.size
|
||||
.width),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.start,
|
||||
children: [
|
||||
if (snapshot.data?['state'] != null)
|
||||
...snapshot.data!['state']!
|
||||
if (ownerDevicesStatusSnapshot
|
||||
.data?['state'] !=
|
||||
null)
|
||||
...ownerDevicesStatusSnapshot
|
||||
.data!['state']!
|
||||
.map(
|
||||
(item) => SizedBox(
|
||||
width: context.dynamicWidth(0.95),
|
||||
child: FutureBuilder<Widget>(
|
||||
future: warningCard(context, apiServices, item),
|
||||
builder: (context, warningCardSnapshot) {
|
||||
if (warningCardSnapshot.hasData) {
|
||||
return warningCardSnapshot.data!;
|
||||
width: context
|
||||
.dynamicWidth(0.95),
|
||||
child: FutureBuilder<
|
||||
Widget>(
|
||||
future: warningCard(
|
||||
context,
|
||||
apiServices,
|
||||
item),
|
||||
builder: (context,
|
||||
warningCardSnapshot) {
|
||||
if (warningCardSnapshot
|
||||
.hasData) {
|
||||
return warningCardSnapshot
|
||||
.data!;
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
return const SizedBox
|
||||
.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
if (snapshot.data?['battery'] != null)
|
||||
...snapshot.data!['battery']!
|
||||
if (ownerDevicesStatusSnapshot
|
||||
.data?['battery'] !=
|
||||
null)
|
||||
...ownerDevicesStatusSnapshot
|
||||
.data!['battery']!
|
||||
.map(
|
||||
(batteryItem) => SizedBox(
|
||||
width: context.dynamicWidth(0.95),
|
||||
child: FutureBuilder<Widget>(
|
||||
future: notificationCard(
|
||||
context, "lowBattery", appLocalization(context).low_battery_message, batteryItem),
|
||||
builder: (context, warningCardSnapshot) {
|
||||
if (warningCardSnapshot.hasData) {
|
||||
return warningCardSnapshot.data!;
|
||||
width: context
|
||||
.dynamicWidth(0.95),
|
||||
child: FutureBuilder<
|
||||
Widget>(
|
||||
future:
|
||||
notificationCard(
|
||||
context,
|
||||
"lowBattery",
|
||||
appLocalization(
|
||||
context)
|
||||
.low_battery_message,
|
||||
batteryItem,
|
||||
),
|
||||
builder: (context,
|
||||
warningCardSnapshot) {
|
||||
if (warningCardSnapshot
|
||||
.hasData) {
|
||||
return warningCardSnapshot
|
||||
.data!;
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
return const SizedBox
|
||||
.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
@@ -126,48 +216,49 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
.toList(),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
)
|
||||
: Padding(
|
||||
key: const ValueKey('no_data'),
|
||||
padding: context.paddingMedium,
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.check_circle_outline_rounded,
|
||||
Icons
|
||||
.check_circle_outline_rounded,
|
||||
size: 40,
|
||||
color: Colors.green,
|
||||
),
|
||||
SizedBox(width: context.lowValue),
|
||||
SizedBox(
|
||||
width: context.lowValue),
|
||||
Text(
|
||||
appLocalization(context).notification_description,
|
||||
appLocalization(context)
|
||||
.notification_description,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
overflow:
|
||||
TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
StreamBuilder<Map<String, List<DeviceWithAlias>>>(
|
||||
StreamBuilder<Map<String, List<DeviceWithAlias>>?>(
|
||||
stream: homeBloc.streamAllDevicesAliasMap,
|
||||
builder: (context, allDevicesAliasMapSnapshot) {
|
||||
if (!allDevicesAliasMapSnapshot.hasData ||
|
||||
allDevicesAliasMapSnapshot.data == null) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (allDevicesAliasMapSnapshot.data == null) {
|
||||
homeBloc.getDeviceStatusAliasMap(
|
||||
aliasDevicesSnapshot.data ?? []);
|
||||
return const SharedComponentLoadingAnimation();
|
||||
} else {
|
||||
final data = allDevicesAliasMapSnapshot.data!;
|
||||
return OverviewCard(
|
||||
isOwner: true,
|
||||
@@ -175,34 +266,10 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
active: data['online']?.length ?? 0,
|
||||
inactive: data['offline']?.length ?? 0,
|
||||
warning: data['warn']?.length ?? 0,
|
||||
unused: data['not-use']?.length ?? 0);
|
||||
}),
|
||||
SizedBox(height: context.lowValue),
|
||||
StreamBuilder<Map<String, List<DeviceWithAlias>>>(
|
||||
stream: homeBloc.streamAllDevicesAliasJoinedMap,
|
||||
builder: (context, allDevicesAliasJoinedMapSnapshot) {
|
||||
if (!allDevicesAliasJoinedMapSnapshot.hasData ||
|
||||
allDevicesAliasJoinedMapSnapshot.data == null) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
final data = allDevicesAliasJoinedMapSnapshot.data!;
|
||||
final total = data['all']?.length ?? 0;
|
||||
final active = data['online']?.length ?? 0;
|
||||
final inactive = data['offline']?.length ?? 0;
|
||||
final warning = data['warn']?.length ?? 0;
|
||||
final unused = data['not-use']?.length ?? 0;
|
||||
|
||||
if (total == 0 && active == 0 && inactive == 0 && warning == 0 && unused == 0) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return OverviewCard(
|
||||
isOwner: false,
|
||||
total: total,
|
||||
active: active,
|
||||
inactive: inactive,
|
||||
warning: warning,
|
||||
unused: unused,
|
||||
unused: data['not-use']?.length ?? 0,
|
||||
showUnused: false,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
@@ -211,121 +278,31 @@ class _HomeScreenState extends State<HomeScreen> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void getOwnerAndJoinedDevices() async {
|
||||
String response = await apiServices.getDashBoardDevices();
|
||||
final data = jsonDecode(response);
|
||||
List<dynamic> result = data["items"];
|
||||
devices = DeviceWithAlias.fromJsonDynamicList(result);
|
||||
getOwnerDeviceState(devices);
|
||||
checkSettingDevice(devices);
|
||||
getDeviceStatusAliasMap(devices);
|
||||
}
|
||||
|
||||
void getOwnerDeviceState(List<DeviceWithAlias> allDevices) async {
|
||||
List<DeviceWithAlias> ownerDevices = [];
|
||||
for (var device in allDevices) {
|
||||
if (device.isOwner!) {
|
||||
ownerDevices.add(device);
|
||||
}
|
||||
}
|
||||
if (ownerDevicesState.isEmpty || ownerDevicesState.length < devices.length) {
|
||||
ownerDevicesState.clear();
|
||||
ownerDevicesStatus.clear();
|
||||
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
|
||||
int count = 0;
|
||||
for (var device in ownerDevices) {
|
||||
Map<String, dynamic> sensorMap =
|
||||
DeviceUtils.instance.getDeviceSensors(context, device.status?.sensors ?? []);
|
||||
if (device.state == 1 || device.state == 3) {
|
||||
ownerDevicesStatus["state"] ??= [];
|
||||
ownerDevicesStatus["state"]!.add(device);
|
||||
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
|
||||
count++;
|
||||
}
|
||||
if (sensorMap['sensorBattery'] != appLocalization(context).no_data_message) {
|
||||
if (double.parse(sensorMap['sensorBattery']) <= 20) {
|
||||
ownerDevicesStatus['battery'] ??= [];
|
||||
ownerDevicesStatus['battery']!.add(device);
|
||||
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
notificationCount = count;
|
||||
homeBloc.sinkCountNotification.add(notificationCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void getDeviceStatusAliasMap(List<DeviceWithAlias> devices) {
|
||||
allDevicesAliasMap.clear();
|
||||
allDevicesAliasJoinedMap.clear();
|
||||
|
||||
for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) {
|
||||
allDevicesAliasMap[key] = [];
|
||||
allDevicesAliasJoinedMap[key] = [];
|
||||
}
|
||||
|
||||
for (DeviceWithAlias device in devices) {
|
||||
if (device.isOwner == true) {
|
||||
allDevicesAliasMap['all']!.add(device);
|
||||
if (device.state == 0 || device.state == 1) {
|
||||
allDevicesAliasMap['online']!.add(device);
|
||||
}
|
||||
if (device.state == -1) {
|
||||
allDevicesAliasMap['offline']!.add(device);
|
||||
}
|
||||
if (device.state == 1) {
|
||||
allDevicesAliasMap['warning']!.add(device);
|
||||
}
|
||||
if (device.state == -2) {
|
||||
allDevicesAliasMap['not-use']!.add(device);
|
||||
}
|
||||
} else {
|
||||
allDevicesAliasJoinedMap['all']!.add(device);
|
||||
if (device.state == 0 || device.state == 1) {
|
||||
allDevicesAliasJoinedMap['online']!.add(device);
|
||||
}
|
||||
if (device.state == -1) {
|
||||
allDevicesAliasJoinedMap['offline']!.add(device);
|
||||
}
|
||||
if (device.state == 1) {
|
||||
allDevicesAliasJoinedMap['warning']!.add(device);
|
||||
}
|
||||
if (device.state == -2) {
|
||||
allDevicesAliasJoinedMap['not-use']!.add(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap);
|
||||
homeBloc.sinkAllDevicesAliasJoinedMap.add(allDevicesAliasJoinedMap);
|
||||
});
|
||||
}
|
||||
|
||||
void checkSettingDevice(List<DeviceWithAlias> devices) async {
|
||||
if (isFunctionCall) {
|
||||
log("Ham check setting da duoc goi");
|
||||
} else {
|
||||
String? response = await apiServices.getAllSettingsNotificationOfDevices();
|
||||
if (response != "") {
|
||||
final data = jsonDecode(response);
|
||||
final result = data['data'];
|
||||
// log("Data ${DeviceNotificationSettings.mapFromJson(jsonDecode(data)).values.toList()}");
|
||||
await apiServices.execute(context, () async {
|
||||
List<DeviceNotificationSettings> list =
|
||||
DeviceNotificationSettings.mapFromJson(result).values.toList();
|
||||
await apiServices.getAllSettingsNotificationOfDevices();
|
||||
// log("List: $list");
|
||||
Set<String> thingIdsInList = list.map((device) => device.thingId!).toSet();
|
||||
Set<String> thingIdsInList =
|
||||
list.map((device) => device.thingId!).toSet();
|
||||
for (var device in devices) {
|
||||
if (!thingIdsInList.contains(device.thingId)) {
|
||||
log("Device with Thing ID ${device.thingId} is not in the notification settings list.");
|
||||
await apiServices.setupDeviceNotification(device.thingId!, device.name!);
|
||||
await apiServices.execute(context, () async {
|
||||
await apiServices.setupDeviceNotification(
|
||||
device.thingId!, device.name!);
|
||||
});
|
||||
} else {
|
||||
log("All devices are in the notification settings list.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log("apiServices: getAllSettingsNotificationofDevices error!");
|
||||
}
|
||||
});
|
||||
}
|
||||
isFunctionCall = true;
|
||||
}
|
||||
|
||||
@@ -3,24 +3,24 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:sfm_app/feature/home/device_alias_model.dart';
|
||||
|
||||
import '../../../product/shared/shared_rocket_container.dart';
|
||||
import '../../../product/constant/enums/app_route_enums.dart';
|
||||
import '../../../product/constant/image/image_constants.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../device_alias_model.dart';
|
||||
|
||||
Future<Widget> notificationCard(BuildContext context, String notiticationType,
|
||||
Future<Widget> notificationCard(BuildContext context, String notificationType,
|
||||
String notificationTitle, DeviceWithAlias device) async {
|
||||
String location = "";
|
||||
if (device.areaPath != "") {
|
||||
location = await DeviceUtils.instance
|
||||
.getFullDeviceLocation(context, device.areaPath!);
|
||||
.getFullDeviceLocation(context, device.areaPath!, "");
|
||||
}
|
||||
String path = "";
|
||||
// DateTime time = DateTime.now();
|
||||
String time = "";
|
||||
for (var sensor in device.status!.sensors!) {
|
||||
if (sensor.name! == "7") {
|
||||
@@ -29,7 +29,7 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
|
||||
time = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
|
||||
}
|
||||
}
|
||||
if (notiticationType == "lowBattery") {
|
||||
if (notificationType == "lowBattery") {
|
||||
path = ImageConstants.instance.getImage("low_battery");
|
||||
}
|
||||
return Card(
|
||||
@@ -62,10 +62,7 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
|
||||
SizedBox(
|
||||
child: Text(
|
||||
"${appLocalization(context).device_title} ${device.isOwner! ? device.name : device.alias}",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
style: context.responsiveBodyLargeWithBold,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
@@ -92,7 +89,7 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
|
||||
Expanded(
|
||||
child: Text(
|
||||
location,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
style: context.responsiveBodySmall,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
@@ -111,7 +108,7 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
|
||||
Expanded(
|
||||
child: Text(
|
||||
time.toString(),
|
||||
style: const TextStyle(fontSize: 15),
|
||||
style: context.responsiveBodySmall,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
@@ -120,11 +117,16 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
|
||||
),
|
||||
],
|
||||
),
|
||||
Align(
|
||||
SizedBox(
|
||||
height: context.lowValue,
|
||||
),
|
||||
device.isOwner!
|
||||
? Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: OutlinedButton(
|
||||
style: const ButtonStyle(
|
||||
backgroundColor: WidgetStatePropertyAll(Colors.blueAccent),
|
||||
backgroundColor:
|
||||
WidgetStatePropertyAll(Colors.blueAccent),
|
||||
),
|
||||
onPressed: () {
|
||||
context.pushNamed(AppRoutes.DEVICE_DETAIL.name,
|
||||
@@ -132,11 +134,28 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context).detail_message,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ClipPath(
|
||||
clipper: SharedRocketContainer(),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(context.lowValue),
|
||||
height: context.mediumValue,
|
||||
width: context.dynamicWidth(0.22),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green[300],
|
||||
),
|
||||
child: Text(
|
||||
appLocalization(context).interfamily_page_name,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,69 +1,93 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'status_card.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
class OverviewCard extends StatelessWidget {
|
||||
class OverviewCard extends StatefulWidget {
|
||||
final bool isOwner;
|
||||
final int total;
|
||||
final int active;
|
||||
final int inactive;
|
||||
final int warning;
|
||||
final int unused;
|
||||
final bool showTotal;
|
||||
final bool showActive;
|
||||
final bool showInactive;
|
||||
final bool showWarning;
|
||||
final bool showUnused;
|
||||
|
||||
const OverviewCard(
|
||||
{super.key,
|
||||
const OverviewCard({
|
||||
super.key,
|
||||
required this.isOwner,
|
||||
required this.total,
|
||||
required this.active,
|
||||
required this.inactive,
|
||||
required this.warning,
|
||||
required this.unused});
|
||||
required this.unused,
|
||||
this.showTotal = true,
|
||||
this.showActive = true,
|
||||
this.showInactive = true,
|
||||
this.showWarning = true,
|
||||
this.showUnused = true,
|
||||
});
|
||||
|
||||
@override
|
||||
State<OverviewCard> createState() => _OverviewCardState();
|
||||
}
|
||||
|
||||
class _OverviewCardState extends State<OverviewCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
elevation: 8,
|
||||
return FittedBox(
|
||||
alignment: Alignment.topCenter,
|
||||
child: SizedBox(
|
||||
width: context.width,
|
||||
child: Card(
|
||||
// elevation: 8,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||
child: Padding(
|
||||
padding: context.paddingNormal,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
isOwner
|
||||
widget.isOwner
|
||||
? appLocalization(context).overview_message
|
||||
: appLocalization(context).interfamily_page_name,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: context.h2,
|
||||
),
|
||||
SizedBox(height: context.normalValue),
|
||||
Column(
|
||||
children: [
|
||||
if (widget.showTotal)
|
||||
StatusCard(
|
||||
label: appLocalization(context).total_nof_devices_message,
|
||||
count: total,
|
||||
count: widget.total,
|
||||
color: Colors.blue,
|
||||
),
|
||||
if (widget.showActive)
|
||||
StatusCard(
|
||||
label: appLocalization(context).active_devices_message,
|
||||
count: active,
|
||||
count: widget.active,
|
||||
color: Colors.green,
|
||||
),
|
||||
if (widget.showInactive)
|
||||
StatusCard(
|
||||
label: appLocalization(context).inactive_devices_message,
|
||||
count: inactive,
|
||||
count: widget.inactive,
|
||||
color: Colors.grey,
|
||||
),
|
||||
if (widget.showWarning)
|
||||
StatusCard(
|
||||
label: appLocalization(context).warning_devices_message,
|
||||
count: warning,
|
||||
count: widget.warning,
|
||||
color: Colors.orange,
|
||||
),
|
||||
if (widget.showUnused)
|
||||
StatusCard(
|
||||
label: appLocalization(context).unused_devices_message,
|
||||
count: unused,
|
||||
count: widget.unused,
|
||||
color: Colors.yellow,
|
||||
),
|
||||
],
|
||||
@@ -71,6 +95,8 @@ class OverviewCard extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
|
||||
class StatusCard extends StatelessWidget {
|
||||
final String label;
|
||||
final int count;
|
||||
@@ -27,14 +29,8 @@ class StatusCard extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(label, style: const TextStyle(fontSize: 18)),
|
||||
Text(
|
||||
count.toString(),
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
Text(label, style: context.responsiveBodyLarge),
|
||||
Text(count.toString(), style: context.h2),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:maps_launcher/maps_launcher.dart';
|
||||
import 'package:badges/badges.dart' as badges;
|
||||
|
||||
import '../../../product/shared/shared_rocket_container.dart';
|
||||
import '../device_alias_model.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../product/constant/image/image_constants.dart';
|
||||
@@ -21,7 +22,7 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
String fullLocation = "";
|
||||
if (device.areaPath != "") {
|
||||
fullLocation = await DeviceUtils.instance
|
||||
.getFullDeviceLocation(context, device.areaPath!);
|
||||
.getFullDeviceLocation(context, device.areaPath!, "");
|
||||
}
|
||||
String time = "";
|
||||
for (var sensor in device.status!.sensors!) {
|
||||
@@ -33,7 +34,7 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
}
|
||||
if (device.state! == 3) {
|
||||
backgroundColor = Colors.grey;
|
||||
textColor = Colors.black;
|
||||
textColor = Colors.white;
|
||||
message = appLocalization(context).in_progress_message;
|
||||
} else if (device.state! == 2) {
|
||||
backgroundColor = const Color.fromARGB(255, 6, 138, 72);
|
||||
@@ -42,32 +43,18 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
} else if (device.state! == 1) {
|
||||
backgroundColor = const Color.fromARGB(255, 250, 63, 63);
|
||||
textColor = Colors.white;
|
||||
if(device.isOwner == true){
|
||||
|
||||
message = appLocalization(context).button_fake_fire_message;
|
||||
}else{
|
||||
message = appLocalization(context).smoke_detecting_message_lowercase;
|
||||
}
|
||||
} else {
|
||||
backgroundColor = Colors.black;
|
||||
textColor = Colors.white;
|
||||
message = appLocalization(context).disconnect_message_uppercase;
|
||||
}
|
||||
return badges.Badge(
|
||||
badgeAnimation: const badges.BadgeAnimation.fade(),
|
||||
position: badges.BadgePosition.bottomStart(bottom: 15, start: 10),
|
||||
badgeContent: device.isOwner!
|
||||
? null
|
||||
: Text(
|
||||
appLocalization(context).interfamily_page_name,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
badgeStyle: badges.BadgeStyle(
|
||||
shape: badges.BadgeShape.square,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderSide: const BorderSide(color: Colors.white, width: 2),
|
||||
badgeColor: Theme.of(context).colorScheme.surfaceDim,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
|
||||
),
|
||||
child: Card(
|
||||
return Card(
|
||||
child: Padding(
|
||||
padding: context.paddingLow,
|
||||
child: Column(
|
||||
@@ -97,10 +84,7 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
SizedBox(
|
||||
child: Text(
|
||||
"${appLocalization(context).device_title}: ${device.isOwner! ? device.name : device.alias}",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
),
|
||||
style: context.responsiveBodyLargeWithBold,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
@@ -128,7 +112,7 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
Expanded(
|
||||
child: Text(
|
||||
fullLocation,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
style: context.responsiveBodySmall,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
@@ -147,7 +131,7 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
Expanded(
|
||||
child: Text(
|
||||
time,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
style: context.responsiveBodySmall,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
softWrap: true,
|
||||
@@ -159,14 +143,16 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
SizedBox(
|
||||
height: context.lowValue,
|
||||
),
|
||||
Row(
|
||||
device.isOwner == true
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
IconButton.outlined(
|
||||
onPressed: () async => {},
|
||||
// displayListOfFireStationPhoneNumbers(testDevice),
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.call),
|
||||
icon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.call),
|
||||
iconSize: 25,
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
@@ -199,7 +185,8 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
WidgetStatePropertyAll(backgroundColor)),
|
||||
onPressed: () async {
|
||||
if (message ==
|
||||
appLocalization(context).button_fake_fire_message) {
|
||||
appLocalization(context)
|
||||
.button_fake_fire_message) {
|
||||
await showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
@@ -212,8 +199,11 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
await apiServices.execute(context,
|
||||
() async {
|
||||
int statusCode = await apiServices
|
||||
.confirmFakeFireByUser(device.thingId!);
|
||||
.confirmFakeFireByUser(
|
||||
device.thingId!);
|
||||
if (statusCode == 200) {
|
||||
showNoIconTopSnackBar(
|
||||
context,
|
||||
@@ -229,13 +219,15 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
Colors.red,
|
||||
Colors.red);
|
||||
}
|
||||
});
|
||||
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
.confirm_fake_fire_sure_message,
|
||||
style:
|
||||
const TextStyle(color: Colors.red)),
|
||||
style: const TextStyle(
|
||||
color: Colors.red)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
@@ -250,7 +242,8 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
} else {
|
||||
showNoIconTopSnackBar(
|
||||
context,
|
||||
appLocalization(context).let_PCCC_handle_message,
|
||||
appLocalization(context)
|
||||
.let_PCCC_handle_message,
|
||||
Colors.orange,
|
||||
Colors.white);
|
||||
}
|
||||
@@ -263,10 +256,45 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
ClipPath(
|
||||
clipper: SharedRocketContainer(),
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(context.lowValue),
|
||||
height: context.mediumValue,
|
||||
width: context.dynamicWidth(0.22),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.green[300],
|
||||
),
|
||||
child: Text(
|
||||
appLocalization(context).interfamily_page_name,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: context.mediumValue),
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: OutlinedButton(
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
WidgetStatePropertyAll(backgroundColor)),
|
||||
onPressed: () async {},
|
||||
child: Text(
|
||||
message,
|
||||
style: TextStyle(color: textColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../bloc/group_detail_bloc.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import '../../devices/device_model.dart';
|
||||
import 'group_detail_model.dart';
|
||||
|
||||
addDeviceDialog(BuildContext context, DetailGroupBloc detailGroupBloc,
|
||||
String groupID, List<DeviceOfGroup> devices) async {
|
||||
List<Device> ownerDevices = await detailGroupBloc.getOwnerDevices();
|
||||
List<Device> ownerDevices = await detailGroupBloc.getOwnerDevices(context);
|
||||
List<String> selectedItems = [];
|
||||
List<String> selectedDevices = [];
|
||||
if (devices.isNotEmpty) {
|
||||
@@ -36,7 +37,7 @@ addDeviceDialog(BuildContext context, DetailGroupBloc detailGroupBloc,
|
||||
),
|
||||
hint: Text(
|
||||
appLocalization(context).choose_device_dropdownButton,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
style: context.responsiveBodySmall,
|
||||
),
|
||||
items: ownerDevices
|
||||
.map(
|
||||
@@ -73,7 +74,7 @@ addDeviceDialog(BuildContext context, DetailGroupBloc detailGroupBloc,
|
||||
Expanded(
|
||||
child: Text(
|
||||
item.name!,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
style: context.responsiveBodySmall,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -130,7 +131,7 @@ addDeviceDialog(BuildContext context, DetailGroupBloc detailGroupBloc,
|
||||
for (var device in selectedItems) {
|
||||
await detailGroupBloc.addDeviceToGroup(
|
||||
context, groupID, device);
|
||||
await detailGroupBloc.getGroupDetail(groupID);
|
||||
await detailGroupBloc.getGroupDetail(context,groupID);
|
||||
}
|
||||
|
||||
Navigator.of(dialogContext).pop();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../bloc/group_detail_bloc.dart';
|
||||
import '../../../product/shared/shared_loading_animation.dart';
|
||||
import 'group_detail_model.dart';
|
||||
import '../../../product/base/bloc/base_bloc.dart';
|
||||
import '../../../product/constant/app/app_constants.dart';
|
||||
@@ -13,7 +14,6 @@ import '../../../product/services/api_services.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
import '../../../product/utils/response_status_utils.dart';
|
||||
|
||||
import 'add_device_to_group_dialog.dart';
|
||||
|
||||
class DetailGroupScreen extends StatefulWidget {
|
||||
@@ -35,14 +35,14 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
const duration = Duration(seconds: 10);
|
||||
getGroupDetailTimer = Timer.periodic(
|
||||
duration,
|
||||
(Timer t) => detailGroupBloc.getGroupDetail(widget.group),
|
||||
(Timer t) => detailGroupBloc.getGroupDetail(context, widget.group),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
getGroupDetailTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -51,10 +51,8 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
stream: detailGroupBloc.streamDetailGroup,
|
||||
builder: (context, detailGroupSnapshot) {
|
||||
if (detailGroupSnapshot.data?.id == null) {
|
||||
detailGroupBloc.getGroupDetail(widget.group);
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
detailGroupBloc.getGroupDetail(context, widget.group);
|
||||
return const SharedLoadingAnimation();
|
||||
} else {
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
@@ -140,8 +138,8 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
widget.group,
|
||||
user.id!,
|
||||
user.name!);
|
||||
detailGroupBloc
|
||||
.getGroupDetail(widget.group);
|
||||
detailGroupBloc.getGroupDetail(
|
||||
context, widget.group);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.check,
|
||||
@@ -158,8 +156,8 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
widget.group,
|
||||
user.id!,
|
||||
user.name!);
|
||||
await detailGroupBloc
|
||||
.getGroupDetail(widget.group);
|
||||
await detailGroupBloc.getGroupDetail(
|
||||
context, widget.group);
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.close,
|
||||
@@ -205,8 +203,8 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
widget.group,
|
||||
user.id!,
|
||||
user.name!);
|
||||
await detailGroupBloc
|
||||
.getGroupDetail(widget.group);
|
||||
await detailGroupBloc.getGroupDetail(
|
||||
context, widget.group);
|
||||
},
|
||||
value: 2,
|
||||
child: Text(appLocalization(context)
|
||||
@@ -239,7 +237,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
? PopupMenuButton(
|
||||
icon: IconConstants.instance
|
||||
.getMaterialIcon(Icons.more_horiz),
|
||||
itemBuilder: (contex) => [
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem(
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
@@ -325,6 +323,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
Future.delayed(context.lowDuration).then(
|
||||
(value) => Navigator.pop(context),
|
||||
);
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices
|
||||
.deleteGroup(widget.group);
|
||||
showSnackBarResponseByStatusCode(
|
||||
@@ -334,6 +333,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
.notification_delete_group_success,
|
||||
appLocalization(context)
|
||||
.notification_delete_group_failed);
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
appLocalization(context)
|
||||
@@ -429,7 +429,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
return SafeArea(
|
||||
child: Center(
|
||||
child: devices.isEmpty
|
||||
? Center(
|
||||
@@ -461,7 +461,8 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
DeviceUtils.instance.checkStateDevice(
|
||||
context, devices[index].state!),
|
||||
style: TextStyle(
|
||||
color: DeviceUtils.instance.getTableRowColor(context,
|
||||
color: DeviceUtils.instance.getTableRowColor(
|
||||
context,
|
||||
devices[index].state!,
|
||||
),
|
||||
),
|
||||
@@ -493,10 +494,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('${appLocalization(context).map_result}: ',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.black)),
|
||||
style: context.h3),
|
||||
Container(
|
||||
alignment: Alignment.centerRight,
|
||||
child: IconButton(
|
||||
@@ -526,7 +524,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
|
||||
String alias = aliasController.text;
|
||||
await detailGroupBloc.updateDeviceNameInGroup(
|
||||
context, device.thingId!, alias);
|
||||
await detailGroupBloc.getGroupDetail(widget.group);
|
||||
await detailGroupBloc.getGroupDetail(context, widget.group);
|
||||
},
|
||||
child: Text(appLocalization(context).confirm_button_content)),
|
||||
)
|
||||
|
||||
@@ -1,165 +1,125 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../product/constant/enums/app_route_enums.dart';
|
||||
import 'groups_model.dart';
|
||||
import 'groups_widget.dart';
|
||||
import '../../../bloc/inter_family_bloc.dart';
|
||||
import '../inter_family_widget.dart';
|
||||
import '../../../product/base/bloc/base_bloc.dart';
|
||||
import '../../../product/constant/app/app_constants.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import 'groups_widget.dart';
|
||||
|
||||
class GroupsScreen extends StatefulWidget {
|
||||
const GroupsScreen({super.key, required this.role});
|
||||
/// Stateless widget that renders a provided list of groups. The parent
|
||||
/// screen owns fetching/updating the list; this widget only displays it and
|
||||
/// forwards actions to the provided [InterFamilyBloc].
|
||||
class GroupsScreen extends StatelessWidget {
|
||||
const GroupsScreen(
|
||||
{super.key,
|
||||
required this.role,
|
||||
required this.groups,
|
||||
required this.interFamilyBloc});
|
||||
|
||||
final String role;
|
||||
|
||||
@override
|
||||
State<GroupsScreen> createState() => _GroupsScreenState();
|
||||
}
|
||||
|
||||
class _GroupsScreenState extends State<GroupsScreen> {
|
||||
late InterFamilyBloc interFamilyBloc;
|
||||
Timer? getAllGroupsTimer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
interFamilyBloc = BlocProvider.of(context);
|
||||
const duration = Duration(seconds: 10);
|
||||
getAllGroupsTimer = Timer.periodic(
|
||||
duration,
|
||||
(Timer t) => interFamilyBloc.getAllGroup(widget.role),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
getAllGroupsTimer?.cancel();
|
||||
}
|
||||
final List<Group> groups;
|
||||
final InterFamilyBloc interFamilyBloc;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (widget.role == ApplicationConstants.OWNER_GROUP ||
|
||||
widget.role == ApplicationConstants.PARTICIPANT_GROUP) {
|
||||
interFamilyBloc.getAllGroup(widget.role);
|
||||
return StreamBuilder<List<Group>>(
|
||||
stream: interFamilyBloc.streamCurrentGroups,
|
||||
builder: (context, groupsSnapshot) {
|
||||
return Scaffold(
|
||||
body: groupsSnapshot.data?.isEmpty ?? true
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: ListView.builder(
|
||||
itemCount: groupsSnapshot.data!.length,
|
||||
if (role != ApplicationConstants.OWNER_GROUP &&
|
||||
role != ApplicationConstants.PARTICIPANT_GROUP) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
if (groups.isEmpty) {
|
||||
return Center(child: Text(appLocalization(context).dont_have_group));
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
itemCount: groups.length,
|
||||
itemBuilder: (context, index) {
|
||||
final group = groups[index];
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
context.pushNamed(AppRoutes.GROUP_DETAIL.name,
|
||||
pathParameters: {"groupId": groupsSnapshot.data![index].id!},
|
||||
extra: widget.role);
|
||||
},
|
||||
onTap: () => context.pushNamed(AppRoutes.GROUP_DETAIL.name,
|
||||
pathParameters: {"groupId": group.id!}, extra: role),
|
||||
leading: IconConstants.instance.getMaterialIcon(Icons.diversity_2),
|
||||
title: Text(
|
||||
groupsSnapshot.data![index].name ?? '',
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
subtitle: Text(groupsSnapshot.data![index].description ?? ""),
|
||||
trailing: widget.role == ApplicationConstants.OWNER_GROUP
|
||||
? PopupMenuButton(
|
||||
title: Text(group.name ?? '',
|
||||
style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||
subtitle: Text(group.description ?? ''),
|
||||
trailing: role == ApplicationConstants.OWNER_GROUP
|
||||
? _ownerPopupMenu(group, context)
|
||||
: null,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _ownerPopupMenu(Group group, BuildContext context) {
|
||||
return PopupMenuButton<int>(
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(8.0),
|
||||
bottomRight: Radius.circular(8.0),
|
||||
topLeft: Radius.circular(8.0),
|
||||
topRight: Radius.circular(8.0),
|
||||
),
|
||||
),
|
||||
borderRadius: BorderRadius.all(Radius.circular(8.0))),
|
||||
itemBuilder: (ctx) => [
|
||||
_buildPopupMenuItem(groupsSnapshot.data![index], context,
|
||||
_buildPopupMenuItem(group, context,
|
||||
appLocalization(context).share_group_title, Icons.share, 4),
|
||||
_buildPopupMenuItem(
|
||||
groupsSnapshot.data![index],
|
||||
group,
|
||||
context,
|
||||
appLocalization(context).change_group_infomation_title,
|
||||
Icons.settings_backup_restore,
|
||||
2),
|
||||
_buildPopupMenuItem(
|
||||
groupsSnapshot.data![index],
|
||||
group,
|
||||
context,
|
||||
appLocalization(context).delete_group_title,
|
||||
Icons.delete_forever_rounded,
|
||||
3),
|
||||
],
|
||||
icon: const Icon(Icons.more_horiz),
|
||||
)
|
||||
: const SizedBox.shrink(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
|
||||
PopupMenuItem _buildPopupMenuItem(
|
||||
Group group, BuildContext context, String title, IconData iconData, int position) {
|
||||
return PopupMenuItem(
|
||||
PopupMenuItem<int> _buildPopupMenuItem(Group group, BuildContext context,
|
||||
String title, IconData iconData, int value) {
|
||||
return PopupMenuItem<int>(
|
||||
value: value,
|
||||
child: Row(children: [
|
||||
Icon(iconData, color: Colors.black),
|
||||
const SizedBox(width: 10),
|
||||
Text(title)
|
||||
]),
|
||||
onTap: () {
|
||||
Future.delayed(context.lowDuration, () {
|
||||
if (title == appLocalization(context).share_group_title) {
|
||||
Future.delayed(context.lowDuration, () {
|
||||
shareGroup(context, group);
|
||||
});
|
||||
} else if (title == appLocalization(context).change_group_infomation_title) {
|
||||
Future.delayed(context.lowDuration, () {
|
||||
} else if (title ==
|
||||
appLocalization(context).change_group_infomation_title) {
|
||||
createOrJoinGroupDialog(
|
||||
context,
|
||||
interFamilyBloc,
|
||||
widget.role,
|
||||
role,
|
||||
appLocalization(context).change_group_infomation_content,
|
||||
appLocalization(context).group_name_title,
|
||||
group.name!,
|
||||
group.name ?? '',
|
||||
false,
|
||||
group.id!,
|
||||
group.id ?? '',
|
||||
appLocalization(context).description_group,
|
||||
group.description ?? "");
|
||||
});
|
||||
group.description ?? '',
|
||||
);
|
||||
} else if (title == appLocalization(context).delete_group_title) {
|
||||
Future.delayed(context.lowDuration, () {
|
||||
showActionDialog(
|
||||
context,
|
||||
widget.role,
|
||||
role,
|
||||
interFamilyBloc,
|
||||
appLocalization(context).delete_group_title,
|
||||
appLocalization(context).delete_group_content,
|
||||
group);
|
||||
group,
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {}
|
||||
},
|
||||
value: position,
|
||||
child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Icon(
|
||||
iconData,
|
||||
color: Colors.black,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Text(title),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
import '../../../bloc/inter_family_bloc.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import 'groups_model.dart';
|
||||
|
||||
shareGroup(BuildContext context, Group group) {
|
||||
@@ -80,7 +80,8 @@ showActionDialog(
|
||||
if (dialogTitle == appLocalization(context).delete_group_title) {
|
||||
Navigator.of(dialogContext).pop();
|
||||
await interFamilyBloc.deleteGroup(context, group.id!);
|
||||
interFamilyBloc.getAllGroup(role);
|
||||
// ignore: use_build_context_synchronously
|
||||
interFamilyBloc.getAllGroup(context,role);
|
||||
} else {}
|
||||
},
|
||||
child: Text(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'groups/groups_screen.dart';
|
||||
import 'groups/groups_model.dart';
|
||||
import '../../bloc/inter_family_bloc.dart';
|
||||
import 'inter_family_widget.dart';
|
||||
import '../../product/base/bloc/base_bloc.dart';
|
||||
@@ -25,20 +26,29 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
interFamilyBloc = BlocProvider.of(context);
|
||||
// fetch initial groups for the default selected tab
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
interFamilyBloc.getAllGroup(
|
||||
context,
|
||||
_selectedIndex == 0
|
||||
? ApplicationConstants.OWNER_GROUP
|
||||
: ApplicationConstants.PARTICIPANT_GROUP);
|
||||
});
|
||||
}
|
||||
|
||||
final _widgetOptions = <Widget>[
|
||||
BlocProvider(
|
||||
blocBuilder: () => InterFamilyBloc(),
|
||||
child: const GroupsScreen(
|
||||
List<Group> ownerGroups = [];
|
||||
List<Group> participantGroups = [];
|
||||
|
||||
List<Widget> get _widgetOptions => [
|
||||
GroupsScreen(
|
||||
role: ApplicationConstants.OWNER_GROUP,
|
||||
groups: ownerGroups,
|
||||
interFamilyBloc: interFamilyBloc,
|
||||
),
|
||||
),
|
||||
BlocProvider(
|
||||
blocBuilder: () => InterFamilyBloc(),
|
||||
child: const GroupsScreen(
|
||||
GroupsScreen(
|
||||
role: ApplicationConstants.PARTICIPANT_GROUP,
|
||||
),
|
||||
groups: participantGroups,
|
||||
interFamilyBloc: interFamilyBloc,
|
||||
),
|
||||
];
|
||||
|
||||
@@ -49,6 +59,20 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
|
||||
stream: interFamilyBloc.streamSelectedScreen,
|
||||
initialData: _selectedIndex,
|
||||
builder: (context, selectSnapshot) {
|
||||
// subscribe to groups stream and update local lists so child widgets render instantly
|
||||
return StreamBuilder<List<Group>>(
|
||||
stream: interFamilyBloc.streamCurrentGroups,
|
||||
builder: (context, groupsSnapshot) {
|
||||
if (groupsSnapshot.hasData) {
|
||||
final all = groupsSnapshot.data!;
|
||||
ownerGroups = all
|
||||
.where((g) => g.isOwner == true && g.visibility == 'PUBLIC')
|
||||
.toList();
|
||||
participantGroups = all
|
||||
.where((g) => g.isOwner == null && g.visibility == 'PUBLIC')
|
||||
.toList();
|
||||
}
|
||||
// build UI below
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
actions: [
|
||||
@@ -58,35 +82,32 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
|
||||
createOrJoinGroupDialog(
|
||||
context,
|
||||
interFamilyBloc,
|
||||
selectSnapshot.data! == 0
|
||||
? ApplicationConstants.OWNER_GROUP
|
||||
: ApplicationConstants.PARTICIPANT_GROUP,
|
||||
ApplicationConstants.OWNER_GROUP,
|
||||
appLocalization(context).add_new_group,
|
||||
appLocalization(context).group_name_title,
|
||||
"",
|
||||
false,
|
||||
"",
|
||||
"",
|
||||
"");
|
||||
"",
|
||||
);
|
||||
} else {
|
||||
createOrJoinGroupDialog(
|
||||
context,
|
||||
interFamilyBloc,
|
||||
selectSnapshot.data! == 0
|
||||
? ApplicationConstants.OWNER_GROUP
|
||||
: ApplicationConstants.PARTICIPANT_GROUP,
|
||||
ApplicationConstants.PARTICIPANT_GROUP,
|
||||
appLocalization(context).join_group,
|
||||
appLocalization(context).group_id_title,
|
||||
'',
|
||||
true,
|
||||
"",
|
||||
appLocalization(context).group_name_title,
|
||||
"");
|
||||
"",
|
||||
);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
shape: const CircleBorder(),
|
||||
),
|
||||
style:
|
||||
ElevatedButton.styleFrom(shape: const CircleBorder()),
|
||||
child: IconConstants.instance.getMaterialIcon(Icons.add),
|
||||
),
|
||||
],
|
||||
@@ -111,7 +132,7 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
|
||||
),
|
||||
),
|
||||
drawer: Drawer(
|
||||
width: context.dynamicWidth(0.4),
|
||||
width: context.dynamicWidth(0.6),
|
||||
child: ListView(
|
||||
padding: EdgeInsets.zero,
|
||||
children: [
|
||||
@@ -142,6 +163,8 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void checkTitle(int index) {
|
||||
@@ -159,5 +182,11 @@ class _InterFamilyScreenState extends State<InterFamilyScreen> {
|
||||
interFamilyBloc.sinkSelectedScreen.add(_selectedIndex);
|
||||
isLoading = false;
|
||||
interFamilyBloc.sinkIsLoading.add(isLoading);
|
||||
// fetch groups for the selected tab immediately
|
||||
interFamilyBloc.getAllGroup(
|
||||
context,
|
||||
_selectedIndex == 0
|
||||
? ApplicationConstants.OWNER_GROUP
|
||||
: ApplicationConstants.PARTICIPANT_GROUP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ createOrJoinGroupDialog(
|
||||
try {
|
||||
await interFamilyBloc.createGroup(
|
||||
context, groupName, description);
|
||||
interFamilyBloc.getAllGroup(role);
|
||||
interFamilyBloc.getAllGroup(context, role);
|
||||
Navigator.of(dialogContext).pop();
|
||||
} catch (e) {
|
||||
// log("Lỗi khi tạo nhóm: $e");
|
||||
@@ -131,9 +131,9 @@ createOrJoinGroupDialog(
|
||||
appLocalization(context)
|
||||
.change_group_infomation_content) {
|
||||
try {
|
||||
await interFamilyBloc.changeGroupInfomation(
|
||||
await interFamilyBloc.changeGroupInformation(
|
||||
context, groupID, groupName, description);
|
||||
interFamilyBloc.getAllGroup(role);
|
||||
interFamilyBloc.getAllGroup(context, role);
|
||||
Navigator.of(dialogContext).pop();
|
||||
} catch (e) {
|
||||
// log("Lỗi khi sửa nhóm: $e");
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:badges/badges.dart' as badges;
|
||||
import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart';
|
||||
import '../../product/permission/notification_permission.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
|
||||
import '../../product/shared/shared_snack_bar.dart';
|
||||
import '../../product/services/notification_services.dart';
|
||||
import '../../product/utils/permission_handler.dart';
|
||||
import '../../product/permission/notification_permission.dart';
|
||||
import '../settings/profile/profile_model.dart';
|
||||
import '../../product/extension/context_extension.dart';
|
||||
import '../../bloc/home_bloc.dart';
|
||||
import '../../product/constant/app/app_constants.dart';
|
||||
import '../../product/constant/enums/app_route_enums.dart';
|
||||
import '../../product/permission/location_permission.dart';
|
||||
import '../../product/services/theme_services.dart';
|
||||
import '../../bloc/devices_manager_bloc.dart';
|
||||
import '../devices/devices_manager_screen.dart';
|
||||
@@ -44,20 +44,8 @@ class MainScreen extends StatefulWidget {
|
||||
State<MainScreen> createState() => _MainScreenState();
|
||||
}
|
||||
|
||||
PersistentTabController controller = PersistentTabController(initialIndex: 0);
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
log("Full background message payload: ${message.toMap()}");
|
||||
await Firebase.initializeApp();
|
||||
final notificationServices = NotificationServices();
|
||||
await notificationServices.initLocalNotifications(controller);
|
||||
await notificationServices.showNotification(message);
|
||||
log("Background message handled: ${message.data['title']}");
|
||||
}
|
||||
|
||||
|
||||
class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
|
||||
APIServices apiServices = APIServices();
|
||||
final NotificationServices notificationServices = NotificationServices();
|
||||
late MainBloc mainBloc;
|
||||
@@ -86,36 +74,34 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
}
|
||||
mainBloc.sinkIsVNIcon.add(isVN);
|
||||
mainBloc.sinkThemeMode.add(isLight);
|
||||
LocationPermissionRequest.instance.checkLocationPermission(context);
|
||||
NotificationPermission.instance.checkNotificationPermission(context);
|
||||
checkAndRequestPermission();
|
||||
NotificationServices.requestNotificationPermission();
|
||||
// NotificationPermission.instance.checkNotificationPermission(context);
|
||||
// bool? notificationStatus = await NotificationPermission.instance.requestNotificationPermission();
|
||||
// if(notificationStatus == false){
|
||||
// showNoIconTopSnackBar(context, "Yêu cầu quyền thông báo không thành công", Colors.orange, Colors.white12);
|
||||
// }
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
mainBloc = BlocProvider.of(context);
|
||||
mainBloc.getFCMTokenAndPresentations();
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
initialCheck();
|
||||
getBellNotification();
|
||||
mainBloc.getUserProfile();
|
||||
notificationServices.initLocalNotifications(controller);
|
||||
notificationServices.firebaseInit(context);
|
||||
NotificationServices().setupInteractMessage(controller);
|
||||
}
|
||||
mainBloc.getUserProfile(context);
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
super.didChangeAppLifecycleState(state);
|
||||
if (state == AppLifecycleState.inactive) {
|
||||
log("App Inactive");
|
||||
} else if (state == AppLifecycleState.resumed) {
|
||||
log("App Resumed");
|
||||
LocationPermissionRequest.instance.checkLocationPermission(context);
|
||||
} else if (state == AppLifecycleState.paused) {
|
||||
log("App paused");
|
||||
} else if (state == AppLifecycleState.detached) {
|
||||
log("App detached");
|
||||
}
|
||||
FirebaseMessaging.instance.onTokenRefresh.listen((newToken) {
|
||||
log("New FCM Token: $newToken");
|
||||
// Gửi token mới lên server
|
||||
mainBloc.sendNotificationToken(newToken);
|
||||
});
|
||||
|
||||
// notificationServices.initLocalNotifications(controller);
|
||||
// notificationServices.firebaseInit(context);
|
||||
// NotificationServices().setupInteractMessage(controller);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -124,87 +110,75 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
}
|
||||
|
||||
|
||||
List<PersistentBottomNavBarItem> _navBarsItems() {
|
||||
return [
|
||||
PersistentBottomNavBarItem(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.home),
|
||||
title: appLocalization(context).home_page_destination,
|
||||
activeColorPrimary: Colors.blue,
|
||||
inactiveColorPrimary: Colors.grey,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.home_outlined),
|
||||
),
|
||||
PersistentBottomNavBarItem(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.settings),
|
||||
title: appLocalization(context).manager_page_destination,
|
||||
activeColorPrimary: Colors.blue,
|
||||
inactiveColorPrimary: Colors.grey,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.settings_outlined),
|
||||
),
|
||||
PersistentBottomNavBarItem(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.location_on),
|
||||
title: appLocalization(context).map_page_destination,
|
||||
activeColorPrimary: Colors.blue,
|
||||
inactiveColorPrimary: Colors.grey,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.location_on_outlined),
|
||||
),
|
||||
PersistentBottomNavBarItem(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.history),
|
||||
title: appLocalization(context).history_page_destination,
|
||||
activeColorPrimary: Colors.blue,
|
||||
inactiveColorPrimary: Colors.grey,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.history_outlined),
|
||||
),
|
||||
PersistentBottomNavBarItem(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.group),
|
||||
title: appLocalization(context).group_page_destination,
|
||||
activeColorPrimary: Colors.blue,
|
||||
inactiveColorPrimary: Colors.grey,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.group_outlined),
|
||||
),
|
||||
// PersistentBottomNavBarItem(
|
||||
// icon: IconConstants.instance
|
||||
// .getMaterialIcon(Icons.notifications_outlined),
|
||||
// title: appLocalization(context).notification,
|
||||
// activeColorPrimary: Colors.blue,
|
||||
// inactiveColorPrimary: Colors.grey,
|
||||
// inactiveIcon: IconConstants.instance
|
||||
// .getMaterialIcon(Icons.notifications_outlined),
|
||||
// ),
|
||||
];
|
||||
}
|
||||
|
||||
List<Widget> _buildScreens() {
|
||||
return [
|
||||
BlocProvider(
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<PersistentTabConfig> tabs = [
|
||||
PersistentTabConfig(
|
||||
screen: BlocProvider(
|
||||
child: const HomeScreen(),
|
||||
blocBuilder: () => HomeBloc(),
|
||||
),
|
||||
BlocProvider(
|
||||
item: ItemConfig(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.home),
|
||||
title: appLocalization(context).home_page_destination,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.home_outlined),
|
||||
iconSize: 30,
|
||||
),
|
||||
),
|
||||
PersistentTabConfig(
|
||||
screen: BlocProvider(
|
||||
child: const DevicesManagerScreen(),
|
||||
blocBuilder: () => DevicesManagerBloc()),
|
||||
BlocProvider(
|
||||
blocBuilder: () => DevicesManagerBloc(),
|
||||
),
|
||||
item: ItemConfig(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.settings),
|
||||
title: appLocalization(context).manager_page_destination,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.settings_outlined),
|
||||
iconSize: 30,
|
||||
),
|
||||
),
|
||||
PersistentTabConfig(
|
||||
screen: BlocProvider(
|
||||
child: const MapScreen(),
|
||||
blocBuilder: () => MapBloc(),
|
||||
),
|
||||
BlocProvider(
|
||||
item: ItemConfig(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.location_on),
|
||||
title: appLocalization(context).map_page_destination,
|
||||
inactiveIcon: IconConstants.instance
|
||||
.getMaterialIcon(Icons.location_on_outlined),
|
||||
iconSize: 30,
|
||||
),
|
||||
),
|
||||
PersistentTabConfig(
|
||||
screen: BlocProvider(
|
||||
child: const DeviceLogsScreen(),
|
||||
blocBuilder: () => DeviceLogsBloc(),
|
||||
),
|
||||
BlocProvider(
|
||||
item: ItemConfig(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.history),
|
||||
title: appLocalization(context).history_page_destination,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.history_outlined),
|
||||
iconSize: 30,
|
||||
),
|
||||
),
|
||||
PersistentTabConfig(
|
||||
screen: BlocProvider(
|
||||
child: const InterFamilyScreen(),
|
||||
blocBuilder: () => InterFamilyBloc(),
|
||||
),
|
||||
item: ItemConfig(
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.group),
|
||||
title: appLocalization(context).group_page_destination,
|
||||
inactiveIcon:
|
||||
IconConstants.instance.getMaterialIcon(Icons.group_outlined),
|
||||
iconSize: 30,
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return StreamBuilder<bool>(
|
||||
stream: mainBloc.streamThemeMode,
|
||||
initialData: isLight,
|
||||
@@ -220,7 +194,7 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
SizedBox(
|
||||
width: context.lowValue,
|
||||
),
|
||||
Text(userSnapshot.data?.name ?? "")
|
||||
Flexible(child: Text(userSnapshot.data?.name ?? ""))
|
||||
],
|
||||
);
|
||||
}),
|
||||
@@ -353,41 +327,38 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
],
|
||||
),
|
||||
body: PersistentTabView(
|
||||
context,
|
||||
stateManagement: false,
|
||||
controller: controller,
|
||||
screens: _buildScreens(),
|
||||
items: _navBarsItems(),
|
||||
handleAndroidBackButtonPress: true,
|
||||
resizeToAvoidBottomInset: true,
|
||||
stateManagement: true,
|
||||
tabs: tabs,
|
||||
navBarBuilder: (navBarConfig) => Style6BottomNavBar(
|
||||
navBarConfig: navBarConfig,
|
||||
navBarDecoration: NavBarDecoration(
|
||||
color: themeModeSnapshot.data! ? Colors.white : Colors.black,
|
||||
borderRadius: BorderRadius.circular(context.mediumValue),
|
||||
padding: const EdgeInsets.all(10)),
|
||||
),
|
||||
backgroundColor:
|
||||
themeModeSnapshot.data! ? Colors.white : Colors.black,
|
||||
decoration: NavBarDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
colorBehindNavBar:
|
||||
themeModeSnapshot.data! ? Colors.white : Colors.black,
|
||||
),
|
||||
animationSettings: const NavBarAnimationSettings(
|
||||
navBarItemAnimation: ItemAnimationSettings(
|
||||
duration: Duration(milliseconds: 200),
|
||||
curve: Curves.bounceInOut,
|
||||
),
|
||||
screenTransitionAnimation: ScreenTransitionAnimationSettings(
|
||||
animateTabTransition: true,
|
||||
navBarOverlap: const NavBarOverlap.none(),
|
||||
// margin: EdgeInsets.only(
|
||||
// left: context.lowValue,
|
||||
// bottom: context.dynamicHeight(0.02),
|
||||
// right: context.lowValue),
|
||||
screenTransitionAnimation: const ScreenTransitionAnimation(
|
||||
curve: Curves.bounceInOut,
|
||||
duration: Duration(milliseconds: 200),
|
||||
),
|
||||
),
|
||||
navBarStyle: NavBarStyle.style13,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getBellNotification() async {
|
||||
await apiServices.execute(context, () async {
|
||||
bell = await apiServices.getBellNotifications("0", "20");
|
||||
mainBloc.bellBloc.add(bell);
|
||||
});
|
||||
}
|
||||
|
||||
bool checkStatus(List<BellItems> bells) {
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:google_maps_cluster_manager_2/google_maps_cluster_manager_2.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart'
|
||||
hide ClusterManager, Cluster;
|
||||
import 'package:sfm_app/feature/devices/device_model.dart';
|
||||
import 'package:sfm_app/bloc/map_bloc.dart';
|
||||
import 'package:sfm_app/feature/map/widget/on_tap_marker_widget.dart';
|
||||
import 'package:sfm_app/product/base/bloc/base_bloc.dart';
|
||||
import 'package:sfm_app/product/constant/icon/icon_constants.dart';
|
||||
import 'package:sfm_app/product/permission/location_permission.dart';
|
||||
import 'package:sfm_app/product/services/api_services.dart';
|
||||
|
||||
import '../../bloc/map_bloc.dart';
|
||||
import '../../product/base/bloc/base_bloc.dart';
|
||||
import '../../product/constant/enums/app_theme_enums.dart';
|
||||
import '../../product/constant/icon/icon_constants.dart';
|
||||
import '../../product/services/api_services.dart';
|
||||
import '../../product/utils/permission_handler.dart';
|
||||
import '../devices/device_model.dart';
|
||||
import 'widget/on_tap_marker_widget.dart';
|
||||
|
||||
class MapScreen extends StatefulWidget {
|
||||
const MapScreen({super.key});
|
||||
@@ -37,7 +36,7 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||
APIServices apiServices = APIServices();
|
||||
final streamController = StreamController<GoogleMapController>.broadcast();
|
||||
List<Device> devices = [];
|
||||
Completer<GoogleMapController> _controller = Completer();
|
||||
final Completer<GoogleMapController> _controller = Completer();
|
||||
List<String> imageAssets = [
|
||||
IconConstants.instance.getIcon("normal_icon"),
|
||||
IconConstants.instance.getIcon("offline_icon"),
|
||||
@@ -57,6 +56,7 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||
Timer? checkThemeTimer;
|
||||
Timer? getMarker;
|
||||
String themeMode = '';
|
||||
bool _isDisposed = false;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -72,19 +72,21 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_isDisposed = true;
|
||||
checkThemeTimer?.cancel();
|
||||
getMarker?.cancel();
|
||||
_controller = Completer();
|
||||
streamController.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onMapCreated(GoogleMapController controller) {
|
||||
if (!_isDisposed && !streamController.isClosed) {
|
||||
_controller.complete(controller);
|
||||
streamController.add(controller);
|
||||
clusterManager.setMapId(controller.mapId);
|
||||
checkTheme();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -116,12 +118,15 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||
clusterManager.updateMap();
|
||||
},
|
||||
polylines: {
|
||||
if (polylinesSnapshot.data != null &&
|
||||
polylinesSnapshot.data!.isNotEmpty) ...[
|
||||
Polyline(
|
||||
polylineId: const PolylineId('router'),
|
||||
points: polylinesSnapshot.data ?? [],
|
||||
points: polylinesSnapshot.data!,
|
||||
color: Colors.deepPurpleAccent,
|
||||
width: 8,
|
||||
),
|
||||
]
|
||||
},
|
||||
style: mapThemeSnapshot.data,
|
||||
);
|
||||
@@ -169,11 +174,11 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||
return ClusterManager<Device>(
|
||||
devices,
|
||||
_updateMarkers,
|
||||
markerBuilder: _getmarkerBuilder(),
|
||||
markerBuilder: _getMarkerBuilder(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<Marker> Function(Cluster<Device>) _getmarkerBuilder() =>
|
||||
Future<Marker> Function(Cluster<Device>) _getMarkerBuilder() =>
|
||||
(cluster) async {
|
||||
return Marker(
|
||||
markerId: MarkerId(
|
||||
@@ -181,8 +186,9 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||
),
|
||||
position: cluster.location,
|
||||
onTap: () async {
|
||||
bool check = await checkLocationPermission(context);
|
||||
if (check == true) {
|
||||
LocationPermission permission = await checkAndRequestPermission();
|
||||
if (permission == LocationPermission.whileInUse ||
|
||||
permission == LocationPermission.always) {
|
||||
Position position = await Geolocator.getCurrentPosition();
|
||||
onTapMarker(
|
||||
// ignore: use_build_context_synchronously
|
||||
@@ -270,23 +276,12 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void getAllMarkers() async {
|
||||
String response = await apiServices.getOwnerDevices();
|
||||
if (response != "") {
|
||||
final data = jsonDecode(response);
|
||||
List<dynamic> result = data['items'];
|
||||
if (result.isNotEmpty) {
|
||||
await apiServices.execute(context, () async {
|
||||
devices.clear();
|
||||
final devicesList = Device.fromJsonDynamicList(result);
|
||||
final devicesList = await apiServices.getOwnerDevices();
|
||||
for (var device in devicesList) {
|
||||
devices.add(device);
|
||||
}
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> checkLocationPermission(context) async {
|
||||
bool check = await LocationPermissionRequest.instance
|
||||
.checkLocationPermission(context);
|
||||
return check;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
import 'show_direction_widget.dart';
|
||||
import 'show_nearest_place.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
@@ -11,7 +12,6 @@ import '../../../bloc/map_bloc.dart';
|
||||
import '../../../product/services/api_services.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
|
||||
import '../../devices/device_model.dart';
|
||||
|
||||
onTapMarker(
|
||||
@@ -72,14 +72,14 @@ onTapMarker(
|
||||
double.parse(device.settings!.latitude!),
|
||||
double.parse(device.settings!.longitude!),
|
||||
);
|
||||
mapBloc.findTheWay(
|
||||
await mapBloc.findTheWay(
|
||||
context,
|
||||
controller,
|
||||
myLocation,
|
||||
destination,
|
||||
);
|
||||
String deviceLocations = await DeviceUtils.instance
|
||||
.getFullDeviceLocation(context, device.areaPath!);
|
||||
.getFullDeviceLocation(context, device.areaPath!,device.name);
|
||||
String yourLocation =
|
||||
appLocalization(context).map_your_location;
|
||||
showDirections(
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:maps_launcher/maps_launcher.dart';
|
||||
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import '../../../bloc/map_bloc.dart';
|
||||
|
||||
showDirections(
|
||||
@@ -16,16 +15,14 @@ showDirections(
|
||||
MapBloc mapBloc,
|
||||
String originalName,
|
||||
String destinationLocation,
|
||||
double devicelat,
|
||||
double devicelng,
|
||||
double deviceLat,
|
||||
double deviceLng,
|
||||
) {
|
||||
TextEditingController originController =
|
||||
TextEditingController(text: originalName);
|
||||
TextEditingController destinationController =
|
||||
TextEditingController(text: destinationLocation);
|
||||
TextEditingController originController = TextEditingController(text: originalName);
|
||||
TextEditingController destinationController = TextEditingController(text: destinationLocation);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
// dismissDirection: DismissDirection.none,
|
||||
duration: const Duration(minutes: 5),
|
||||
content: Column(
|
||||
@@ -38,21 +35,20 @@ showDirections(
|
||||
children: [
|
||||
Text(
|
||||
appLocalization(context).map_show_direction,
|
||||
style: context.titleLargeTextStyle,
|
||||
style: context.responsiveBodyLargeWithBold,
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.centerRight,
|
||||
child: IconButton.outlined(
|
||||
onPressed: () async {
|
||||
mapBloc.sinkPolylines.add([]);
|
||||
markers.clear();
|
||||
await mapBloc.updateCameraPosition(
|
||||
controller,
|
||||
devicelat,
|
||||
devicelng,
|
||||
deviceLat,
|
||||
deviceLng,
|
||||
13.0,
|
||||
);
|
||||
List<LatLng> polylineCoordinates = [];
|
||||
mapBloc.sinkPolylines.add(polylineCoordinates);
|
||||
markers.clear();
|
||||
if (context.mounted) {
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
}
|
||||
@@ -103,17 +99,12 @@ showDirections(
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
List<LatLng> polylineCoordinates = [];
|
||||
mapBloc.sinkPolylines.add(polylineCoordinates);
|
||||
MapsLauncher.launchCoordinates(devicelat, devicelng);
|
||||
MapsLauncher.launchCoordinates(deviceLat, deviceLng);
|
||||
},
|
||||
icon: IconConstants.instance
|
||||
.getMaterialIcon(Icons.near_me_rounded),
|
||||
icon: IconConstants.instance.getMaterialIcon(Icons.near_me_rounded),
|
||||
label: Text(
|
||||
appLocalization(context).map_stream,
|
||||
),
|
||||
style: ButtonStyle(
|
||||
backgroundColor:
|
||||
WidgetStateProperty.all<Color>(Colors.blue[300]!),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
|
||||
import '../../../bloc/map_bloc.dart';
|
||||
import 'show_direction_widget.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
@@ -61,10 +61,7 @@ showNearPlacesSideSheet(
|
||||
Center(
|
||||
child: Text(
|
||||
'${appLocalization(modalBottomSheetContext).map_result}: ',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
style: context.h3
|
||||
),
|
||||
),
|
||||
Container(
|
||||
@@ -118,10 +115,7 @@ showNearPlacesSideSheet(
|
||||
children: [
|
||||
Text(
|
||||
place.result!.name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
style: context.responsiveBodyMediumWithBold,
|
||||
),
|
||||
SizedBox(height: listViewContext.lowValue),
|
||||
Text(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'dart:convert';
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../product/shared/shared_snack_bar.dart';
|
||||
import '../../../bloc/device_notification_settings_bloc.dart';
|
||||
import 'device_notification_settings_model.dart';
|
||||
@@ -73,7 +73,7 @@ class _DeviceNotificationSettingsScreenState
|
||||
hint: Text(
|
||||
appLocalization(context)
|
||||
.choose_device_dropdownButton,
|
||||
style: const TextStyle(fontSize: 14),
|
||||
style: context.responsiveBodySmall,
|
||||
),
|
||||
iconStyleData: const IconStyleData(
|
||||
icon: Icon(
|
||||
@@ -111,14 +111,12 @@ class _DeviceNotificationSettingsScreenState
|
||||
}
|
||||
|
||||
void getNotificationSetting() async {
|
||||
String? response = await apiServices.getAllSettingsNotificationOfDevices();
|
||||
final data = jsonDecode(response);
|
||||
final result = data['data'];
|
||||
// log("Data ${DeviceNotificationSettings.mapFromJson(jsonDecode(data)).values.toList()}");
|
||||
await apiServices.execute(context, () async {
|
||||
deviceNotifications =
|
||||
DeviceNotificationSettings.mapFromJson(result).values.toList();
|
||||
await apiServices.getAllSettingsNotificationOfDevices();
|
||||
deviceNotificationSettingsBloc.sinkListNotifications
|
||||
.add(deviceNotifications);
|
||||
});
|
||||
}
|
||||
|
||||
Widget listNotificationSetting(
|
||||
@@ -292,12 +290,14 @@ class _DeviceNotificationSettingsScreenState
|
||||
|
||||
void updateDeviceNotification(String thingID, Map<String, int> notifiSettings,
|
||||
bool isDataChange) async {
|
||||
await apiServices.execute(context, () async {
|
||||
int statusCode = await apiServices.updateDeviceNotificationSettings(
|
||||
thingID, notifiSettings);
|
||||
if (statusCode == 200) {
|
||||
showNoIconTopSnackBar(
|
||||
context,
|
||||
appLocalization(context).notification_update_device_settings_success,
|
||||
appLocalization(context)
|
||||
.notification_update_device_settings_success,
|
||||
Colors.green,
|
||||
Colors.white);
|
||||
} else {
|
||||
@@ -309,5 +309,6 @@ class _DeviceNotificationSettingsScreenState
|
||||
}
|
||||
isDataChange = false;
|
||||
deviceNotificationSettingsBloc.sinkIsDataChange.add(isDataChange);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../product/shared/shared_snack_bar.dart';
|
||||
import '../../../product/constant/icon/icon_constants.dart';
|
||||
import '../../../product/services/api_services.dart';
|
||||
@@ -8,7 +9,6 @@ import '../../../bloc/settings_bloc.dart';
|
||||
import '../../../product/shared/shared_input_decoration.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import 'profile_model.dart';
|
||||
|
||||
changeUserInfomation(
|
||||
@@ -38,6 +38,7 @@ changeUserInfomation(
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
if (formKey.currentState!.validate()) {
|
||||
await apiServices.execute(context,() async {
|
||||
formKey.currentState!.save();
|
||||
String latitude = user.latitude ?? "";
|
||||
String longitude = user.longitude ?? "";
|
||||
@@ -66,7 +67,44 @@ changeUserInfomation(
|
||||
Colors.redAccent,
|
||||
Colors.white);
|
||||
}
|
||||
settingsBloc.getUserProfile(context);
|
||||
Navigator.pop(modalBottomSheetContext);
|
||||
});
|
||||
// try {
|
||||
// formKey.currentState!.save();
|
||||
// String latitude = user.latitude ?? "";
|
||||
// String longitude = user.longitude ?? "";
|
||||
// Map<String, dynamic> body = {
|
||||
// "name": username,
|
||||
// "email": email,
|
||||
// "phone": tel,
|
||||
// "address": address,
|
||||
// "latitude": latitude,
|
||||
// "longitude": longitude
|
||||
// };
|
||||
// int statusCode =
|
||||
// await apiServices.updateUserProfile(body);
|
||||
// if (statusCode == 200) {
|
||||
// showNoIconTopSnackBar(
|
||||
// modalBottomSheetContext,
|
||||
// appLocalization(context)
|
||||
// .notification_update_profile_success,
|
||||
// Colors.green,
|
||||
// Colors.white);
|
||||
// } else {
|
||||
// showNoIconTopSnackBar(
|
||||
// modalBottomSheetContext,
|
||||
// appLocalization(context)
|
||||
// .notification_update_profile_failed,
|
||||
// Colors.redAccent,
|
||||
// Colors.white);
|
||||
// }
|
||||
// settingsBloc.getUserProfile(context);
|
||||
// Navigator.pop(modalBottomSheetContext);
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(context, e.toString());
|
||||
// }
|
||||
}
|
||||
},
|
||||
icon:
|
||||
@@ -205,6 +243,7 @@ changeUserInfomation(
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
if (formKey.currentState!.validate()) {
|
||||
await apiServices.execute(context,() async {
|
||||
formKey.currentState!.save();
|
||||
String latitude = user.latitude ?? "";
|
||||
String longitude = user.longitude ?? "";
|
||||
@@ -233,7 +272,9 @@ changeUserInfomation(
|
||||
Colors.redAccent,
|
||||
Colors.white);
|
||||
}
|
||||
settingsBloc.getUserProfile(context);
|
||||
Navigator.pop(modalBottomSheetContext);
|
||||
});
|
||||
}
|
||||
},
|
||||
style: const ButtonStyle(
|
||||
@@ -283,6 +324,7 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
|
||||
? IconButton(
|
||||
onPressed: () async {
|
||||
if (formKey.currentState!.validate()) {
|
||||
await apiServices.execute(context,() async {
|
||||
formKey.currentState!.save();
|
||||
Map<String, dynamic> body = {
|
||||
"password_old": oldPass,
|
||||
@@ -306,6 +348,7 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
|
||||
Colors.white);
|
||||
}
|
||||
Navigator.pop(modalBottomSheetContext);
|
||||
});
|
||||
}
|
||||
},
|
||||
icon:
|
||||
@@ -390,6 +433,7 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
|
||||
? Center(
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
await apiServices.execute(context,() async {
|
||||
if (formKey.currentState!.validate()) {
|
||||
formKey.currentState!.save();
|
||||
Map<String, dynamic> body = {
|
||||
@@ -415,6 +459,38 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
|
||||
}
|
||||
Navigator.pop(modalBottomSheetContext);
|
||||
}
|
||||
});
|
||||
// try {
|
||||
// if (formKey.currentState!.validate()) {
|
||||
// formKey.currentState!.save();
|
||||
// Map<String, dynamic> body = {
|
||||
// "password_old": oldPass,
|
||||
// "password_new": newPass,
|
||||
// };
|
||||
// int statusCode = await apiServices
|
||||
// .updateUserPassword(body);
|
||||
// if (statusCode == 200) {
|
||||
// showNoIconTopSnackBar(
|
||||
// modalBottomSheetContext,
|
||||
// appLocalization(context)
|
||||
// .notification_update_password_success,
|
||||
// Colors.green,
|
||||
// Colors.white);
|
||||
// } else {
|
||||
// showNoIconTopSnackBar(
|
||||
// modalBottomSheetContext,
|
||||
// appLocalization(context)
|
||||
// .notification_update_password_failed,
|
||||
// Colors.redAccent,
|
||||
// Colors.white);
|
||||
// }
|
||||
// Navigator.pop(modalBottomSheetContext);
|
||||
// }
|
||||
// } catch (e) {
|
||||
// if (!context.mounted) return;
|
||||
// showErrorTopSnackBarCustom(
|
||||
// context, e.toString());
|
||||
// }
|
||||
},
|
||||
style: const ButtonStyle(
|
||||
backgroundColor:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../product/constant/app/app_constants.dart';
|
||||
import '../../product/shared/shared_loading_animation.dart';
|
||||
import 'profile/profile_screen.dart';
|
||||
import '../../product/constant/icon/icon_constants.dart';
|
||||
import '../../product/extension/context_extension.dart';
|
||||
@@ -27,7 +27,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
settingsBloc = BlocProvider.of(context);
|
||||
getUserProfile();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -39,15 +38,12 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
body: StreamBuilder<User>(
|
||||
stream: settingsBloc.streamUserProfile,
|
||||
initialData: user,
|
||||
builder: (context, userSnapshot) {
|
||||
return userSnapshot.data?.id == "" || user.id == ""
|
||||
? Center(
|
||||
child: CircularProgressIndicator(
|
||||
value: context.highValue,
|
||||
),
|
||||
)
|
||||
: Column(
|
||||
if (userSnapshot.data == null) {
|
||||
settingsBloc.getUserProfile(context);
|
||||
return const SharedLoadingAnimation();
|
||||
} else {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
@@ -60,12 +56,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
child: CircleAvatar(
|
||||
radius: 50,
|
||||
child: Text(
|
||||
getAvatarContent(
|
||||
userSnapshot.data?.username ?? ""),
|
||||
style: const TextStyle(
|
||||
fontSize: 35,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
getAvatarContent(userSnapshot.data?.username ?? ""),
|
||||
style: context.dynamicResponsiveSize(36),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -76,8 +68,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
children: [
|
||||
Text(
|
||||
userSnapshot.data?.name ?? "User Name",
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w900, fontSize: 26),
|
||||
style: context.h2,
|
||||
)
|
||||
],
|
||||
),
|
||||
@@ -89,29 +80,36 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
cardContent(
|
||||
Icons.account_circle_rounded,
|
||||
appLocalization(context).profile_change_info,
|
||||
),
|
||||
userSnapshot.data ?? user),
|
||||
SizedBox(height: context.lowValue),
|
||||
cardContent(
|
||||
Icons.lock_outline,
|
||||
appLocalization(context).profile_change_pass,
|
||||
),
|
||||
userSnapshot.data ?? user),
|
||||
SizedBox(height: context.lowValue),
|
||||
cardContent(
|
||||
Icons.settings_outlined,
|
||||
appLocalization(context).profile_setting,
|
||||
),
|
||||
userSnapshot.data ?? user),
|
||||
SizedBox(height: context.lowValue),
|
||||
cardContent(
|
||||
Icons.sim_card,
|
||||
appLocalization(context).profile_sim_data,
|
||||
userSnapshot.data ?? user),
|
||||
SizedBox(height: context.lowValue),
|
||||
cardContent(
|
||||
Icons.logout_outlined,
|
||||
appLocalization(context).log_out,
|
||||
),
|
||||
userSnapshot.data ?? user),
|
||||
],
|
||||
);
|
||||
}),
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
cardContent(IconData icon, String content) {
|
||||
cardContent(IconData icon, String content, User user) {
|
||||
return GestureDetector(
|
||||
onTap: () async {
|
||||
if (icon == Icons.account_circle_rounded) {
|
||||
@@ -120,7 +118,10 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
changeUserPassword(context, settingsBloc);
|
||||
} else if (icon == Icons.settings_outlined) {
|
||||
context.push(ApplicationConstants.DEVICE_NOTIFICATIONS_SETTINGS);
|
||||
} else {
|
||||
} else if(icon == Icons.sim_card){
|
||||
context.push(ApplicationConstants.SIM_DATA_SETTINGS);
|
||||
}
|
||||
else {
|
||||
await apiServices.logOut(context);
|
||||
}
|
||||
},
|
||||
@@ -132,7 +133,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
leading: IconConstants.instance.getMaterialIcon(icon),
|
||||
title: Text(
|
||||
content,
|
||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
style: context.responsiveBodyMediumWithBold,
|
||||
),
|
||||
trailing: const Icon(
|
||||
Icons.arrow_forward_ios_outlined,
|
||||
@@ -142,12 +143,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
void getUserProfile() async {
|
||||
String data = await apiServices.getUserDetail();
|
||||
user = User.fromJson(jsonDecode(data));
|
||||
settingsBloc.sinkUserProfile.add(user);
|
||||
}
|
||||
|
||||
String getAvatarContent(String username) {
|
||||
String name = "";
|
||||
if (username.isNotEmpty) {
|
||||
|
||||
170
lib/feature/settings/sim_data/shared_sim_component.dart
Normal file
@@ -0,0 +1,170 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../../devices/device_model.dart';
|
||||
import '../../../product/extension/context_extension.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
|
||||
import '../../../product/utils/device_utils.dart';
|
||||
|
||||
class SharedSimComponent extends StatelessWidget {
|
||||
|
||||
const SharedSimComponent({super.key, required this.device});
|
||||
final Device device;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
double screenWidth = MediaQuery.of(context).size.width;
|
||||
double screenHeight = MediaQuery.of(context).size.height;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
width: screenWidth,
|
||||
height: screenHeight / 5.5,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
gradient: getGradientColor(getMonthLeft())
|
||||
),
|
||||
child: Padding(
|
||||
padding: context.paddingLow,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
device.name ?? "name",
|
||||
style: const TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
_buildStatusChip(context,device.state ?? -1),
|
||||
],
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
// Time period
|
||||
Text(
|
||||
"${appLocalization(context).time_title}: ${convertStartTime()} - ${convertExpireTime()}",
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
SizedBox(height: context.lowValue),
|
||||
_buildDurationDisplay(context),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusChip(BuildContext context,int state) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Colors.white),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Colors.white,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.circle,
|
||||
color: DeviceUtils.instance.getTableRowColor(context, state),
|
||||
size: 12,
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
DeviceUtils.instance.checkStateDevice(context, state),
|
||||
style: TextStyle(
|
||||
color: DeviceUtils.instance.getTableRowColor(context, state),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDurationDisplay(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.baseline,
|
||||
textBaseline: TextBaseline.alphabetic,
|
||||
children: [
|
||||
Text(
|
||||
"${getMonthLeft()}",
|
||||
style: const TextStyle(
|
||||
fontSize: 40,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
appLocalization(context).sim_data_month_left_message,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
String convertStartTime(){
|
||||
return DateFormat('dd/MM/yyyy').format(device.createdAt!);
|
||||
}
|
||||
|
||||
String convertExpireTime() {
|
||||
final expireDate = _calculateExpireDate();
|
||||
return DateFormat('dd/MM/yyyy').format(expireDate);
|
||||
}
|
||||
|
||||
int getMonthLeft() {
|
||||
final expireDate = _calculateExpireDate();
|
||||
final now = DateTime.now();
|
||||
|
||||
int totalMonths = (expireDate.year - now.year) * 12 + (expireDate.month - now.month);
|
||||
|
||||
if (expireDate.day < now.day) {
|
||||
totalMonths -= 1;
|
||||
}
|
||||
|
||||
return totalMonths;
|
||||
}
|
||||
|
||||
DateTime _calculateExpireDate() {
|
||||
return DateTime(
|
||||
device.createdAt!.year + 3,
|
||||
device.createdAt!.month,
|
||||
device.createdAt!.day,
|
||||
device.createdAt!.hour,
|
||||
device.createdAt!.minute,
|
||||
device.createdAt!.second,
|
||||
device.createdAt!.millisecond,
|
||||
device.createdAt!.microsecond,
|
||||
);
|
||||
}
|
||||
|
||||
LinearGradient getGradientColor(int monthLeft){
|
||||
if(monthLeft <= 3){
|
||||
return const LinearGradient(
|
||||
colors: [Color(0xFFff4b1f), Color(0xFFff9068)],
|
||||
);
|
||||
}else{
|
||||
return const LinearGradient(
|
||||
colors: [Color(0xFF56ab2f), Color(0xFFa8e063)],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
55
lib/feature/settings/sim_data/sim_data_screen.dart
Normal file
@@ -0,0 +1,55 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'shared_sim_component.dart';
|
||||
import '../../../product/services/language_services.dart';
|
||||
import '../../../product/shared/shared_loading_animation.dart';
|
||||
import '../../../bloc/sim_data_bloc.dart';
|
||||
import '../../../product/base/bloc/base_bloc.dart';
|
||||
|
||||
class SimDataScreen extends StatefulWidget {
|
||||
const SimDataScreen({super.key});
|
||||
@override
|
||||
State<SimDataScreen> createState() => _SimDataScreenState();
|
||||
}
|
||||
|
||||
class _SimDataScreenState extends State<SimDataScreen> {
|
||||
late SimDataBloc simDataBloc;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
simDataBloc = BlocProvider.of(context);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(appLocalization(context).profile_sim_data),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: StreamBuilder(
|
||||
stream: simDataBloc.streamDevices,
|
||||
builder: (context, devicesSnapshot) {
|
||||
if (devicesSnapshot.data == null) {
|
||||
simDataBloc.getOwnerDevices(context);
|
||||
return const SharedLoadingAnimation();
|
||||
} else if (devicesSnapshot.data!.isEmpty) {
|
||||
return Center(
|
||||
child: Text(appLocalization(context).main_no_data),
|
||||
);
|
||||
} else {
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
children: devicesSnapshot.data!.map(
|
||||
(device) {
|
||||
return SharedSimComponent(device: device,);
|
||||
},
|
||||
).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:alarm/alarm.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'feature/main/main_screen.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'
|
||||
show PersistentTabController;
|
||||
|
||||
import 'firebase_options.dart';
|
||||
import 'product/lang/l10n/app_localizations.dart';
|
||||
import 'product/services/api_services.dart';
|
||||
import 'product/services/notification_services.dart';
|
||||
import 'product/services/theme_services.dart';
|
||||
@@ -13,13 +15,17 @@ import 'bloc/main_bloc.dart';
|
||||
import 'product/base/bloc/base_bloc.dart';
|
||||
import 'product/constant/navigation/navigation_router.dart';
|
||||
|
||||
PersistentTabController controller = PersistentTabController(initialIndex: 0);
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp();
|
||||
FirebaseMessaging
|
||||
.onBackgroundMessage(firebaseMessagingBackgroundHandler);
|
||||
// NotificationServices().setupInteractMessage();
|
||||
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
name: "sfm-notification");
|
||||
FirebaseMessaging.onBackgroundMessage(
|
||||
NotificationServices.firebaseMessagingBackgroundHandler);
|
||||
await Alarm.init();
|
||||
await Alarm.stopAll();
|
||||
runApp(
|
||||
BlocProvider(
|
||||
child: const MyApp(),
|
||||
@@ -28,15 +34,6 @@ void main() async {
|
||||
);
|
||||
}
|
||||
|
||||
// @pragma('vm:entry-point')
|
||||
// Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
// log("Full background message payload: ${message.toMap()}");
|
||||
// await Firebase.initializeApp();
|
||||
// final notificationServices = NotificationServices();
|
||||
// await notificationServices.initLocalNotifications();
|
||||
// await notificationServices.showNotification(message);
|
||||
// log("Background message handled: ${message.data['title']}");
|
||||
// }
|
||||
class MyApp extends StatefulWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
@@ -70,22 +67,14 @@ class _MyAppState extends State<MyApp> {
|
||||
_themeData = theme;
|
||||
mainBloc.sinkTheme.add(_themeData);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
mainBloc = BlocProvider.of(context);
|
||||
// notificationServices.initLocalNotifications();
|
||||
// notificationServices.firebaseInit(context);
|
||||
// notificationServices.setupInteractMessage();
|
||||
notificationServices.getDeviceToken().then((token){
|
||||
print("Firebase Token: $token");
|
||||
sendNotificationToken(token);
|
||||
});
|
||||
}
|
||||
|
||||
void sendNotificationToken (String token) async {
|
||||
int statusCode = await apiServices.sendNotificationToken(token);
|
||||
log("Notification Send StatusCode : $statusCode");
|
||||
notificationServices.initialize();
|
||||
notificationServices.firebaseInit(context);
|
||||
notificationServices.setupInteractMessage(controller);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -114,8 +103,7 @@ class _MyAppState extends State<MyApp> {
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
locale: languageSnapshot.data,
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -30,8 +30,7 @@ class RequestPermissionDialog {
|
||||
child: Text(
|
||||
"Alow app to use $content permission",
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 18),
|
||||
style: context.responsiveBodyLargeWithBold,
|
||||
),
|
||||
),
|
||||
Divider(height: dialogContext.lowValue),
|
||||
@@ -87,8 +86,8 @@ class RequestPermissionDialog {
|
||||
child: Text(
|
||||
appLocalization(showCupertinoDialogContext).allow_message),
|
||||
onPressed: () {
|
||||
Navigator.pop(showCupertinoDialogContext);
|
||||
AppSettings.openAppSettings(type: appSettingsType);
|
||||
Navigator.pop(showCupertinoDialogContext);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: constant_identifier_names, non_constant_identifier_names
|
||||
|
||||
class ApplicationConstants {
|
||||
static const APP_NAME = "Smatec SFM";
|
||||
@@ -21,8 +21,10 @@ class ApplicationConstants {
|
||||
static const DEVICE_LOGS_PATH = "/device-logs";
|
||||
static const GROUP_PATH = "/groups";
|
||||
static const DEVICE_NOTIFICATIONS_SETTINGS = "/device-notifications-settings";
|
||||
static const SIM_DATA_SETTINGS = "/sim-data-settings";
|
||||
static const OWNER_GROUP = "owner";
|
||||
static const PARTICIPANT_GROUP = "participant";
|
||||
static const NO_DATA = "no_data";
|
||||
static const LOADING = "loading";
|
||||
static int CALL_API_TIMEOUT = 30;
|
||||
}
|
||||
|
||||
@@ -13,4 +13,5 @@ enum AppRoutes {
|
||||
HISTORY,
|
||||
GROUPS,
|
||||
GROUP_DETAIL,
|
||||
SIM_DATA_SETTING,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../../../bloc/sim_data_bloc.dart';
|
||||
import '../../../feature/settings/sim_data/sim_data_screen.dart';
|
||||
import '../../../bloc/device_detail_bloc.dart';
|
||||
import '../../../feature/devices/device_detail/device_detail_screen.dart';
|
||||
import '../../../bloc/device_notification_settings_bloc.dart';
|
||||
@@ -151,6 +154,16 @@ GoRouter goRouter() {
|
||||
),
|
||||
transitionsBuilder: transitionsRightToLeft),
|
||||
),
|
||||
GoRoute(
|
||||
path: ApplicationConstants.SIM_DATA_SETTINGS,
|
||||
name: AppRoutes.SIM_DATA_SETTING.name,
|
||||
pageBuilder: (context, state) => CustomTransitionPage(
|
||||
child: BlocProvider(
|
||||
child: const SimDataScreen(),
|
||||
blocBuilder: () => SimDataBloc(),
|
||||
),
|
||||
transitionsBuilder: transitionsRightToLeft),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||