diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..e77609d
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,2 @@
+ENV_NAME=development
+BASE_URL=https://syncrow-dev.azurewebsites.net
\ No newline at end of file
diff --git a/.env.production b/.env.production
new file mode 100644
index 0000000..4e9dcb8
--- /dev/null
+++ b/.env.production
@@ -0,0 +1,2 @@
+ENV_NAME=production
+BASE_URL=https://syncrow-staging.azurewebsites.net
\ No newline at end of file
diff --git a/.env.staging b/.env.staging
new file mode 100644
index 0000000..9565b42
--- /dev/null
+++ b/.env.staging
@@ -0,0 +1,2 @@
+ENV_NAME=staging
+BASE_URL=https://syncrow-staging.azurewebsites.net
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 3a83c2f..c3e0679 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,27 +1,42 @@
-# See https://www.dartlang.org/guides/libraries/private-files
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
-# Files and directories created by pub
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+*.env
+# Flutter/Dart/Pub related
+**/doc/api/
+**/ios/Flutter/.last_build_id
.dart_tool/
-.packages
-build/
-# If you're building an application, you may want to check-in your pubspec.lock
-pubspec.lock
-
-# Directory created by dartdoc
-# If you don't generate documentation locally you can remove this line.
-doc/api/
-
-# dotenv environment variables file
-.env*
-
-# Avoid committing generated Javascript files:
-*.dart.js
-*.info.json # Produced by the --dump-info flag.
-*.js # When generated by dart2js. Don't specify *.js if your
- # project includes source files written in JavaScript.
-*.js_
-*.js.deps
-*.js.map
-
.flutter-plugins
.flutter-plugins-dependencies
+.pub-cache/
+/build/
+
+# Symbolication related
+app.*.symbols
+
+# Obfuscation related
+app.*.map.json
+
+# Android Studio will place build artifacts here
+/android/app/debug
+/android/app/profile
+/android/app/release
diff --git a/.metadata b/.metadata
new file mode 100644
index 0000000..b2bb4f6
--- /dev/null
+++ b/.metadata
@@ -0,0 +1,36 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+ revision: "ef1af02aead6fe2414f3aafa5a61087b610e1332"
+ channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+ platforms:
+ - platform: root
+ create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+ base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+ - platform: android
+ create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+ base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+ - platform: ios
+ create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+ base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+ - platform: web
+ create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+ base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332
+
+ # User provided section
+
+ # List of Local paths (relative to this file) that should be
+ # ignored by the migrate tool.
+ #
+ # Files that are not part of the templates will be ignored by default.
+ unmanaged_files:
+ - 'lib/main.dart'
+ - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..b6f83bd
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,61 @@
+{
+ "configurations": [
+
+ {
+
+ "name": "DEVELOPMENT",
+
+ "request": "launch",
+
+ "type": "dart",
+
+ "args": [
+
+ "--dart-define",
+
+ "FLAVOR=development"
+
+ ],
+
+ "flutterMode": "debug"
+
+ },{
+
+ "name": "STAGING",
+
+ "request": "launch",
+
+ "type": "dart",
+
+ "args": [
+
+ "--dart-define",
+
+ "FLAVOR=staging"
+
+ ],
+
+ "flutterMode": "debug"
+
+ },{
+
+ "name": "PRODUCTION",
+
+ "request": "launch",
+
+ "type": "dart",
+
+ "args": [
+
+ "--dart-define",
+
+ "FLAVOR=production"
+
+ ],
+
+ "flutterMode": "debug"
+
+ },
+
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..418c018
--- /dev/null
+++ b/README.md
@@ -0,0 +1,98 @@
+# syncrow_app
+
+This is the mobile application project, developed with Flutter for Syncrow IOT Project..
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
+
+## Development Process
+
+1- You'll receive a task assignment in Jira that's been assigned to you.
+
+2- In Jira, change the status of the task to "in progress".
+
+3- Create a new branch for the task using the command "git checkout -b task_number".
+
+4- Make your changes and commit them using the command "git commit -m 'Add my changes'".
+
+5- Push your changes to the task branch using the command "git push origin task-branch".
+Open a pull request on the DEV branch and add a reviewer to it.
+
+6- Once the reviewer approves your pull request, merge your changes into the DEV branch.
+
+7- Use the command "git checkout DEV" to switch to the DEV branch.
+
+8- Upload apk file and ipa file to Firebase distribution (you can find the steps to upload your app to Firebase Distribution for both Android and iOS platforms in the Deployment section).
+
+9- Update the task status in Jira to "QA".
+## Deployment
+
+### Android
+
+**- Firebase Distribution:**
+
+To test the app, we use Firebase Distribution to send testing builds of the app to the testers.
+
+- Create an Android build for testing with the command: `flutter build apk --dart-define FLAVOR=staging --build-name={build_version}-qa --build-number={build_number}`.
+
+- Upload the apk file to Firebase distribution
+
+**- Google Play Store:**
+
+1- To create an APK file from your Flutter project, you can use the command: `flutter build apk --release`
+
+2- Upload your APK file to the Google Play Console and provide all necessary information about the release, such as release notes and version number.
+
+3- Submit your app for review, which can take several days to complete. Once your app is approved, it will be available for download on the Google Play Store.
+
+### iOS
+
+**- Firebase Distribution:**
+
+To test the app, we use Firebase Distribution to send testing builds of the app to the testers.
+
+1- Create an iOS for testing with the command: `flutter build ios --dart-define FLAVOR=staging --build-name=1.0.0-qa --build-number=1`.
+
+2- Create an archive of your app: Open Xcode and go to the "Product" menu, then select "Archive" to create an archive of your app. Make sure to select the "Generic iOS Device" as the build destination.
+
+3- Once the archive is complete, go to the "Organizer" window and select the archive you just created and click on the "Distribute App" button.
+
+4- Choose "Ad Hoc" as the distribution method and click "Next".
+
+5- Choose the appropriate signing identity and click "Export".
+
+6- Choose a location to save the exported app and click "Save".
+
+7- Your HOC build is now ready to be signed and uploaded to Firebase Distribution.
+
+8- Upload the ipa file to Firebase distribution
+
+You can also create an archive through these commands lines:
+
+1- Create an iOS for testing with the command: `flutter build ios --dart-define FLAVOR=staging --build-name={build_version}-qa --build-number={build_number}`.
+
+2- Create an archive with this command: `xcodebuild -workspace Runner.xcworkspace -scheme Runner -archivePath "build/Runner.xcarchive" archive`.
+
+3- Export the ipa file with this command: `-exportArchive -archivePath "build/Runner.xcarchive" -exportPath "build/exported_ipas" -exportOptionsPlist "build/ExportOptions.plist"`
+
+**- Apple Store**
+
+1- Build your app: Use Flutter to build your app for release. To build your app for iOS, use the command: `flutter build ios --release --no-codesign`
+
+Note: The --no-codesign flag will tell Flutter not to sign your app, since you'll be doing that later with Xcode.
+
+2- Create an archive of your app: Open Xcode and go to the "Product" menu, then select "Archive" to create an archive of your app. Make sure to select the "Generic iOS Device" as the build destination.
+
+3- Validate and upload your app: Once the archive is created, Xcode will automatically open the Organizer window. Select the archive you just created and click the "Validate App" button to validate your app. Once the validation process is complete, click the "Distribute App" button to upload your app to the App Store Connect.
+
+4- Submit your app for review: After uploading your app, you'll need to submit it for review by Apple. This process can take several days, and you'll be notified by email once your app is approved or rejected.
diff --git a/analysis_options.yaml b/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # 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
diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..6f56801
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/android/app/build.gradle b/android/app/build.gradle
new file mode 100644
index 0000000..4a14eae
--- /dev/null
+++ b/android/app/build.gradle
@@ -0,0 +1,71 @@
+plugins {
+ id "com.android.application"
+ // START: FlutterFire Configuration
+ id 'com.google.gms.google-services'
+ id 'com.google.firebase.crashlytics'
+ // END: FlutterFire Configuration
+ id "kotlin-android"
+ id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+ localPropertiesFile.withReader('UTF-8') { reader ->
+ localProperties.load(reader)
+ }
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+ flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+ flutterVersionName = '1.0'
+}
+
+android {
+ namespace "com.example.syncrow_application"
+ compileSdkVersion 34
+ ndkVersion flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+
+ defaultConfig {
+ // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+ applicationId "com.example.syncrow_application"
+ // You can update the following values to match your application needs.
+ // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+ minSdkVersion 21
+ targetSdkVersion flutter.targetSdkVersion
+ versionCode flutterVersionCode.toInteger()
+ versionName flutterVersionName
+ }
+
+ buildTypes {
+ release {
+ // TODO: Add your own signing config for the release build.
+ // Signing with the debug keys for now, so `flutter run --release` works.
+ signingConfig signingConfigs.debug
+ }
+ }
+}
+
+flutter {
+ source '../..'
+}
+
+dependencies {}
diff --git a/android/app/google-services.json b/android/app/google-services.json
new file mode 100644
index 0000000..b304aae
--- /dev/null
+++ b/android/app/google-services.json
@@ -0,0 +1,48 @@
+{
+ "project_info": {
+ "project_number": "427332280600",
+ "project_id": "test2-8a3d2",
+ "storage_bucket": "test2-8a3d2.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:427332280600:android:550f67441246cb1a0c7e6d",
+ "android_client_info": {
+ "package_name": "com.example.syncrow_application"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ },
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:427332280600:android:bb6047adeeb80fb00c7e6d",
+ "android_client_info": {
+ "package_name": "com.example.syncrow_application"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyA5qOErxdm0zJmoHIB0TixfebYEsNRpwV0"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ad16c69
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/kotlin/com/example/syncrow_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/syncrow_app/MainActivity.kt
new file mode 100644
index 0000000..1e03aee
--- /dev/null
+++ b/android/app/src/main/kotlin/com/example/syncrow_app/MainActivity.kt
@@ -0,0 +1,6 @@
+package com.example.syncrow_application
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/android/app/src/main/res/drawable-v21/launch_background.xml b/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/drawable/launch_background.xml b/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..fdc23c4
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..63a7e34
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..629b51e
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f2bc9ef
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..837c4b2
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..e83fb5d
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,30 @@
+buildscript {
+ ext.kotlin_version = '1.7.10'
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+ project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+ project.evaluationDependsOn(':app')
+}
+
+tasks.register("clean", Delete) {
+ delete rootProject.buildDir
+}
diff --git a/android/gradle.properties b/android/gradle.properties
new file mode 100644
index 0000000..598d13f
--- /dev/null
+++ b/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx4G
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..60df464
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 03 23:37:40 EET 2024
+distributionBase=GRADLE_USER_HOME
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..0e6c956
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1,33 @@
+pluginManagement {
+ def flutterSdkPath = {
+ def properties = new Properties()
+ file("local.properties").withInputStream { properties.load(it) }
+ def flutterSdkPath = properties.getProperty("flutter.sdk")
+ assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+ return flutterSdkPath
+ }
+ settings.ext.flutterSdkPath = flutterSdkPath()
+
+ includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
+
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+
+ plugins {
+ id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
+ }
+}
+
+plugins {
+ id "dev.flutter.flutter-plugin-loader" version "1.0.0"
+ id "com.android.application" version "7.3.0" apply false
+ // START: FlutterFire Configuration
+ id "com.google.gms.google-services" version "4.3.15" apply false
+ id "com.google.firebase.crashlytics" version "2.8.1" apply false
+ // END: FlutterFire Configuration
+}
+
+include ":app"
diff --git a/assets/fonts/AftikaRegular.ttf b/assets/fonts/AftikaRegular.ttf
new file mode 100644
index 0000000..5ca4dc5
Binary files /dev/null and b/assets/fonts/AftikaRegular.ttf differ
diff --git a/assets/icons/3GangSwitch.svg b/assets/icons/3GangSwitch.svg
new file mode 100644
index 0000000..ecb9992
--- /dev/null
+++ b/assets/icons/3GangSwitch.svg
@@ -0,0 +1,19 @@
+
diff --git a/assets/icons/AC.svg b/assets/icons/AC.svg
new file mode 100644
index 0000000..92f6fc5
--- /dev/null
+++ b/assets/icons/AC.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/CO2.svg b/assets/icons/CO2.svg
new file mode 100644
index 0000000..09a2db6
--- /dev/null
+++ b/assets/icons/CO2.svg
@@ -0,0 +1,7 @@
+
diff --git a/assets/icons/Curtain.svg b/assets/icons/Curtain.svg
new file mode 100644
index 0000000..a2e4f23
--- /dev/null
+++ b/assets/icons/Curtain.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/Devices-fill.svg b/assets/icons/Devices-fill.svg
new file mode 100644
index 0000000..de6e9af
--- /dev/null
+++ b/assets/icons/Devices-fill.svg
@@ -0,0 +1,13 @@
+
diff --git a/assets/icons/Devices.svg b/assets/icons/Devices.svg
new file mode 100644
index 0000000..51d527c
--- /dev/null
+++ b/assets/icons/Devices.svg
@@ -0,0 +1,21 @@
+
diff --git a/assets/icons/DoorLockLinkage.svg b/assets/icons/DoorLockLinkage.svg
new file mode 100644
index 0000000..b9730e3
--- /dev/null
+++ b/assets/icons/DoorLockLinkage.svg
@@ -0,0 +1,13 @@
+
diff --git a/assets/icons/DoorLockLock.svg b/assets/icons/DoorLockLock.svg
new file mode 100644
index 0000000..931e17f
--- /dev/null
+++ b/assets/icons/DoorLockLock.svg
@@ -0,0 +1,61 @@
+
diff --git a/assets/icons/DoorLockMembers.svg b/assets/icons/DoorLockMembers.svg
new file mode 100644
index 0000000..f7a60fb
--- /dev/null
+++ b/assets/icons/DoorLockMembers.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/DoorLockPassword.svg b/assets/icons/DoorLockPassword.svg
new file mode 100644
index 0000000..583035b
--- /dev/null
+++ b/assets/icons/DoorLockPassword.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/DoorLockRecords.svg b/assets/icons/DoorLockRecords.svg
new file mode 100644
index 0000000..125f3d9
--- /dev/null
+++ b/assets/icons/DoorLockRecords.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/Facebook.svg b/assets/icons/Facebook.svg
new file mode 100644
index 0000000..929d386
--- /dev/null
+++ b/assets/icons/Facebook.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/Gateway.svg b/assets/icons/Gateway.svg
new file mode 100644
index 0000000..e293999
--- /dev/null
+++ b/assets/icons/Gateway.svg
@@ -0,0 +1,19 @@
+
diff --git a/assets/icons/Google.svg b/assets/icons/Google.svg
new file mode 100644
index 0000000..750ccdd
--- /dev/null
+++ b/assets/icons/Google.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/icons/Layout-fill.svg b/assets/icons/Layout-fill.svg
new file mode 100644
index 0000000..0e69648
--- /dev/null
+++ b/assets/icons/Layout-fill.svg
@@ -0,0 +1,13 @@
+
diff --git a/assets/icons/Layout.svg b/assets/icons/Layout.svg
new file mode 100644
index 0000000..4756e3b
--- /dev/null
+++ b/assets/icons/Layout.svg
@@ -0,0 +1,21 @@
+
diff --git a/assets/icons/Light.svg b/assets/icons/Light.svg
new file mode 100644
index 0000000..c8cfff5
--- /dev/null
+++ b/assets/icons/Light.svg
@@ -0,0 +1,15 @@
+
diff --git a/assets/icons/Menu-fill.svg b/assets/icons/Menu-fill.svg
new file mode 100644
index 0000000..db5821c
--- /dev/null
+++ b/assets/icons/Menu-fill.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/Menu.svg b/assets/icons/Menu.svg
new file mode 100644
index 0000000..072d3e9
--- /dev/null
+++ b/assets/icons/Menu.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/MenuIcons/GeneralSettingsIcons/clearCach.svg b/assets/icons/MenuIcons/GeneralSettingsIcons/clearCach.svg
new file mode 100644
index 0000000..20ec573
--- /dev/null
+++ b/assets/icons/MenuIcons/GeneralSettingsIcons/clearCach.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/GeneralSettingsIcons/language.svg b/assets/icons/MenuIcons/GeneralSettingsIcons/language.svg
new file mode 100644
index 0000000..15bd55d
--- /dev/null
+++ b/assets/icons/MenuIcons/GeneralSettingsIcons/language.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/GeneralSettingsIcons/networkDiagnosis.svg b/assets/icons/MenuIcons/GeneralSettingsIcons/networkDiagnosis.svg
new file mode 100644
index 0000000..89edd09
--- /dev/null
+++ b/assets/icons/MenuIcons/GeneralSettingsIcons/networkDiagnosis.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/GeneralSettingsIcons/temperatureUnit.svg b/assets/icons/MenuIcons/GeneralSettingsIcons/temperatureUnit.svg
new file mode 100644
index 0000000..ff1291a
--- /dev/null
+++ b/assets/icons/MenuIcons/GeneralSettingsIcons/temperatureUnit.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/MenuIcons/GeneralSettingsIcons/touchTone.svg b/assets/icons/MenuIcons/GeneralSettingsIcons/touchTone.svg
new file mode 100644
index 0000000..2d1b5eb
--- /dev/null
+++ b/assets/icons/MenuIcons/GeneralSettingsIcons/touchTone.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/MenuIcons/GeneralSettingsIcons/voiceAssistant.svg b/assets/icons/MenuIcons/GeneralSettingsIcons/voiceAssistant.svg
new file mode 100644
index 0000000..053b9ae
--- /dev/null
+++ b/assets/icons/MenuIcons/GeneralSettingsIcons/voiceAssistant.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/MenuIcons/HomeManagementIcons/CreateHome.svg b/assets/icons/MenuIcons/HomeManagementIcons/CreateHome.svg
new file mode 100644
index 0000000..5d7d222
--- /dev/null
+++ b/assets/icons/MenuIcons/HomeManagementIcons/CreateHome.svg
@@ -0,0 +1,8 @@
+
diff --git a/assets/icons/MenuIcons/HomeManagementIcons/ManageYourHome.svg b/assets/icons/MenuIcons/HomeManagementIcons/ManageYourHome.svg
new file mode 100644
index 0000000..6e729d7
--- /dev/null
+++ b/assets/icons/MenuIcons/HomeManagementIcons/ManageYourHome.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/MenuIcons/HomeManagementIcons/joinAHome.svg b/assets/icons/MenuIcons/HomeManagementIcons/joinAHome.svg
new file mode 100644
index 0000000..1ad882a
--- /dev/null
+++ b/assets/icons/MenuIcons/HomeManagementIcons/joinAHome.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/LeagalInfoIcons/About.svg b/assets/icons/MenuIcons/LeagalInfoIcons/About.svg
new file mode 100644
index 0000000..47e30f5
--- /dev/null
+++ b/assets/icons/MenuIcons/LeagalInfoIcons/About.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/MenuIcons/LeagalInfoIcons/PrivacyPolicy.svg b/assets/icons/MenuIcons/LeagalInfoIcons/PrivacyPolicy.svg
new file mode 100644
index 0000000..c5d1e3d
--- /dev/null
+++ b/assets/icons/MenuIcons/LeagalInfoIcons/PrivacyPolicy.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/LeagalInfoIcons/UserAgreement.svg b/assets/icons/MenuIcons/LeagalInfoIcons/UserAgreement.svg
new file mode 100644
index 0000000..6cabfad
--- /dev/null
+++ b/assets/icons/MenuIcons/LeagalInfoIcons/UserAgreement.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/MessagesCenterIcons/Alerts.svg b/assets/icons/MenuIcons/MessagesCenterIcons/Alerts.svg
new file mode 100644
index 0000000..7762dd4
--- /dev/null
+++ b/assets/icons/MenuIcons/MessagesCenterIcons/Alerts.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/MenuIcons/MessagesCenterIcons/FAQs.svg b/assets/icons/MenuIcons/MessagesCenterIcons/FAQs.svg
new file mode 100644
index 0000000..ab3dc9f
--- /dev/null
+++ b/assets/icons/MenuIcons/MessagesCenterIcons/FAQs.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/MenuIcons/MessagesCenterIcons/HelpAndFeedback.svg b/assets/icons/MenuIcons/MessagesCenterIcons/HelpAndFeedback.svg
new file mode 100644
index 0000000..fb53dd0
--- /dev/null
+++ b/assets/icons/MenuIcons/MessagesCenterIcons/HelpAndFeedback.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/MessagesCenterIcons/Messages.svg b/assets/icons/MenuIcons/MessagesCenterIcons/Messages.svg
new file mode 100644
index 0000000..c9a7e35
--- /dev/null
+++ b/assets/icons/MenuIcons/MessagesCenterIcons/Messages.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/MenuIcons/SecurityAndPrivacyIcons/Privacy.svg b/assets/icons/MenuIcons/SecurityAndPrivacyIcons/Privacy.svg
new file mode 100644
index 0000000..69ea2cd
--- /dev/null
+++ b/assets/icons/MenuIcons/SecurityAndPrivacyIcons/Privacy.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/MenuIcons/SecurityAndPrivacyIcons/Securty.svg b/assets/icons/MenuIcons/SecurityAndPrivacyIcons/Securty.svg
new file mode 100644
index 0000000..beecb3e
--- /dev/null
+++ b/assets/icons/MenuIcons/SecurityAndPrivacyIcons/Securty.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/Routines-fill.svg b/assets/icons/Routines-fill.svg
new file mode 100644
index 0000000..99cbc5d
--- /dev/null
+++ b/assets/icons/Routines-fill.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/Routines.svg b/assets/icons/Routines.svg
new file mode 100644
index 0000000..adcf9b8
--- /dev/null
+++ b/assets/icons/Routines.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/Scan.svg b/assets/icons/Scan.svg
new file mode 100644
index 0000000..11fed1b
--- /dev/null
+++ b/assets/icons/Scan.svg
@@ -0,0 +1,13 @@
+
diff --git a/assets/icons/Screen.svg b/assets/icons/Screen.svg
new file mode 100644
index 0000000..cc0cd8f
--- /dev/null
+++ b/assets/icons/Screen.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/Summer.svg b/assets/icons/Summer.svg
new file mode 100644
index 0000000..32a0c3c
--- /dev/null
+++ b/assets/icons/Summer.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/Vector-1.svg b/assets/icons/Vector-1.svg
new file mode 100644
index 0000000..ce3fd9d
--- /dev/null
+++ b/assets/icons/Vector-1.svg
@@ -0,0 +1,29 @@
+
diff --git a/assets/icons/Vector.svg b/assets/icons/Vector.svg
new file mode 100644
index 0000000..2b26ff9
--- /dev/null
+++ b/assets/icons/Vector.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/Wifi.svg b/assets/icons/Wifi.svg
new file mode 100644
index 0000000..4f795c7
--- /dev/null
+++ b/assets/icons/Wifi.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/Winter.svg b/assets/icons/Winter.svg
new file mode 100644
index 0000000..1494cc0
--- /dev/null
+++ b/assets/icons/Winter.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/Winter_mode.svg b/assets/icons/Winter_mode.svg
new file mode 100644
index 0000000..6293ee6
--- /dev/null
+++ b/assets/icons/Winter_mode.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/ac_switch_ic.svg b/assets/icons/ac_switch_ic.svg
new file mode 100644
index 0000000..3ee128e
--- /dev/null
+++ b/assets/icons/ac_switch_ic.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/active.svg b/assets/icons/active.svg
new file mode 100644
index 0000000..7ea03f0
--- /dev/null
+++ b/assets/icons/active.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/add.svg b/assets/icons/add.svg
new file mode 100644
index 0000000..bbd96d7
--- /dev/null
+++ b/assets/icons/add.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/automated_clock.svg b/assets/icons/automated_clock.svg
new file mode 100644
index 0000000..f537623
--- /dev/null
+++ b/assets/icons/automated_clock.svg
@@ -0,0 +1,28 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstChargeddmOff.svg b/assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstChargeddmOff.svg
new file mode 100644
index 0000000..93cb142
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstChargeddmOff.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstDefaultdmOff.svg b/assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstDefaultdmOff.svg
new file mode 100644
index 0000000..e8c4852
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOfflowOffpmOffstDefaultdmOff.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOfflowOffpmOnstChargeddmOff.svg b/assets/icons/battery/dmOff/perOffchargOfflowOffpmOnstChargeddmOff.svg
new file mode 100644
index 0000000..d4c7880
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOfflowOffpmOnstChargeddmOff.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOfflowOnpmOffstDefaultdmOff.svg b/assets/icons/battery/dmOff/perOffchargOfflowOnpmOffstDefaultdmOff.svg
new file mode 100644
index 0000000..dfaf086
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOfflowOnpmOffstDefaultdmOff.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOfflowOnpmOnstDefaultdmOff.svg b/assets/icons/battery/dmOff/perOffchargOfflowOnpmOnstDefaultdmOff.svg
new file mode 100644
index 0000000..e82252c
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOfflowOnpmOnstDefaultdmOff.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOnlowOffpmOffstChargeddmOff.svg b/assets/icons/battery/dmOff/perOffchargOnlowOffpmOffstChargeddmOff.svg
new file mode 100644
index 0000000..a7e3893
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOnlowOffpmOffstChargeddmOff.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOnlowOnpmOffstlowBatterydmOff.svg b/assets/icons/battery/dmOff/perOffchargOnlowOnpmOffstlowBatterydmOff.svg
new file mode 100644
index 0000000..6a58104
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOnlowOnpmOffstlowBatterydmOff.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOff/perOffchargOnlowOnpmOnstlowpmdmOff.svg b/assets/icons/battery/dmOff/perOffchargOnlowOnpmOnstlowpmdmOff.svg
new file mode 100644
index 0000000..7664a08
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOffchargOnlowOnpmOnstlowpmdmOff.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstChargeddmOff.svg b/assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstChargeddmOff.svg
new file mode 100644
index 0000000..b1d3600
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstChargeddmOff.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstDefaultdmOff.svg b/assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstDefaultdmOff.svg
new file mode 100644
index 0000000..44f83ec
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOfflowOffpmOffstDefaultdmOff.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOfflowOffpmOnstChargeddmOff.svg b/assets/icons/battery/dmOff/perOnchargOfflowOffpmOnstChargeddmOff.svg
new file mode 100644
index 0000000..8aa497f
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOfflowOffpmOnstChargeddmOff.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOfflowOnpmOffstDefaultdmOff.svg b/assets/icons/battery/dmOff/perOnchargOfflowOnpmOffstDefaultdmOff.svg
new file mode 100644
index 0000000..792f06b
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOfflowOnpmOffstDefaultdmOff.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOfflowOnpmOnstDefaultdmOff.svg b/assets/icons/battery/dmOff/perOnchargOfflowOnpmOnstDefaultdmOff.svg
new file mode 100644
index 0000000..f712afe
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOfflowOnpmOnstDefaultdmOff.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOnlowOffpmOffstChargeddmOff.svg b/assets/icons/battery/dmOff/perOnchargOnlowOffpmOffstChargeddmOff.svg
new file mode 100644
index 0000000..f56167d
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOnlowOffpmOffstChargeddmOff.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOnlowOnpmOffstlowBatterydmOff.svg b/assets/icons/battery/dmOff/perOnchargOnlowOnpmOffstlowBatterydmOff.svg
new file mode 100644
index 0000000..d580188
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOnlowOnpmOffstlowBatterydmOff.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/battery/dmOff/perOnchargOnlowOnpmOnstlowpmdmOff.svg b/assets/icons/battery/dmOff/perOnchargOnlowOnpmOnstlowpmdmOff.svg
new file mode 100644
index 0000000..c290192
--- /dev/null
+++ b/assets/icons/battery/dmOff/perOnchargOnlowOnpmOnstlowpmdmOff.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstChargeddmOn.svg b/assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstChargeddmOn.svg
new file mode 100644
index 0000000..ba2ff6c
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstChargeddmOn.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstDefaultdmOn.svg b/assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstDefaultdmOn.svg
new file mode 100644
index 0000000..5f713b6
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOfflowOffpmOffstDefaultdmOn.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOfflowOffpmOnstChargeddmOn.svg b/assets/icons/battery/dmOn/perOffchargOfflowOffpmOnstChargeddmOn.svg
new file mode 100644
index 0000000..31fb0cd
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOfflowOffpmOnstChargeddmOn.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOfflowOnpmOffstDefaultdmOn.svg b/assets/icons/battery/dmOn/perOffchargOfflowOnpmOffstDefaultdmOn.svg
new file mode 100644
index 0000000..e198cd4
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOfflowOnpmOffstDefaultdmOn.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOfflowOnpmOnstDefaultdmOn.svg b/assets/icons/battery/dmOn/perOffchargOfflowOnpmOnstDefaultdmOn.svg
new file mode 100644
index 0000000..6175ffe
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOfflowOnpmOnstDefaultdmOn.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOnlowOffpmOffstChargeddmOn.svg b/assets/icons/battery/dmOn/perOffchargOnlowOffpmOffstChargeddmOn.svg
new file mode 100644
index 0000000..017e6c3
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOnlowOffpmOffstChargeddmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOnlowOnpmOffstlowBatterydmOn.svg b/assets/icons/battery/dmOn/perOffchargOnlowOnpmOffstlowBatterydmOn.svg
new file mode 100644
index 0000000..895745f
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOnlowOnpmOffstlowBatterydmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOffchargOnlowOnpmOnstlowpmdmOn.svg b/assets/icons/battery/dmOn/perOffchargOnlowOnpmOnstlowpmdmOn.svg
new file mode 100644
index 0000000..9b32e45
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOffchargOnlowOnpmOnstlowpmdmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstChargeddmOn.svg b/assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstChargeddmOn.svg
new file mode 100644
index 0000000..334aa8a
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstChargeddmOn.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstDefaultdmOn.svg b/assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstDefaultdmOn.svg
new file mode 100644
index 0000000..c2e406f
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOfflowOffpmOffstDefaultdmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOfflowOffpmOnstChargeddmOn.svg b/assets/icons/battery/dmOn/perOnchargOfflowOffpmOnstChargeddmOn.svg
new file mode 100644
index 0000000..a7c162c
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOfflowOffpmOnstChargeddmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOfflowOnpmOffstDefaultdmOn.svg b/assets/icons/battery/dmOn/perOnchargOfflowOnpmOffstDefaultdmOn.svg
new file mode 100644
index 0000000..8e766d7
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOfflowOnpmOffstDefaultdmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOfflowOnpmOnstDefaultdmOn.svg b/assets/icons/battery/dmOn/perOnchargOfflowOnpmOnstDefaultdmOn.svg
new file mode 100644
index 0000000..00f679c
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOfflowOnpmOnstDefaultdmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOnlowOffpmOffstChargeddmOn.svg b/assets/icons/battery/dmOn/perOnchargOnlowOffpmOffstChargeddmOn.svg
new file mode 100644
index 0000000..952d9ca
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOnlowOffpmOffstChargeddmOn.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOnlowOnpmOffstlowBatterydmOn.svg b/assets/icons/battery/dmOn/perOnchargOnlowOnpmOffstlowBatterydmOn.svg
new file mode 100644
index 0000000..22ce56e
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOnlowOnpmOffstlowBatterydmOn.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/battery/dmOn/perOnchargOnlowOnpmOnstlowpmdmOn.svg b/assets/icons/battery/dmOn/perOnchargOnlowOnpmOnstlowpmdmOn.svg
new file mode 100644
index 0000000..5ab5765
--- /dev/null
+++ b/assets/icons/battery/dmOn/perOnchargOnlowOnpmOnstlowpmdmOn.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/blue_checkbox_ic.svg b/assets/icons/blue_checkbox_ic.svg
new file mode 100644
index 0000000..46d0160
--- /dev/null
+++ b/assets/icons/blue_checkbox_ic.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/coldMode.svg b/assets/icons/coldMode.svg
new file mode 100644
index 0000000..ab17a65
--- /dev/null
+++ b/assets/icons/coldMode.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/color_wheel.svg b/assets/icons/color_wheel.svg
new file mode 100644
index 0000000..793ac1b
--- /dev/null
+++ b/assets/icons/color_wheel.svg
@@ -0,0 +1,20 @@
+
diff --git a/assets/icons/curtainsIcon/closeCurtain.svg b/assets/icons/curtainsIcon/closeCurtain.svg
new file mode 100644
index 0000000..8fa548f
--- /dev/null
+++ b/assets/icons/curtainsIcon/closeCurtain.svg
@@ -0,0 +1,56 @@
+
diff --git a/assets/icons/curtainsIcon/curtainHolder.svg b/assets/icons/curtainsIcon/curtainHolder.svg
new file mode 100644
index 0000000..8ed2e91
--- /dev/null
+++ b/assets/icons/curtainsIcon/curtainHolder.svg
@@ -0,0 +1,34 @@
+
diff --git a/assets/icons/curtainsIcon/openCurtain.svg b/assets/icons/curtainsIcon/openCurtain.svg
new file mode 100644
index 0000000..67fd13c
--- /dev/null
+++ b/assets/icons/curtainsIcon/openCurtain.svg
@@ -0,0 +1,56 @@
+
diff --git a/assets/icons/curtainsIcon/verticalBlade.svg b/assets/icons/curtainsIcon/verticalBlade.svg
new file mode 100644
index 0000000..3089113
--- /dev/null
+++ b/assets/icons/curtainsIcon/verticalBlade.svg
@@ -0,0 +1,32 @@
+
diff --git a/assets/icons/dashboard-fill.svg b/assets/icons/dashboard-fill.svg
new file mode 100644
index 0000000..ed518e5
--- /dev/null
+++ b/assets/icons/dashboard-fill.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/dashboard.svg b/assets/icons/dashboard.svg
new file mode 100644
index 0000000..e112256
--- /dev/null
+++ b/assets/icons/dashboard.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/delay.svg b/assets/icons/delay.svg
new file mode 100644
index 0000000..2285837
--- /dev/null
+++ b/assets/icons/delay.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/delete_room_ic.svg b/assets/icons/delete_room_ic.svg
new file mode 100644
index 0000000..3ac2dbd
--- /dev/null
+++ b/assets/icons/delete_room_ic.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/doorLock.svg b/assets/icons/doorLock.svg
new file mode 100644
index 0000000..6f27673
--- /dev/null
+++ b/assets/icons/doorLock.svg
@@ -0,0 +1,24 @@
+
diff --git a/assets/icons/doorlock-assets/BatteryIndicator.svg b/assets/icons/doorlock-assets/BatteryIndicator.svg
new file mode 100644
index 0000000..e82252c
--- /dev/null
+++ b/assets/icons/doorlock-assets/BatteryIndicator.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/doorlock-assets/door_un_look_ic.svg b/assets/icons/doorlock-assets/door_un_look_ic.svg
new file mode 100644
index 0000000..b647ec8
--- /dev/null
+++ b/assets/icons/doorlock-assets/door_un_look_ic.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/doorlock-assets/doorlock-button-one.svg b/assets/icons/doorlock-assets/doorlock-button-one.svg
new file mode 100644
index 0000000..492fdc0
--- /dev/null
+++ b/assets/icons/doorlock-assets/doorlock-button-one.svg
@@ -0,0 +1,23 @@
+
diff --git a/assets/icons/doorlock-assets/doorlock-button-two.svg b/assets/icons/doorlock-assets/doorlock-button-two.svg
new file mode 100644
index 0000000..3aa3bed
--- /dev/null
+++ b/assets/icons/doorlock-assets/doorlock-button-two.svg
@@ -0,0 +1,42 @@
+
diff --git a/assets/icons/doorlock-assets/lockIcon.svg b/assets/icons/doorlock-assets/lockIcon.svg
new file mode 100644
index 0000000..a78161c
--- /dev/null
+++ b/assets/icons/doorlock-assets/lockIcon.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/doorlock-assets/members-management.svg b/assets/icons/doorlock-assets/members-management.svg
new file mode 100644
index 0000000..f7a60fb
--- /dev/null
+++ b/assets/icons/doorlock-assets/members-management.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/doorlock-assets/smart-linkage.svg b/assets/icons/doorlock-assets/smart-linkage.svg
new file mode 100644
index 0000000..b9730e3
--- /dev/null
+++ b/assets/icons/doorlock-assets/smart-linkage.svg
@@ -0,0 +1,13 @@
+
diff --git a/assets/icons/doorlock-assets/temporary-password.svg b/assets/icons/doorlock-assets/temporary-password.svg
new file mode 100644
index 0000000..583035b
--- /dev/null
+++ b/assets/icons/doorlock-assets/temporary-password.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/doorlock-assets/unlocking-records.svg b/assets/icons/doorlock-assets/unlocking-records.svg
new file mode 100644
index 0000000..125f3d9
--- /dev/null
+++ b/assets/icons/doorlock-assets/unlocking-records.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/empty_checkbox_ic.svg b/assets/icons/empty_checkbox_ic.svg
new file mode 100644
index 0000000..34522c8
--- /dev/null
+++ b/assets/icons/empty_checkbox_ic.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/fan-0.svg b/assets/icons/fan-0.svg
new file mode 100644
index 0000000..82841be
--- /dev/null
+++ b/assets/icons/fan-0.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/fan-1.svg b/assets/icons/fan-1.svg
new file mode 100644
index 0000000..3a4dbf2
--- /dev/null
+++ b/assets/icons/fan-1.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/fan-2.svg b/assets/icons/fan-2.svg
new file mode 100644
index 0000000..9e54725
--- /dev/null
+++ b/assets/icons/fan-2.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/fan-3.svg b/assets/icons/fan-3.svg
new file mode 100644
index 0000000..2650a57
--- /dev/null
+++ b/assets/icons/fan-3.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/filter.png b/assets/icons/filter.png
new file mode 100644
index 0000000..ccb920e
Binary files /dev/null and b/assets/icons/filter.png differ
diff --git a/assets/icons/frequency.svg b/assets/icons/frequency.svg
new file mode 100644
index 0000000..3054ec7
--- /dev/null
+++ b/assets/icons/frequency.svg
@@ -0,0 +1,25 @@
+
diff --git a/assets/icons/functions_icons/ac_cooling.svg b/assets/icons/functions_icons/ac_cooling.svg
new file mode 100644
index 0000000..e95c0d4
--- /dev/null
+++ b/assets/icons/functions_icons/ac_cooling.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/ac_fan_auto.svg b/assets/icons/functions_icons/ac_fan_auto.svg
new file mode 100644
index 0000000..0acacfe
--- /dev/null
+++ b/assets/icons/functions_icons/ac_fan_auto.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/functions_icons/ac_fan_high.svg b/assets/icons/functions_icons/ac_fan_high.svg
new file mode 100644
index 0000000..d613153
--- /dev/null
+++ b/assets/icons/functions_icons/ac_fan_high.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/ac_fan_low.svg b/assets/icons/functions_icons/ac_fan_low.svg
new file mode 100644
index 0000000..f4bf56b
--- /dev/null
+++ b/assets/icons/functions_icons/ac_fan_low.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/ac_fan_middle.svg b/assets/icons/functions_icons/ac_fan_middle.svg
new file mode 100644
index 0000000..ee94023
--- /dev/null
+++ b/assets/icons/functions_icons/ac_fan_middle.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/ac_heating.svg b/assets/icons/functions_icons/ac_heating.svg
new file mode 100644
index 0000000..47a160c
--- /dev/null
+++ b/assets/icons/functions_icons/ac_heating.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/functions_icons/ac_power.svg b/assets/icons/functions_icons/ac_power.svg
new file mode 100644
index 0000000..cc2127f
--- /dev/null
+++ b/assets/icons/functions_icons/ac_power.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/functions_icons/ac_power_off.svg b/assets/icons/functions_icons/ac_power_off.svg
new file mode 100644
index 0000000..70f7f9a
--- /dev/null
+++ b/assets/icons/functions_icons/ac_power_off.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/card_unlock.svg b/assets/icons/functions_icons/automation_functions/card_unlock.svg
new file mode 100644
index 0000000..dd77680
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/card_unlock.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/current_temp.svg b/assets/icons/functions_icons/automation_functions/current_temp.svg
new file mode 100644
index 0000000..42cceb2
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/current_temp.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/doorbell.svg b/assets/icons/functions_icons/automation_functions/doorbell.svg
new file mode 100644
index 0000000..1dc515a
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/doorbell.svg
@@ -0,0 +1,13 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/doorlock_normal_open.svg b/assets/icons/functions_icons/automation_functions/doorlock_normal_open.svg
new file mode 100644
index 0000000..8f4a590
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/doorlock_normal_open.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/double_lock.svg b/assets/icons/functions_icons/automation_functions/double_lock.svg
new file mode 100644
index 0000000..d8ad971
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/double_lock.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/fingerprint_unlock.svg b/assets/icons/functions_icons/automation_functions/fingerprint_unlock.svg
new file mode 100644
index 0000000..f9f5b84
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/fingerprint_unlock.svg
@@ -0,0 +1,79 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/hijack_alarm.svg b/assets/icons/functions_icons/automation_functions/hijack_alarm.svg
new file mode 100644
index 0000000..e32997f
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/hijack_alarm.svg
@@ -0,0 +1,13 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/lock_alarm.svg b/assets/icons/functions_icons/automation_functions/lock_alarm.svg
new file mode 100644
index 0000000..8bd2dee
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/lock_alarm.svg
@@ -0,0 +1,149 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/motion.svg b/assets/icons/functions_icons/automation_functions/motion.svg
new file mode 100644
index 0000000..8d69463
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/motion.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/password_unlock.svg b/assets/icons/functions_icons/automation_functions/password_unlock.svg
new file mode 100644
index 0000000..1920b69
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/password_unlock.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/presence.svg b/assets/icons/functions_icons/automation_functions/presence.svg
new file mode 100644
index 0000000..d71a474
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/presence.svg
@@ -0,0 +1,18 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/presence_state.svg b/assets/icons/functions_icons/automation_functions/presence_state.svg
new file mode 100644
index 0000000..d5de48e
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/presence_state.svg
@@ -0,0 +1,18 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/remote_unlock_req.svg b/assets/icons/functions_icons/automation_functions/remote_unlock_req.svg
new file mode 100644
index 0000000..da128ff
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/remote_unlock_req.svg
@@ -0,0 +1,15 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/remote_unlock_via_app.svg b/assets/icons/functions_icons/automation_functions/remote_unlock_via_app.svg
new file mode 100644
index 0000000..39fc859
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/remote_unlock_via_app.svg
@@ -0,0 +1,40 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/residual_electricity.svg b/assets/icons/functions_icons/automation_functions/residual_electricity.svg
new file mode 100644
index 0000000..6a5b612
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/residual_electricity.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/self_test_result.svg b/assets/icons/functions_icons/automation_functions/self_test_result.svg
new file mode 100644
index 0000000..8739327
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/self_test_result.svg
@@ -0,0 +1,23 @@
+
diff --git a/assets/icons/functions_icons/automation_functions/temp_password_unlock.svg b/assets/icons/functions_icons/automation_functions/temp_password_unlock.svg
new file mode 100644
index 0000000..98d7573
--- /dev/null
+++ b/assets/icons/functions_icons/automation_functions/temp_password_unlock.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/functions_icons/celsius_degrees.svg b/assets/icons/functions_icons/celsius_degrees.svg
new file mode 100644
index 0000000..7acbd6e
--- /dev/null
+++ b/assets/icons/functions_icons/celsius_degrees.svg
@@ -0,0 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/assets/icons/functions_icons/child_lock.svg b/assets/icons/functions_icons/child_lock.svg
new file mode 100644
index 0000000..6b0138b
--- /dev/null
+++ b/assets/icons/functions_icons/child_lock.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/functions_icons/factory_reset.svg b/assets/icons/functions_icons/factory_reset.svg
new file mode 100644
index 0000000..7a47f24
--- /dev/null
+++ b/assets/icons/functions_icons/factory_reset.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/functions_icons/fan_speed.svg b/assets/icons/functions_icons/fan_speed.svg
new file mode 100644
index 0000000..07a4883
--- /dev/null
+++ b/assets/icons/functions_icons/fan_speed.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/far_detection.svg b/assets/icons/functions_icons/far_detection.svg
new file mode 100644
index 0000000..2827d94
--- /dev/null
+++ b/assets/icons/functions_icons/far_detection.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/functions_icons/far_detection_function.svg b/assets/icons/functions_icons/far_detection_function.svg
new file mode 100644
index 0000000..894b84e
--- /dev/null
+++ b/assets/icons/functions_icons/far_detection_function.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/functions_icons/freezing.svg b/assets/icons/functions_icons/freezing.svg
new file mode 100644
index 0000000..6c02f2e
--- /dev/null
+++ b/assets/icons/functions_icons/freezing.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/functions_icons/indicator.svg b/assets/icons/functions_icons/indicator.svg
new file mode 100644
index 0000000..b58a976
--- /dev/null
+++ b/assets/icons/functions_icons/indicator.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/light_countdown.svg b/assets/icons/functions_icons/light_countdown.svg
new file mode 100644
index 0000000..94f65b9
--- /dev/null
+++ b/assets/icons/functions_icons/light_countdown.svg
@@ -0,0 +1,42 @@
+
diff --git a/assets/icons/functions_icons/master_state.svg b/assets/icons/functions_icons/master_state.svg
new file mode 100644
index 0000000..0aafae1
--- /dev/null
+++ b/assets/icons/functions_icons/master_state.svg
@@ -0,0 +1,18 @@
+
diff --git a/assets/icons/functions_icons/motion_detection.svg b/assets/icons/functions_icons/motion_detection.svg
new file mode 100644
index 0000000..a9b2d68
--- /dev/null
+++ b/assets/icons/functions_icons/motion_detection.svg
@@ -0,0 +1,21 @@
+
diff --git a/assets/icons/functions_icons/motionless_detection.svg b/assets/icons/functions_icons/motionless_detection.svg
new file mode 100644
index 0000000..25a767c
--- /dev/null
+++ b/assets/icons/functions_icons/motionless_detection.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/functions_icons/nobody_time.svg b/assets/icons/functions_icons/nobody_time.svg
new file mode 100644
index 0000000..df80b51
--- /dev/null
+++ b/assets/icons/functions_icons/nobody_time.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/functions_icons/reset_off.svg b/assets/icons/functions_icons/reset_off.svg
new file mode 100644
index 0000000..eac88f2
--- /dev/null
+++ b/assets/icons/functions_icons/reset_off.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/functions_icons/scene_child_lock.svg b/assets/icons/functions_icons/scene_child_lock.svg
new file mode 100644
index 0000000..7e56164
--- /dev/null
+++ b/assets/icons/functions_icons/scene_child_lock.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/scene_child_unlock.svg b/assets/icons/functions_icons/scene_child_unlock.svg
new file mode 100644
index 0000000..4eafbde
--- /dev/null
+++ b/assets/icons/functions_icons/scene_child_unlock.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/functions_icons/scene_refresh.svg b/assets/icons/functions_icons/scene_refresh.svg
new file mode 100644
index 0000000..c54ffb0
--- /dev/null
+++ b/assets/icons/functions_icons/scene_refresh.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/functions_icons/sensitivity.svg b/assets/icons/functions_icons/sensitivity.svg
new file mode 100644
index 0000000..b75ebd3
--- /dev/null
+++ b/assets/icons/functions_icons/sensitivity.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/functions_icons/sesitivity_operation_icon.svg b/assets/icons/functions_icons/sesitivity_operation_icon.svg
new file mode 100644
index 0000000..612148c
--- /dev/null
+++ b/assets/icons/functions_icons/sesitivity_operation_icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/functions_icons/switch_alarm_sound.svg b/assets/icons/functions_icons/switch_alarm_sound.svg
new file mode 100644
index 0000000..db64533
--- /dev/null
+++ b/assets/icons/functions_icons/switch_alarm_sound.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/functions_icons/tempreture.svg b/assets/icons/functions_icons/tempreture.svg
new file mode 100644
index 0000000..448083a
--- /dev/null
+++ b/assets/icons/functions_icons/tempreture.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/icons/gang.svg b/assets/icons/gang.svg
new file mode 100644
index 0000000..85e6e9b
--- /dev/null
+++ b/assets/icons/gang.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/gateway_icon.svg b/assets/icons/gateway_icon.svg
new file mode 100644
index 0000000..d64135c
--- /dev/null
+++ b/assets/icons/gateway_icon.svg
@@ -0,0 +1,40 @@
+
diff --git a/assets/icons/hand_click.svg b/assets/icons/hand_click.svg
new file mode 100644
index 0000000..f0c81f2
--- /dev/null
+++ b/assets/icons/hand_click.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/home.svg b/assets/icons/home.svg
new file mode 100644
index 0000000..9ab0dca
--- /dev/null
+++ b/assets/icons/home.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/assets/icons/hot1.jpg b/assets/icons/hot1.jpg
new file mode 100644
index 0000000..5281185
Binary files /dev/null and b/assets/icons/hot1.jpg differ
diff --git a/assets/icons/kalvin.svg b/assets/icons/kalvin.svg
new file mode 100644
index 0000000..67332f4
--- /dev/null
+++ b/assets/icons/kalvin.svg
@@ -0,0 +1,20 @@
+
diff --git a/assets/icons/lightSwitchOff.svg b/assets/icons/lightSwitchOff.svg
new file mode 100644
index 0000000..b982c13
--- /dev/null
+++ b/assets/icons/lightSwitchOff.svg
@@ -0,0 +1,25 @@
+
diff --git a/assets/icons/lightSwitchOn.svg b/assets/icons/lightSwitchOn.svg
new file mode 100644
index 0000000..e0245bc
--- /dev/null
+++ b/assets/icons/lightSwitchOn.svg
@@ -0,0 +1,38 @@
+
diff --git a/assets/icons/linkageIcons/doorLockAlarm.svg b/assets/icons/linkageIcons/doorLockAlarm.svg
new file mode 100644
index 0000000..3452356
--- /dev/null
+++ b/assets/icons/linkageIcons/doorLockAlarm.svg
@@ -0,0 +1,11 @@
+
diff --git a/assets/icons/linkageIcons/familyHome.svg b/assets/icons/linkageIcons/familyHome.svg
new file mode 100644
index 0000000..d4b0a95
--- /dev/null
+++ b/assets/icons/linkageIcons/familyHome.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/lock.svg b/assets/icons/lock.svg
new file mode 100644
index 0000000..23e3db3
--- /dev/null
+++ b/assets/icons/lock.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/logo.png b/assets/icons/logo.png
new file mode 100644
index 0000000..417841e
Binary files /dev/null and b/assets/icons/logo.png differ
diff --git a/assets/icons/minus.svg b/assets/icons/minus.svg
new file mode 100644
index 0000000..c6d62f4
--- /dev/null
+++ b/assets/icons/minus.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/noValidPasswords.svg b/assets/icons/noValidPasswords.svg
new file mode 100644
index 0000000..1a660df
--- /dev/null
+++ b/assets/icons/noValidPasswords.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/no_units_ic.svg b/assets/icons/no_units_ic.svg
new file mode 100644
index 0000000..f336e9d
--- /dev/null
+++ b/assets/icons/no_units_ic.svg
@@ -0,0 +1,15 @@
+
diff --git a/assets/icons/oneTimePassword.svg b/assets/icons/oneTimePassword.svg
new file mode 100644
index 0000000..06bd9b5
--- /dev/null
+++ b/assets/icons/oneTimePassword.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/pause_ic.svg b/assets/icons/pause_ic.svg
new file mode 100644
index 0000000..c6f6d5c
--- /dev/null
+++ b/assets/icons/pause_ic.svg
@@ -0,0 +1,55 @@
+
diff --git a/assets/icons/play_ic.svg b/assets/icons/play_ic.svg
new file mode 100644
index 0000000..e9242b0
--- /dev/null
+++ b/assets/icons/play_ic.svg
@@ -0,0 +1,55 @@
+
diff --git a/assets/icons/player.svg b/assets/icons/player.svg
new file mode 100644
index 0000000..859abdd
--- /dev/null
+++ b/assets/icons/player.svg
@@ -0,0 +1,6 @@
+
diff --git a/assets/icons/plus.svg b/assets/icons/plus.svg
new file mode 100644
index 0000000..0a6cfb1
--- /dev/null
+++ b/assets/icons/plus.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/presence-sensor-assets/Distance.svg b/assets/icons/presence-sensor-assets/Distance.svg
new file mode 100644
index 0000000..5057814
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Distance.svg
@@ -0,0 +1,20 @@
+
diff --git a/assets/icons/presence-sensor-assets/Empty.svg b/assets/icons/presence-sensor-assets/Empty.svg
new file mode 100644
index 0000000..cf1e5df
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Empty.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/presence-sensor-assets/Illuminance-Record.svg b/assets/icons/presence-sensor-assets/Illuminance-Record.svg
new file mode 100644
index 0000000..5f64243
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Illuminance-Record.svg
@@ -0,0 +1,21 @@
+
diff --git a/assets/icons/presence-sensor-assets/Illuminance-Value.svg b/assets/icons/presence-sensor-assets/Illuminance-Value.svg
new file mode 100644
index 0000000..c087b7c
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Illuminance-Value.svg
@@ -0,0 +1,18 @@
+
diff --git a/assets/icons/presence-sensor-assets/Indicator.svg b/assets/icons/presence-sensor-assets/Indicator.svg
new file mode 100644
index 0000000..600d6da
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Indicator.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/presence-sensor-assets/Presence.svg b/assets/icons/presence-sensor-assets/Presence.svg
new file mode 100644
index 0000000..638cb39
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Presence.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/presence-sensor-assets/Record.svg b/assets/icons/presence-sensor-assets/Record.svg
new file mode 100644
index 0000000..ff39c7f
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Record.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/presence-sensor-assets/Sensitivity.svg b/assets/icons/presence-sensor-assets/Sensitivity.svg
new file mode 100644
index 0000000..bac78f7
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Sensitivity.svg
@@ -0,0 +1,14 @@
+
diff --git a/assets/icons/presence-sensor-assets/Time.svg b/assets/icons/presence-sensor-assets/Time.svg
new file mode 100644
index 0000000..f5b43ad
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/Time.svg
@@ -0,0 +1,29 @@
+
diff --git a/assets/icons/presence-sensor-assets/help-description.svg b/assets/icons/presence-sensor-assets/help-description.svg
new file mode 100644
index 0000000..1dd6f19
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/help-description.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/presence-sensor-assets/induction-recording.svg b/assets/icons/presence-sensor-assets/induction-recording.svg
new file mode 100644
index 0000000..97e2c46
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/induction-recording.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/presence-sensor-assets/maximum_distance.svg b/assets/icons/presence-sensor-assets/maximum_distance.svg
new file mode 100644
index 0000000..9b0faa1
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/maximum_distance.svg
@@ -0,0 +1,17 @@
+
diff --git a/assets/icons/presence-sensor-assets/parameter-settings.svg b/assets/icons/presence-sensor-assets/parameter-settings.svg
new file mode 100644
index 0000000..a996635
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/parameter-settings.svg
@@ -0,0 +1,31 @@
+
diff --git a/assets/icons/presence-sensor-assets/presence-sensor-motion.svg b/assets/icons/presence-sensor-assets/presence-sensor-motion.svg
new file mode 100644
index 0000000..6d33deb
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/presence-sensor-motion.svg
@@ -0,0 +1,31 @@
+
diff --git a/assets/icons/presence-sensor-assets/space_type_icon.svg b/assets/icons/presence-sensor-assets/space_type_icon.svg
new file mode 100644
index 0000000..198948f
--- /dev/null
+++ b/assets/icons/presence-sensor-assets/space_type_icon.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/refresh.svg b/assets/icons/refresh.svg
new file mode 100644
index 0000000..9f12d98
--- /dev/null
+++ b/assets/icons/refresh.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/icons/sensors.svg b/assets/icons/sensors.svg
new file mode 100644
index 0000000..7fbb150
--- /dev/null
+++ b/assets/icons/sensors.svg
@@ -0,0 +1,19 @@
+
diff --git a/assets/icons/settings.png b/assets/icons/settings.png
new file mode 100644
index 0000000..4a8bcbf
Binary files /dev/null and b/assets/icons/settings.png differ
diff --git a/assets/icons/settings.svg b/assets/icons/settings.svg
new file mode 100644
index 0000000..5df067d
--- /dev/null
+++ b/assets/icons/settings.svg
@@ -0,0 +1,4 @@
+
diff --git a/assets/icons/summer_mode.svg b/assets/icons/summer_mode.svg
new file mode 100644
index 0000000..d5de0a4
--- /dev/null
+++ b/assets/icons/summer_mode.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/sunnyMode.svg b/assets/icons/sunnyMode.svg
new file mode 100644
index 0000000..bb350d3
--- /dev/null
+++ b/assets/icons/sunnyMode.svg
@@ -0,0 +1,16 @@
+
diff --git a/assets/icons/sustainability.svg b/assets/icons/sustainability.svg
new file mode 100644
index 0000000..ce1ce44
--- /dev/null
+++ b/assets/icons/sustainability.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/timeLimitedPassword.svg b/assets/icons/timeLimitedPassword.svg
new file mode 100644
index 0000000..be4fdbc
--- /dev/null
+++ b/assets/icons/timeLimitedPassword.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/timeLimitedPasswordIcon.svg b/assets/icons/timeLimitedPasswordIcon.svg
new file mode 100644
index 0000000..60cc3d6
--- /dev/null
+++ b/assets/icons/timeLimitedPasswordIcon.svg
@@ -0,0 +1,12 @@
+
diff --git a/assets/icons/unlock_ic.svg b/assets/icons/unlock_ic.svg
new file mode 100644
index 0000000..8ce3cc4
--- /dev/null
+++ b/assets/icons/unlock_ic.svg
@@ -0,0 +1,5 @@
+
diff --git a/assets/icons/unlockingMethodsIcons/face.svg b/assets/icons/unlockingMethodsIcons/face.svg
new file mode 100644
index 0000000..2a317e4
--- /dev/null
+++ b/assets/icons/unlockingMethodsIcons/face.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/icons/unlockingMethodsIcons/fingerprint.svg b/assets/icons/unlockingMethodsIcons/fingerprint.svg
new file mode 100644
index 0000000..f9f55c5
--- /dev/null
+++ b/assets/icons/unlockingMethodsIcons/fingerprint.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/unlockingMethodsIcons/remote.svg b/assets/icons/unlockingMethodsIcons/remote.svg
new file mode 100644
index 0000000..da59643
--- /dev/null
+++ b/assets/icons/unlockingMethodsIcons/remote.svg
@@ -0,0 +1,9 @@
+
diff --git a/assets/icons/volt-meter.svg b/assets/icons/volt-meter.svg
new file mode 100644
index 0000000..6691a7d
--- /dev/null
+++ b/assets/icons/volt-meter.svg
@@ -0,0 +1,26 @@
+
diff --git a/assets/icons/windyMode.svg b/assets/icons/windyMode.svg
new file mode 100644
index 0000000..a7e6284
--- /dev/null
+++ b/assets/icons/windyMode.svg
@@ -0,0 +1,67 @@
+
diff --git a/assets/icons/winter1.jpg b/assets/icons/winter1.jpg
new file mode 100644
index 0000000..12e8b56
Binary files /dev/null and b/assets/icons/winter1.jpg differ
diff --git a/assets/images/Background.png b/assets/images/Background.png
new file mode 100644
index 0000000..02529ba
Binary files /dev/null and b/assets/images/Background.png differ
diff --git a/assets/images/Down.png b/assets/images/Down.png
new file mode 100644
index 0000000..efd6460
Binary files /dev/null and b/assets/images/Down.png differ
diff --git a/assets/images/HorizintalBlade.png b/assets/images/HorizintalBlade.png
new file mode 100644
index 0000000..f4e939b
Binary files /dev/null and b/assets/images/HorizintalBlade.png differ
diff --git a/assets/images/Logo.svg b/assets/images/Logo.svg
new file mode 100644
index 0000000..0a592c0
--- /dev/null
+++ b/assets/images/Logo.svg
@@ -0,0 +1,38 @@
+
diff --git a/assets/images/Pause.png b/assets/images/Pause.png
new file mode 100644
index 0000000..b5659fc
Binary files /dev/null and b/assets/images/Pause.png differ
diff --git a/assets/images/Up.png b/assets/images/Up.png
new file mode 100644
index 0000000..f4b13a8
Binary files /dev/null and b/assets/images/Up.png differ
diff --git a/assets/images/Vector.png b/assets/images/Vector.png
new file mode 100644
index 0000000..c105e7e
Binary files /dev/null and b/assets/images/Vector.png differ
diff --git a/assets/images/Window.png b/assets/images/Window.png
new file mode 100644
index 0000000..be38a0b
Binary files /dev/null and b/assets/images/Window.png differ
diff --git a/assets/images/automation.jpg b/assets/images/automation.jpg
new file mode 100644
index 0000000..23dc891
Binary files /dev/null and b/assets/images/automation.jpg differ
diff --git a/assets/images/black-logo.png b/assets/images/black-logo.png
new file mode 100644
index 0000000..0d42805
Binary files /dev/null and b/assets/images/black-logo.png differ
diff --git a/assets/images/blind.png b/assets/images/blind.png
new file mode 100644
index 0000000..35cad04
Binary files /dev/null and b/assets/images/blind.png differ
diff --git a/assets/images/box-empty.jpg b/assets/images/box-empty.jpg
new file mode 100644
index 0000000..2064a31
Binary files /dev/null and b/assets/images/box-empty.jpg differ
diff --git a/assets/images/curtain.png b/assets/images/curtain.png
new file mode 100644
index 0000000..c8b55c9
Binary files /dev/null and b/assets/images/curtain.png differ
diff --git a/assets/images/logo_horizontal.png b/assets/images/logo_horizontal.png
new file mode 100644
index 0000000..2d29681
Binary files /dev/null and b/assets/images/logo_horizontal.png differ
diff --git a/assets/images/test_dash.png b/assets/images/test_dash.png
new file mode 100644
index 0000000..efa07cf
Binary files /dev/null and b/assets/images/test_dash.png differ
diff --git a/assets/images/test_dash2.png b/assets/images/test_dash2.png
new file mode 100644
index 0000000..b4cfa2a
Binary files /dev/null and b/assets/images/test_dash2.png differ
diff --git a/assets/images/white-logo.png b/assets/images/white-logo.png
new file mode 100644
index 0000000..2e73e35
Binary files /dev/null and b/assets/images/white-logo.png differ
diff --git a/devtools_options.yaml b/devtools_options.yaml
new file mode 100644
index 0000000..5c27c3e
--- /dev/null
+++ b/devtools_options.yaml
@@ -0,0 +1,2 @@
+extensions:
+ - provider: true
\ No newline at end of file
diff --git a/firebase.json b/firebase.json
new file mode 100644
index 0000000..cb3f9b2
--- /dev/null
+++ b/firebase.json
@@ -0,0 +1 @@
+{"flutter":{"platforms":{"android":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:android:bb6047adeeb80fb00c7e6d","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"test2-8a3d2","appId":"1:427332280600:ios:373a65cce55a3af40c7e6d","uploadDebugSymbols":true,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"test2-8a3d2","configurations":{"android":"1:427332280600:android:bb6047adeeb80fb00c7e6d","ios":"1:427332280600:ios:373a65cce55a3af40c7e6d","web":"1:427332280600:web:ad50516a87a35a1a0c7e6d"}}}}}}
\ No newline at end of file
diff --git a/ios/.gitignore b/ios/.gitignore
new file mode 100644
index 0000000..7a7f987
--- /dev/null
+++ b/ios/.gitignore
@@ -0,0 +1,34 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..7c56964
--- /dev/null
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ App
+ CFBundleIdentifier
+ io.flutter.flutter.app
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ App
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ MinimumOSVersion
+ 12.0
+
+
diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..ec97fc6
--- /dev/null
+++ b/ios/Flutter/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..c4855bf
--- /dev/null
+++ b/ios/Flutter/Release.xcconfig
@@ -0,0 +1,2 @@
+#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
+#include "Generated.xcconfig"
diff --git a/ios/Podfile b/ios/Podfile
new file mode 100644
index 0000000..5d30226
--- /dev/null
+++ b/ios/Podfile
@@ -0,0 +1,52 @@
+# Uncomment this line to define a global platform for your project
+# platform :ios, '12.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__))
+ target 'RunnerTests' do
+ inherit! :search_paths
+ end
+end
+
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ flutter_additional_ios_build_settings(target)
+ target.build_configurations.each do |config|
+ config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= [
+ '$(inherited)',
+ ## dart: PermissionGroup.photos
+ 'PERMISSION_PHOTOS=1',
+ ]
+ end
+ end
+end
+
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
new file mode 100644
index 0000000..8ebd9e9
--- /dev/null
+++ b/ios/Podfile.lock
@@ -0,0 +1,338 @@
+PODS:
+ - device_info_plus (0.0.1):
+ - Flutter
+ - Firebase/Analytics (10.25.0):
+ - Firebase/Core
+ - Firebase/Core (10.25.0):
+ - Firebase/CoreOnly
+ - FirebaseAnalytics (~> 10.25.0)
+ - Firebase/CoreOnly (10.25.0):
+ - FirebaseCore (= 10.25.0)
+ - Firebase/Crashlytics (10.25.0):
+ - Firebase/CoreOnly
+ - FirebaseCrashlytics (~> 10.25.0)
+ - Firebase/Database (10.25.0):
+ - Firebase/CoreOnly
+ - FirebaseDatabase (~> 10.25.0)
+ - firebase_analytics (10.8.7):
+ - Firebase/Analytics (= 10.25.0)
+ - firebase_core
+ - Flutter
+ - firebase_core (2.32.0):
+ - Firebase/CoreOnly (= 10.25.0)
+ - Flutter
+ - firebase_crashlytics (3.4.16):
+ - Firebase/Crashlytics (= 10.25.0)
+ - firebase_core
+ - Flutter
+ - firebase_database (10.5.7):
+ - Firebase/Database (= 10.25.0)
+ - firebase_core
+ - Flutter
+ - FirebaseAnalytics (10.25.0):
+ - FirebaseAnalytics/AdIdSupport (= 10.25.0)
+ - FirebaseCore (~> 10.0)
+ - FirebaseInstallations (~> 10.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.11)
+ - GoogleUtilities/MethodSwizzler (~> 7.11)
+ - GoogleUtilities/Network (~> 7.11)
+ - "GoogleUtilities/NSData+zlib (~> 7.11)"
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - FirebaseAnalytics/AdIdSupport (10.25.0):
+ - FirebaseCore (~> 10.0)
+ - FirebaseInstallations (~> 10.0)
+ - GoogleAppMeasurement (= 10.25.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.11)
+ - GoogleUtilities/MethodSwizzler (~> 7.11)
+ - GoogleUtilities/Network (~> 7.11)
+ - "GoogleUtilities/NSData+zlib (~> 7.11)"
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - FirebaseAppCheckInterop (10.29.0)
+ - FirebaseCore (10.25.0):
+ - FirebaseCoreInternal (~> 10.0)
+ - GoogleUtilities/Environment (~> 7.12)
+ - GoogleUtilities/Logger (~> 7.12)
+ - FirebaseCoreExtension (10.29.0):
+ - FirebaseCore (~> 10.0)
+ - FirebaseCoreInternal (10.29.0):
+ - "GoogleUtilities/NSData+zlib (~> 7.8)"
+ - FirebaseCrashlytics (10.25.0):
+ - FirebaseCore (~> 10.5)
+ - FirebaseInstallations (~> 10.0)
+ - FirebaseRemoteConfigInterop (~> 10.23)
+ - FirebaseSessions (~> 10.5)
+ - GoogleDataTransport (~> 9.2)
+ - GoogleUtilities/Environment (~> 7.8)
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - PromisesObjC (~> 2.1)
+ - FirebaseDatabase (10.25.0):
+ - FirebaseAppCheckInterop (~> 10.17)
+ - FirebaseCore (~> 10.0)
+ - FirebaseSharedSwift (~> 10.0)
+ - GoogleUtilities/UserDefaults (~> 7.13)
+ - leveldb-library (~> 1.22)
+ - FirebaseInstallations (10.29.0):
+ - FirebaseCore (~> 10.0)
+ - GoogleUtilities/Environment (~> 7.8)
+ - GoogleUtilities/UserDefaults (~> 7.8)
+ - PromisesObjC (~> 2.1)
+ - FirebaseRemoteConfigInterop (10.29.0)
+ - FirebaseSessions (10.29.0):
+ - FirebaseCore (~> 10.5)
+ - FirebaseCoreExtension (~> 10.0)
+ - FirebaseInstallations (~> 10.0)
+ - GoogleDataTransport (~> 9.2)
+ - GoogleUtilities/Environment (~> 7.13)
+ - GoogleUtilities/UserDefaults (~> 7.13)
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - PromisesSwift (~> 2.1)
+ - FirebaseSharedSwift (10.29.0)
+ - Flutter (1.0.0)
+ - flutter_localization (0.0.1):
+ - Flutter
+ - flutter_secure_storage (6.0.0):
+ - Flutter
+ - GoogleAppMeasurement (10.25.0):
+ - GoogleAppMeasurement/AdIdSupport (= 10.25.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.11)
+ - GoogleUtilities/MethodSwizzler (~> 7.11)
+ - GoogleUtilities/Network (~> 7.11)
+ - "GoogleUtilities/NSData+zlib (~> 7.11)"
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - GoogleAppMeasurement/AdIdSupport (10.25.0):
+ - GoogleAppMeasurement/WithoutAdIdSupport (= 10.25.0)
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.11)
+ - GoogleUtilities/MethodSwizzler (~> 7.11)
+ - GoogleUtilities/Network (~> 7.11)
+ - "GoogleUtilities/NSData+zlib (~> 7.11)"
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - GoogleAppMeasurement/WithoutAdIdSupport (10.25.0):
+ - GoogleUtilities/AppDelegateSwizzler (~> 7.11)
+ - GoogleUtilities/MethodSwizzler (~> 7.11)
+ - GoogleUtilities/Network (~> 7.11)
+ - "GoogleUtilities/NSData+zlib (~> 7.11)"
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - GoogleDataTransport (9.4.1):
+ - GoogleUtilities/Environment (~> 7.7)
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - PromisesObjC (< 3.0, >= 1.2)
+ - GoogleUtilities/AppDelegateSwizzler (7.13.3):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Network
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Environment (7.13.3):
+ - GoogleUtilities/Privacy
+ - PromisesObjC (< 3.0, >= 1.2)
+ - GoogleUtilities/Logger (7.13.3):
+ - GoogleUtilities/Environment
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/MethodSwizzler (7.13.3):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Network (7.13.3):
+ - GoogleUtilities/Logger
+ - "GoogleUtilities/NSData+zlib"
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Reachability
+ - "GoogleUtilities/NSData+zlib (7.13.3)":
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Privacy (7.13.3)
+ - GoogleUtilities/Reachability (7.13.3):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/UserDefaults (7.13.3):
+ - GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
+ - image_picker_ios (0.0.1):
+ - Flutter
+ - leveldb-library (1.22.5)
+ - nanopb (2.30910.0):
+ - nanopb/decode (= 2.30910.0)
+ - nanopb/encode (= 2.30910.0)
+ - nanopb/decode (2.30910.0)
+ - nanopb/encode (2.30910.0)
+ - onesignal_flutter (5.2.0):
+ - Flutter
+ - OneSignalXCFramework (= 5.2.0)
+ - OneSignalXCFramework (5.2.0):
+ - OneSignalXCFramework/OneSignalComplete (= 5.2.0)
+ - OneSignalXCFramework/OneSignal (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalExtension
+ - OneSignalXCFramework/OneSignalLiveActivities
+ - OneSignalXCFramework/OneSignalNotifications
+ - OneSignalXCFramework/OneSignalOSCore
+ - OneSignalXCFramework/OneSignalOutcomes
+ - OneSignalXCFramework/OneSignalUser
+ - OneSignalXCFramework/OneSignalComplete (5.2.0):
+ - OneSignalXCFramework/OneSignal
+ - OneSignalXCFramework/OneSignalInAppMessages
+ - OneSignalXCFramework/OneSignalLocation
+ - OneSignalXCFramework/OneSignalCore (5.2.0)
+ - OneSignalXCFramework/OneSignalExtension (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalOutcomes
+ - OneSignalXCFramework/OneSignalInAppMessages (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalNotifications
+ - OneSignalXCFramework/OneSignalOSCore
+ - OneSignalXCFramework/OneSignalOutcomes
+ - OneSignalXCFramework/OneSignalUser
+ - OneSignalXCFramework/OneSignalLiveActivities (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalOSCore
+ - OneSignalXCFramework/OneSignalUser
+ - OneSignalXCFramework/OneSignalLocation (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalNotifications
+ - OneSignalXCFramework/OneSignalOSCore
+ - OneSignalXCFramework/OneSignalUser
+ - OneSignalXCFramework/OneSignalNotifications (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalExtension
+ - OneSignalXCFramework/OneSignalOutcomes
+ - OneSignalXCFramework/OneSignalOSCore (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalOutcomes (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalUser (5.2.0):
+ - OneSignalXCFramework/OneSignalCore
+ - OneSignalXCFramework/OneSignalNotifications
+ - OneSignalXCFramework/OneSignalOSCore
+ - OneSignalXCFramework/OneSignalOutcomes
+ - path_provider_foundation (0.0.1):
+ - Flutter
+ - FlutterMacOS
+ - permission_handler_apple (9.3.0):
+ - Flutter
+ - PromisesObjC (2.4.0)
+ - PromisesSwift (2.4.0):
+ - PromisesObjC (= 2.4.0)
+ - share_plus (0.0.1):
+ - Flutter
+ - shared_preferences_foundation (0.0.1):
+ - Flutter
+ - FlutterMacOS
+ - sqflite (0.0.3):
+ - Flutter
+ - FlutterMacOS
+ - url_launcher_ios (0.0.1):
+ - Flutter
+
+DEPENDENCIES:
+ - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
+ - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
+ - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
+ - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
+ - firebase_database (from `.symlinks/plugins/firebase_database/ios`)
+ - Flutter (from `Flutter`)
+ - flutter_localization (from `.symlinks/plugins/flutter_localization/ios`)
+ - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
+ - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
+ - onesignal_flutter (from `.symlinks/plugins/onesignal_flutter/ios`)
+ - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
+ - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
+ - share_plus (from `.symlinks/plugins/share_plus/ios`)
+ - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
+ - sqflite (from `.symlinks/plugins/sqflite/darwin`)
+ - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
+
+SPEC REPOS:
+ trunk:
+ - Firebase
+ - FirebaseAnalytics
+ - FirebaseAppCheckInterop
+ - FirebaseCore
+ - FirebaseCoreExtension
+ - FirebaseCoreInternal
+ - FirebaseCrashlytics
+ - FirebaseDatabase
+ - FirebaseInstallations
+ - FirebaseRemoteConfigInterop
+ - FirebaseSessions
+ - FirebaseSharedSwift
+ - GoogleAppMeasurement
+ - GoogleDataTransport
+ - GoogleUtilities
+ - leveldb-library
+ - nanopb
+ - OneSignalXCFramework
+ - PromisesObjC
+ - PromisesSwift
+
+EXTERNAL SOURCES:
+ device_info_plus:
+ :path: ".symlinks/plugins/device_info_plus/ios"
+ firebase_analytics:
+ :path: ".symlinks/plugins/firebase_analytics/ios"
+ firebase_core:
+ :path: ".symlinks/plugins/firebase_core/ios"
+ firebase_crashlytics:
+ :path: ".symlinks/plugins/firebase_crashlytics/ios"
+ firebase_database:
+ :path: ".symlinks/plugins/firebase_database/ios"
+ Flutter:
+ :path: Flutter
+ flutter_localization:
+ :path: ".symlinks/plugins/flutter_localization/ios"
+ flutter_secure_storage:
+ :path: ".symlinks/plugins/flutter_secure_storage/ios"
+ image_picker_ios:
+ :path: ".symlinks/plugins/image_picker_ios/ios"
+ onesignal_flutter:
+ :path: ".symlinks/plugins/onesignal_flutter/ios"
+ path_provider_foundation:
+ :path: ".symlinks/plugins/path_provider_foundation/darwin"
+ permission_handler_apple:
+ :path: ".symlinks/plugins/permission_handler_apple/ios"
+ share_plus:
+ :path: ".symlinks/plugins/share_plus/ios"
+ shared_preferences_foundation:
+ :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
+ sqflite:
+ :path: ".symlinks/plugins/sqflite/darwin"
+ url_launcher_ios:
+ :path: ".symlinks/plugins/url_launcher_ios/ios"
+
+SPEC CHECKSUMS:
+ device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
+ Firebase: 0312a2352584f782ea56f66d91606891d4607f06
+ firebase_analytics: 3a9263fedec72970e6bd30a7132bbdd386de2c14
+ firebase_core: a626d00494efa398e7c54f25f1454a64c8abf197
+ firebase_crashlytics: 0b7cb41f5fb3b6889d0fb408cfce3cc7a4247061
+ firebase_database: 2713033e426b176d4fe5e7195f3d19aa1b549a91
+ FirebaseAnalytics: ec00fe8b93b41dc6fe4a28784b8e51da0647a248
+ FirebaseAppCheckInterop: 6a1757cfd4067d8e00fccd14fcc1b8fd78cfac07
+ FirebaseCore: 7ec4d0484817f12c3373955bc87762d96842d483
+ FirebaseCoreExtension: 705ca5b14bf71d2564a0ddc677df1fc86ffa600f
+ FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934
+ FirebaseCrashlytics: 4b96efb0ce73b38b2a85e8b8bd1bd8f63f09d015
+ FirebaseDatabase: faa489a42f5f868d23a55dd442d6e2099348458e
+ FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd
+ FirebaseRemoteConfigInterop: 6efda51fb5e2f15b16585197e26eaa09574e8a4d
+ FirebaseSessions: dbd14adac65ce996228652c1fc3a3f576bdf3ecc
+ FirebaseSharedSwift: 20530f495084b8d840f78a100d8c5ee613375f6e
+ Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ flutter_localization: f43b18844a2b3d2c71fd64f04ffd6b1e64dd54d4
+ flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
+ GoogleAppMeasurement: 9abf64b682732fed36da827aa2a68f0221fd2356
+ GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
+ GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
+ image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
+ leveldb-library: e8eadf9008a61f9e1dde3978c086d2b6d9b9dc28
+ nanopb: 438bc412db1928dac798aa6fd75726007be04262
+ onesignal_flutter: 5ce68a29861960168e81101cb1bd685d264361de
+ OneSignalXCFramework: bdf74fdc06888f9466dc21e826fe1549ed143095
+ path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
+ permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
+ PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
+ PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
+ share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
+ shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
+ sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
+ url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
+
+PODFILE CHECKSUM: 4243bd7f9184f79552dd731a7c9d5cad03bd2706
+
+COCOAPODS: 1.15.2
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..38b52d7
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,795 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 54;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 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 */; };
+ 611C662010675536F855E5CA /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 490AAF90B8FBFCC5BA996845 /* Pods_RunnerTests.framework */; };
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 8BB48ED4ACF8DB5A4F5DB78C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 90790D9750E58AEFF7247821 /* GoogleService-Info.plist */; };
+ 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 */; };
+ D31283674D2826D7EF8E56BC /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25B37F5982CD6994FABA2CC1 /* Pods_Runner.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+ remoteInfo = Runner;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 25B37F5982CD6994FABA2CC1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
+ 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 = ""; };
+ 444D77D28A8CDF32047CD0AF /* 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 = ""; };
+ 490AAF90B8FBFCC5BA996845 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
+ 90790D9750E58AEFF7247821 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; };
+ 949637473C534E1F68B19CC0 /* 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 = ""; };
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ AAC9129FD50E64509AD1B9AF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; };
+ BFD4DDED98208034B60B5311 /* 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 = ""; };
+ DFB6BB492A265F2BF6FDC8C0 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; };
+ F323D632CA976B68DDB0E669 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 97C146EB1CF9000F007C117D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ D31283674D2826D7EF8E56BC /* Pods_Runner.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C2B33A7265AF659D80692473 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 611C662010675536F855E5CA /* Pods_RunnerTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2F70EB4341A83C900EB253DC /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ BFD4DDED98208034B60B5311 /* Pods-Runner.debug.xcconfig */,
+ 949637473C534E1F68B19CC0 /* Pods-Runner.release.xcconfig */,
+ 444D77D28A8CDF32047CD0AF /* Pods-Runner.profile.xcconfig */,
+ DFB6BB492A265F2BF6FDC8C0 /* Pods-RunnerTests.debug.xcconfig */,
+ F323D632CA976B68DDB0E669 /* Pods-RunnerTests.release.xcconfig */,
+ AAC9129FD50E64509AD1B9AF /* Pods-RunnerTests.profile.xcconfig */,
+ );
+ path = Pods;
+ sourceTree = "";
+ };
+ 331C8082294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXGroup;
+ children = (
+ 331C807B294A618700263BE5 /* RunnerTests.swift */,
+ );
+ path = RunnerTests;
+ sourceTree = "";
+ };
+ 876D3217A8BBDAF41961161F /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 25B37F5982CD6994FABA2CC1 /* Pods_Runner.framework */,
+ 490AAF90B8FBFCC5BA996845 /* Pods_RunnerTests.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 9740EEB11CF90186004384FC /* Flutter */ = {
+ isa = PBXGroup;
+ children = (
+ 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+ 9740EEB21CF90195004384FC /* Debug.xcconfig */,
+ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+ 9740EEB31CF90195004384FC /* Generated.xcconfig */,
+ );
+ name = Flutter;
+ sourceTree = "";
+ };
+ 97C146E51CF9000F007C117D = {
+ isa = PBXGroup;
+ children = (
+ 9740EEB11CF90186004384FC /* Flutter */,
+ 97C146F01CF9000F007C117D /* Runner */,
+ 97C146EF1CF9000F007C117D /* Products */,
+ 331C8082294A63A400263BE5 /* RunnerTests */,
+ 2F70EB4341A83C900EB253DC /* Pods */,
+ 876D3217A8BBDAF41961161F /* Frameworks */,
+ 90790D9750E58AEFF7247821 /* GoogleService-Info.plist */,
+ );
+ sourceTree = "";
+ };
+ 97C146EF1CF9000F007C117D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146EE1CF9000F007C117D /* Runner.app */,
+ 331C8081294A63A400263BE5 /* RunnerTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 97C146F01CF9000F007C117D /* Runner */ = {
+ isa = PBXGroup;
+ children = (
+ 97C146FA1CF9000F007C117D /* Main.storyboard */,
+ 97C146FD1CF9000F007C117D /* Assets.xcassets */,
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+ 97C147021CF9000F007C117D /* Info.plist */,
+ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+ 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+ 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+ );
+ path = Runner;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 331C8080294A63A400263BE5 /* RunnerTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+ buildPhases = (
+ 3B971DE531245D7FD2921C30 /* [CP] Check Pods Manifest.lock */,
+ 331C807D294A63A400263BE5 /* Sources */,
+ 331C807F294A63A400263BE5 /* Resources */,
+ C2B33A7265AF659D80692473 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */,
+ );
+ name = RunnerTests;
+ productName = RunnerTests;
+ productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ 97C146ED1CF9000F007C117D /* Runner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+ buildPhases = (
+ 3DC878D0674AA34AEC9695FB /* [CP] Check Pods Manifest.lock */,
+ 9740EEB61CF901F6004384FC /* Run Script */,
+ 97C146EA1CF9000F007C117D /* Sources */,
+ 97C146EB1CF9000F007C117D /* Frameworks */,
+ 97C146EC1CF9000F007C117D /* Resources */,
+ 9705A1C41CF9048500538489 /* Embed Frameworks */,
+ 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ 315A05630CF83C532DBBCBF2 /* [CP] Embed Pods Frameworks */,
+ 0D61909C49A20C9AA28568EA /* FlutterFire: "flutterfire upload-crashlytics-symbols" */,
+ 3724F7A126D8469D5B04D144 /* [CP] Copy Pods Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = Runner;
+ productName = Runner;
+ productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 97C146E61CF9000F007C117D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ LastUpgradeCheck = 1510;
+ ORGANIZATIONNAME = "";
+ TargetAttributes = {
+ 331C8080294A63A400263BE5 = {
+ CreatedOnToolsVersion = 14.0;
+ TestTargetID = 97C146ED1CF9000F007C117D;
+ };
+ 97C146ED1CF9000F007C117D = {
+ CreatedOnToolsVersion = 7.3.1;
+ LastSwiftMigration = 1100;
+ };
+ };
+ };
+ buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+ compatibilityVersion = "Xcode 15.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 97C146E51CF9000F007C117D;
+ productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 97C146ED1CF9000F007C117D /* Runner */,
+ 331C8080294A63A400263BE5 /* RunnerTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 331C807F294A63A400263BE5 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EC1CF9000F007C117D /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+ 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+ 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ 8BB48ED4ACF8DB5A4F5DB78C /* GoogleService-Info.plist in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 0D61909C49A20C9AA28568EA /* FlutterFire: "flutterfire upload-crashlytics-symbols" */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "FlutterFire: \"flutterfire upload-crashlytics-symbols\"";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\n#!/bin/bash\nPATH=${PATH}:$FLUTTER_ROOT/bin:$HOME/.pub-cache/bin\nflutterfire upload-crashlytics-symbols --upload-symbols-script-path=$PODS_ROOT/FirebaseCrashlytics/upload-symbols --platform=ios --apple-project-path=${SRCROOT} --env-platform-name=${PLATFORM_NAME} --env-configuration=${CONFIGURATION} --env-project-dir=${PROJECT_DIR} --env-built-products-dir=${BUILT_PRODUCTS_DIR} --env-dwarf-dsym-folder-path=${DWARF_DSYM_FOLDER_PATH} --env-dwarf-dsym-file-name=${DWARF_DSYM_FILE_NAME} --env-infoplist-path=${INFOPLIST_PATH} --default-config=default\n";
+ };
+ 315A05630CF83C532DBBCBF2 /* [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;
+ };
+ 3724F7A126D8469D5B04D144 /* [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;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+ );
+ name = "Thin Binary";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+ };
+ 3B971DE531245D7FD2921C30 /* [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-RunnerTests-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;
+ };
+ 3DC878D0674AA34AEC9695FB /* [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;
+ };
+ 9740EEB61CF901F6004384FC /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 331C807D294A63A400263BE5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97C146EA1CF9000F007C117D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97C146ED1CF9000F007C117D /* Runner */;
+ targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C146FB1CF9000F007C117D /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 97C147001CF9000F007C117D /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 249021D3217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Profile;
+ };
+ 249021D4217E4FDB00AE95B9 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 20;
+ DEVELOPMENT_TEAM = 48V27SBR8J;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0.2;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Profile;
+ };
+ 331C8088294A63A400263BE5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = DFB6BB492A265F2BF6FDC8C0 /* Pods-RunnerTests.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrowApp.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Debug;
+ };
+ 331C8089294A63A400263BE5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = F323D632CA976B68DDB0E669 /* Pods-RunnerTests.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrowApp.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Release;
+ };
+ 331C808A294A63A400263BE5 /* Profile */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AAC9129FD50E64509AD1B9AF /* Pods-RunnerTests.profile.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ GENERATE_INFOPLIST_FILE = YES;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrowApp.RunnerTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+ };
+ name = Profile;
+ };
+ 97C147031CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 97C147041CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 97C147061CF9000F007C117D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 20;
+ DEVELOPMENT_TEAM = 48V27SBR8J;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0.2;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Debug;
+ };
+ 97C147071CF9000F007C117D /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 20;
+ DEVELOPMENT_TEAM = 48V27SBR8J;
+ ENABLE_BITCODE = NO;
+ INFOPLIST_FILE = Runner/Info.plist;
+ INFOPLIST_KEY_CFBundleDisplayName = Syncrow;
+ INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0.2;
+ PRODUCT_BUNDLE_IDENTIFIER = com.example.syncrow.app;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+ SWIFT_VERSION = 5.0;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 331C8088294A63A400263BE5 /* Debug */,
+ 331C8089294A63A400263BE5 /* Release */,
+ 331C808A294A63A400263BE5 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147031CF9000F007C117D /* Debug */,
+ 97C147041CF9000F007C117D /* Release */,
+ 249021D3217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97C147061CF9000F007C117D /* Debug */,
+ 97C147071CF9000F007C117D /* Release */,
+ 249021D4217E4FDB00AE95B9 /* Profile */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..8e3ca5d
--- /dev/null
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..21a3cc1
--- /dev/null
+++ b/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+
+
+
+
+ PreviewsEnabled
+
+
+
diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..70693e4
--- /dev/null
+++ b/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+ override func application(
+ _ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+ ) -> Bool {
+ GeneratedPluginRegistrant.register(with: self)
+ return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+ }
+}
diff --git a/ios/Runner/AppIcon.appiconset/1024.png b/ios/Runner/AppIcon.appiconset/1024.png
new file mode 100644
index 0000000..5cc0985
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/1024.png differ
diff --git a/ios/Runner/AppIcon.appiconset/114.png b/ios/Runner/AppIcon.appiconset/114.png
new file mode 100644
index 0000000..4002c14
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/114.png differ
diff --git a/ios/Runner/AppIcon.appiconset/120.png b/ios/Runner/AppIcon.appiconset/120.png
new file mode 100644
index 0000000..ddee75b
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/120.png differ
diff --git a/ios/Runner/AppIcon.appiconset/180.png b/ios/Runner/AppIcon.appiconset/180.png
new file mode 100644
index 0000000..357cd0b
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/180.png differ
diff --git a/ios/Runner/AppIcon.appiconset/29.png b/ios/Runner/AppIcon.appiconset/29.png
new file mode 100644
index 0000000..2a93116
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/29.png differ
diff --git a/ios/Runner/AppIcon.appiconset/40.png b/ios/Runner/AppIcon.appiconset/40.png
new file mode 100644
index 0000000..9ecf032
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/40.png differ
diff --git a/ios/Runner/AppIcon.appiconset/57.png b/ios/Runner/AppIcon.appiconset/57.png
new file mode 100644
index 0000000..a0767a3
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/57.png differ
diff --git a/ios/Runner/AppIcon.appiconset/58.png b/ios/Runner/AppIcon.appiconset/58.png
new file mode 100644
index 0000000..af3366d
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/58.png differ
diff --git a/ios/Runner/AppIcon.appiconset/60.png b/ios/Runner/AppIcon.appiconset/60.png
new file mode 100644
index 0000000..de657d6
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/60.png differ
diff --git a/ios/Runner/AppIcon.appiconset/80.png b/ios/Runner/AppIcon.appiconset/80.png
new file mode 100644
index 0000000..4739c0f
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/80.png differ
diff --git a/ios/Runner/AppIcon.appiconset/87.png b/ios/Runner/AppIcon.appiconset/87.png
new file mode 100644
index 0000000..3757b16
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/87.png differ
diff --git a/ios/Runner/AppIcon.appiconset/Contents.json b/ios/Runner/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..8a28773
--- /dev/null
+++ b/ios/Runner/AppIcon.appiconset/Contents.json
@@ -0,0 +1,116 @@
+{
+ "images" : [
+ {
+ "size" : "20x20",
+ "idiom": "iphone",
+ "filename" : "logo-20@2x.png",
+ "scale": "2x"
+ },
+ {
+ "size" : "20x20",
+ "idiom": "iphone",
+ "filename" : "logo-20@3x.png",
+ "scale": "3x"
+ },
+ {
+ "size" : "20x20",
+ "idiom": "ipad",
+ "filename" : "logo-20.png",
+ "scale": "1x"
+ },
+ {
+ "size" : "20x20",
+ "idiom": "ipad",
+ "filename" : "logo-20@2x.png",
+ "scale": "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "logo-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "logo-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "logo-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "logo-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "logo-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "logo-60@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "logo-29.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "ipad",
+ "filename" : "logo-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "logo-40.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "ipad",
+ "filename" : "logo-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "logo-76.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "76x76",
+ "idiom" : "ipad",
+ "filename" : "logo-76@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "83.5x83.5",
+ "idiom" : "ipad",
+ "filename" : "logo-83.5@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "1024x1024",
+ "idiom" : "ios-marketing",
+ "filename" : "logo-1024.png",
+ "scale" : "1x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/ios/Runner/AppIcon.appiconset/logo-1024.png b/ios/Runner/AppIcon.appiconset/logo-1024.png
new file mode 100644
index 0000000..20102d9
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-1024.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-20.png b/ios/Runner/AppIcon.appiconset/logo-20.png
new file mode 100644
index 0000000..03f60c3
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-20.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-20@2x.png b/ios/Runner/AppIcon.appiconset/logo-20@2x.png
new file mode 100644
index 0000000..fe27f08
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-20@2x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-20@3x.png b/ios/Runner/AppIcon.appiconset/logo-20@3x.png
new file mode 100644
index 0000000..1d09d46
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-20@3x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-29.png b/ios/Runner/AppIcon.appiconset/logo-29.png
new file mode 100644
index 0000000..490fd47
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-29.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-29@2x.png b/ios/Runner/AppIcon.appiconset/logo-29@2x.png
new file mode 100644
index 0000000..90ce766
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-29@2x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-29@3x.png b/ios/Runner/AppIcon.appiconset/logo-29@3x.png
new file mode 100644
index 0000000..b33e6bc
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-29@3x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-40.png b/ios/Runner/AppIcon.appiconset/logo-40.png
new file mode 100644
index 0000000..fe27f08
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-40.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-40@2x.png b/ios/Runner/AppIcon.appiconset/logo-40@2x.png
new file mode 100644
index 0000000..240758a
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-40@2x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-40@3x.png b/ios/Runner/AppIcon.appiconset/logo-40@3x.png
new file mode 100644
index 0000000..dc30e8e
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-40@3x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-60@2x.png b/ios/Runner/AppIcon.appiconset/logo-60@2x.png
new file mode 100644
index 0000000..dc30e8e
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-60@2x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-60@3x.png b/ios/Runner/AppIcon.appiconset/logo-60@3x.png
new file mode 100644
index 0000000..dbaf1a7
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-60@3x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-76.png b/ios/Runner/AppIcon.appiconset/logo-76.png
new file mode 100644
index 0000000..93043c1
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-76.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-76@2x.png b/ios/Runner/AppIcon.appiconset/logo-76@2x.png
new file mode 100644
index 0000000..92107f2
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-76@2x.png differ
diff --git a/ios/Runner/AppIcon.appiconset/logo-83.5@2x.png b/ios/Runner/AppIcon.appiconset/logo-83.5@2x.png
new file mode 100644
index 0000000..039243c
Binary files /dev/null and b/ios/Runner/AppIcon.appiconset/logo-83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..a59299f
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+ "images" : [
+ {
+ "filename" : "Syncrow Icon-20@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Syncrow Icon-20@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Syncrow Icon-29.png",
+ "idiom" : "iphone",
+ "scale" : "1x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Syncrow Icon-29@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Syncrow Icon-29@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Syncrow Icon-40@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Syncrow Icon-40@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Syncrow Icon-60@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "60x60"
+ },
+ {
+ "filename" : "Syncrow Icon-60@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "60x60"
+ },
+ {
+ "filename" : "Syncrow Icon-20.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Syncrow Icon-20@2x 1.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "Syncrow Icon-29 1.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Syncrow Icon-29@2x 1.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "Syncrow Icon-40.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Syncrow Icon-40@2x 1.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "Syncrow Icon-76.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "76x76"
+ },
+ {
+ "filename" : "Syncrow Icon-76@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "76x76"
+ },
+ {
+ "filename" : "Syncrow Icon-83.5@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "83.5x83.5"
+ },
+ {
+ "filename" : "Syncrow Icon-1024.png",
+ "idiom" : "ios-marketing",
+ "scale" : "1x",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-1024.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-1024.png
new file mode 100644
index 0000000..076f903
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-1024.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20.png
new file mode 100644
index 0000000..73e4ade
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@2x 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@2x 1.png
new file mode 100644
index 0000000..ba7adc7
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@2x 1.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@2x.png
new file mode 100644
index 0000000..ba7adc7
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@3x.png
new file mode 100644
index 0000000..be3275f
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-20@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29 1.png
new file mode 100644
index 0000000..0a529fc
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29 1.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29.png
new file mode 100644
index 0000000..0a529fc
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@2x 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@2x 1.png
new file mode 100644
index 0000000..066af50
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@2x 1.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@2x.png
new file mode 100644
index 0000000..066af50
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@3x.png
new file mode 100644
index 0000000..d2ec659
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-29@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40.png
new file mode 100644
index 0000000..ba7adc7
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@2x 1.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@2x 1.png
new file mode 100644
index 0000000..7c1cdcb
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@2x 1.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@2x.png
new file mode 100644
index 0000000..7c1cdcb
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@3x.png
new file mode 100644
index 0000000..bd0ae4c
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-40@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-60@2x.png
new file mode 100644
index 0000000..bd0ae4c
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-60@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-60@3x.png
new file mode 100644
index 0000000..682b8d8
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-60@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-76.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-76.png
new file mode 100644
index 0000000..047ff85
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-76.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-76@2x.png
new file mode 100644
index 0000000..dd495ce
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-76@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-83.5@2x.png
new file mode 100644
index 0000000..84eaebd
Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Syncrow Icon-83.5@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "filename" : "LaunchImage@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000..9da19ea
Binary files /dev/null and b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ
diff --git a/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/ios/Runner/Base.lproj/LaunchScreen.storyboard b/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/Base.lproj/Main.storyboard b/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f80b97a
--- /dev/null
+++ b/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ios/Runner/GoogleService-Info.plist b/ios/Runner/GoogleService-Info.plist
new file mode 100644
index 0000000..196076a
--- /dev/null
+++ b/ios/Runner/GoogleService-Info.plist
@@ -0,0 +1,30 @@
+
+
+
+
+ API_KEY
+ AIzaSyABnpH6yo2RRjtkp4PlvtK84hKwRm2DhBw
+ GCM_SENDER_ID
+ 427332280600
+ PLIST_VERSION
+ 1
+ BUNDLE_ID
+ com.example.syncrow.app
+ PROJECT_ID
+ test2-8a3d2
+ STORAGE_BUCKET
+ test2-8a3d2.appspot.com
+ IS_ADS_ENABLED
+
+ IS_ANALYTICS_ENABLED
+
+ IS_APPINVITE_ENABLED
+
+ IS_GCM_ENABLED
+
+ IS_SIGNIN_ENABLED
+
+ GOOGLE_APP_ID
+ 1:427332280600:ios:c904c0a7a19a4ed90c7e6d
+
+
\ No newline at end of file
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
new file mode 100644
index 0000000..36d1814
--- /dev/null
+++ b/ios/Runner/Info.plist
@@ -0,0 +1,45 @@
+
+
+
+
+ NSPhotoLibraryUsageDescription
+ We need access to your photo library to allow you to select and upload photos.
+ CADisableMinimumFrameDurationOnPhone
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleDisplayName
+ Syncrow App
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ syncrow_app
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ $(FLUTTER_BUILD_NAME)
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ $(FLUTTER_BUILD_NUMBER)
+ LSRequiresIPhoneOS
+
+ UIApplicationSupportsIndirectInputEvents
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+
+
+
diff --git a/ios/Runner/Runner-Bridging-Header.h b/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..308a2a5
--- /dev/null
+++ b/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/ios/RunnerTests/RunnerTests.swift b/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000..86a7c3b
--- /dev/null
+++ b/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+ func testExample() {
+ // If you add code to the Runner application, consider adding tests here.
+ // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+ }
+
+}
diff --git a/lib/features/app_layout/bloc/home_cubit.dart b/lib/features/app_layout/bloc/home_cubit.dart
new file mode 100644
index 0000000..3e85cdc
--- /dev/null
+++ b/lib/features/app_layout/bloc/home_cubit.dart
@@ -0,0 +1,460 @@
+import 'dart:io';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:onesignal_flutter/onesignal_flutter.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:share_plus/share_plus.dart';
+import 'package:syncrow_app/features/app_layout/model/space_model.dart';
+import 'package:syncrow_app/features/app_layout/view/widgets/app_bar_home_dropdown.dart';
+import 'package:syncrow_app/features/auth/model/user_model.dart';
+import 'package:syncrow_app/features/dashboard/view/dashboard_view.dart';
+import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart';
+import 'package:syncrow_app/features/devices/model/room_model.dart';
+import 'package:syncrow_app/features/devices/view/widgets/devices_view_body.dart';
+import 'package:syncrow_app/features/menu/view/menu_view.dart';
+import 'package:syncrow_app/features/scene/bloc/create_scene/create_scene_bloc.dart';
+import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_bloc.dart';
+import 'package:syncrow_app/features/scene/bloc/effective_period/effect_period_event.dart';
+import 'package:syncrow_app/features/scene/bloc/smart_scene/smart_scene_select_dart_bloc.dart';
+import 'package:syncrow_app/features/scene/enum/create_scene_enum.dart';
+import 'package:syncrow_app/features/scene/model/scene_settings_route_arguments.dart';
+import 'package:syncrow_app/features/scene/view/scene_view.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/navigation/navigation_service.dart';
+import 'package:syncrow_app/navigation/routing_constants.dart';
+import 'package:syncrow_app/services/api/devices_api.dart';
+import 'package:syncrow_app/services/api/profile_api.dart';
+import 'package:syncrow_app/services/api/spaces_api.dart';
+import 'package:syncrow_app/utils/helpers/snack_bar.dart';
+import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
+
+part 'home_state.dart';
+
+class HomeCubit extends Cubit {
+ HomeCubit._() : super(HomeInitial()) {
+ checkIfNotificationPermissionGranted();
+ fetchUserInfo();
+ if (selectedSpace == null) {
+ fetchUnitsByUserId();
+ // .then((value) {
+ // if (selectedSpace != null) {
+ // fetchRoomsByUnitId(selectedSpace!);
+ // }
+ // });
+ }
+ }
+ static UserModel? user;
+ static HomeCubit? _instance;
+ static HomeCubit getInstance() {
+ // If an instance already exists, return it
+ _instance ??= HomeCubit._();
+ return _instance!;
+ }
+
+ Future fetchUserInfo() async {
+ try {
+ var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
+ user = await ProfileApi().fetchUserInfo(uuid);
+ emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
+ } catch (e) {
+ return;
+ }
+ }
+
+ void emitSafe(HomeState newState) {
+ final cubit = this;
+ if (!cubit.isClosed) {
+ cubit.emit(newState);
+ }
+ }
+
+ @override
+ Future close() {
+ _instance = null;
+ selectedSpace = null;
+ selectedRoom = null;
+ pageIndex = 0;
+ OneSignal.User.pushSubscription.removeObserver((stateChanges) => oneSignalSubscriptionObserver);
+ OneSignal.Notifications.removePermissionObserver((permission) => oneSignalPermissionObserver);
+ OneSignal.Notifications.removeClickListener((event) => oneSignalClickListenerObserver);
+ return super.close();
+ }
+
+ static HomeCubit get(context) => BlocProvider.of(context);
+
+ List? spaces;
+
+ SpaceModel? selectedSpace;
+
+ RoomModel? selectedRoom;
+
+ PageController devicesPageController = PageController();
+
+ PageController roomsPageController = PageController();
+
+ var duration = const Duration(milliseconds: 300);
+
+ void oneSignalPermissionObserver;
+ void oneSignalSubscriptionObserver;
+ void oneSignalClickListenerObserver;
+
+ // selectSpace(SpaceModel space) async {
+ // selectedSpace = space;
+ // emit(SpaceSelected(space));
+ // }
+
+ checkIfNotificationPermissionGranted() async {
+ try {
+ OneSignal.initialize('762350c9-1e5d-4d95-a648-16d4dc8a25e1');
+
+ //Show native push notification dialog
+ if (Platform.isIOS) {
+ await OneSignal.Notifications.permissionNative();
+ } else {
+ await OneSignal.Notifications.requestPermission(true);
+ }
+
+ if (await Permission.notification.isGranted == false) {
+ return;
+ }
+
+ var userUuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
+ if (userUuid.isNotEmpty) {
+ await OneSignal.login(userUuid);
+ }
+ //Enable push notifications
+ await OneSignal.User.pushSubscription.optIn();
+
+ //this function will be called once a user is subscribed
+ oneSignalSubscriptionObserver = OneSignal.User.pushSubscription.addObserver((state) async {
+ if (state.current.optedIn) {
+ await _sendSubscriptionId();
+ }
+ });
+
+ // Send the player id when a user allows notifications
+ oneSignalPermissionObserver = OneSignal.Notifications.addPermissionObserver((state) async {
+ await _sendSubscriptionId();
+ });
+
+ //check if the player id is sent, if not send it again
+ await _sendSubscriptionId();
+
+ oneSignalClickListenerObserver = OneSignal.Notifications.addClickListener((event) async {
+ //Once the user clicks on the notification
+ });
+ } catch (err) {
+ debugPrint("******* Error");
+ debugPrint(err.toString());
+ rethrow;
+ }
+ }
+
+ _sendSubscriptionId() async {
+ // String? subscriptionId = OneSignal.User.pushSubscription.id ?? '';
+ //TODO send the subscription id to BE
+ }
+
+ changeSelectedSpace(SpaceModel space) {
+ selectedSpace = space;
+ emitSafe(SpaceSelected(space));
+ fetchRoomsByUnitId(space);
+ }
+
+ roomSliderPageChanged(int index) {
+ devicesPageController.animateToPage(
+ index,
+ duration: duration,
+ curve: Curves.linear,
+ );
+
+ if (index == 0) {
+ unselectRoom();
+ } else {
+ selectedRoom = selectedSpace!.rooms![index - 1];
+ emitSafe(RoomSelected(selectedRoom!));
+ }
+ }
+
+ devicesPageChanged(int index) {
+ roomsPageController.animateToPage(
+ index,
+ duration: const Duration(milliseconds: 300),
+ curve: Curves.linear,
+ );
+
+ if (index <= 0) {
+ unselectRoom();
+ } else {
+ selectedRoom = selectedSpace!.rooms![index - 1];
+ emitSafe(RoomSelected(selectedRoom!));
+ }
+ }
+
+ unselectRoom() {
+ // selectedRoom = null;
+ devicesPageController.animateToPage(
+ 0,
+ duration: duration,
+ curve: Curves.linear,
+ );
+
+ roomsPageController.animateToPage(
+ 0,
+ duration: duration,
+ curve: Curves.linear,
+ );
+
+ emitSafe(RoomUnSelected());
+ }
+
+//////////////////////////////////////// API ////////////////////////////////////////
+ generateInvitation(String unitId) async {
+ try {
+ final invitationCode = await SpacesAPI.generateInvitationCode(unitId);
+ if (invitationCode.isNotEmpty) {
+ Share.share('The invitation code is $invitationCode');
+ CustomSnackBar.displaySnackBar(
+ 'Invitation code generated successfully the code is: $invitationCode');
+ } else {
+ CustomSnackBar.displaySnackBar('Please try again!');
+ }
+ } catch (failure) {
+ CustomSnackBar.displaySnackBar('Something went wrong');
+ return;
+ }
+ }
+
+ Future joinAUnit(String code) async {
+ try {
+ var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey) ?? '';
+ Map body = {'userUuid': uuid, 'inviteCode': code};
+
+ final success = await SpacesAPI.joinUnit(body);
+ if (success) {
+ await fetchUnitsByUserId();
+ CustomSnackBar.displaySnackBar('Done successfully');
+ }
+ return true;
+ } catch (failure) {
+ CustomSnackBar.displaySnackBar('Something went wrong');
+ return false;
+ }
+ }
+
+ fetchUnitsByUserId() async {
+ emitSafe(GetSpacesLoading());
+ try {
+ spaces = await SpacesAPI.getUnitsByUserId();
+ } catch (failure) {
+ emitSafe(GetSpacesError("No units found"));
+ return;
+ }
+
+ if (spaces != null && spaces!.isNotEmpty) {
+ selectedSpace = spaces!.first;
+ await fetchRoomsByUnitId(selectedSpace!);
+ emitSafe(GetSpacesSuccess(spaces!));
+ } else {
+ emitSafe(GetSpacesError("No spaces found"));
+ }
+ }
+
+ fetchRoomsByUnitId(SpaceModel space) async {
+ emitSafe(GetSpaceRoomsLoading());
+ try {
+ space.rooms = await SpacesAPI.getRoomsBySpaceId(space.id!);
+ } catch (failure) {
+ emitSafe(GetSpaceRoomsError(failure.toString()));
+ return;
+ }
+ if (space.rooms != null && space.rooms!.isNotEmpty) {
+ emitSafe(GetSpaceRoomsSuccess(space.rooms!));
+ } else {
+ emitSafe(GetSpaceRoomsError("No rooms found"));
+ }
+ }
+
+ /////////////////////////////////////// Nav ///////////////////////////////////////
+
+ static int pageIndex = 0;
+
+ static Map> appBarActions = {
+ 'Dashboard': [
+ // IconButton(
+ // icon: const Icon(
+ // Icons.add,
+ // size: 25,
+ // ),
+ // style: ButtonStyle(
+ // foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor),
+ // ),
+ // onPressed: () {
+ // Navigator.push(
+ // NavigationService.navigatorKey.currentContext!,
+ // CustomPageRoute(
+ // builder: (context) => CurtainView(
+ // curtain: DeviceModel(
+ // name: "Curtain",
+ // status: [StatusModel(code: "awd", value: 1)],
+ // productType: DeviceType.Curtain,
+ // ),
+ // ),
+ // ),
+ // );
+ // },
+ // ),
+ ],
+ 'Devices': [
+ //TODO: to be checked
+ // IconButton(
+ // icon: const Icon(
+ // Icons.add,
+ // size: 25,
+ // ),
+ // style: ButtonStyle(
+ // foregroundColor:
+ // MaterialStateProperty.all(ColorsManager.textPrimaryColor),
+ // ),
+ // onPressed: () {},
+ // ),
+ // IconButton(
+ // icon: const Icon(
+ // Icons.more_vert,
+ // size: 25,
+ // ),
+ // style: ButtonStyle(
+ // foregroundColor:
+ // MaterialStateProperty.all(ColorsManager.textPrimaryColor),
+ // ),
+ // onPressed: () {},
+ // ),
+ ],
+ 'Routine': [
+ // IconButton(
+ // icon: Image.asset(
+ // Assets.assetsIconsFilter,
+ // height: 20,
+ // width: 20,
+ // ),
+ // onPressed: () {},
+ // ),
+ IconButton(
+ icon: const Icon(
+ Icons.add,
+ size: 32,
+ ),
+ style: ButtonStyle(
+ foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor),
+ ),
+ onPressed: () {
+ Navigator.pushNamed(
+ NavigationService.navigatorKey.currentContext!,
+ Routes.sceneTasksRoute,
+ arguments: SceneSettingsRouteArguments(
+ sceneType: '',
+ sceneId: '',
+ sceneName: '',
+ ),
+ );
+ NavigationService.navigatorKey.currentContext!
+ .read()
+ .add(const ClearTaskListEvent());
+ NavigationService.navigatorKey.currentContext!
+ .read()
+ .add(const SceneTypeEvent(CreateSceneEnum.none));
+ NavigationService.navigatorKey.currentContext!
+ .read()
+ .add(const SmartSceneClearEvent());
+ BlocProvider.of(NavigationService.navigatorKey.currentState!.context)
+ .add(ResetEffectivePeriod());
+ },
+ ),
+ IconButton(
+ icon: const Icon(
+ Icons.more_vert,
+ size: 28,
+ ),
+ style: ButtonStyle(
+ foregroundColor: WidgetStateProperty.all(ColorsManager.textPrimaryColor),
+ ),
+ onPressed: () {},
+ ),
+ ],
+ 'Menu': [
+ IconButton(
+ icon: SvgPicture.asset(
+ Assets.assetsIconsScan,
+ height: 20,
+ width: 20,
+ ),
+ onPressed: () {},
+ ),
+ ],
+ };
+
+ static Map appBarLeading = {
+ 'Dashboard': const AppBarHomeDropdown(),
+ 'Devices': const AppBarHomeDropdown(),
+ 'Routine': const AppBarHomeDropdown(),
+ 'Menu': Padding(
+ padding: const EdgeInsets.only(left: 15),
+ child: Image.asset(
+ Assets.assetsImagesLogoHorizontal,
+ height: 15,
+ width: 100,
+ fit: BoxFit.scaleDown,
+ ),
+ ),
+ };
+
+ static var bottomNavItems = [
+ defaultBottomNavBarItem(icon: Assets.assetsIconsDashboard, label: 'Dashboard'),
+ // defaultBottomNavBarItem(icon: Assets.assetsIconslayout, label: 'Layout'),
+ defaultBottomNavBarItem(icon: Assets.assetsIconsDevices, label: 'Devices'),
+ defaultBottomNavBarItem(icon: Assets.assetsIconsRoutines, label: 'Routine'),
+ defaultBottomNavBarItem(icon: Assets.assetsIconsMenu, label: 'Menu'),
+ ];
+
+ final List pages = [
+ const DashboardView(),
+ // const LayoutPage(),
+ BlocProvider(
+ create: (context) => DevicesCubit.getInstance(),
+ child: const DevicesViewBody(),
+ ),
+ const SceneView(),
+ const MenuView(),
+ ];
+
+ void updatePageIndex(int index) {
+ pageIndex = index;
+
+ emitSafe(NavChangePage());
+ }
+
+ void updateDevice(String deviceId) async {
+ try {
+ final response = await DevicesAPI.firmwareDevice(deviceId: deviceId, firmwareVersion: '0');
+ if (response['success'] ?? false) {
+ CustomSnackBar.displaySnackBar('No updates available');
+ }
+ } catch (_) {}
+ }
+}
+
+BottomNavigationBarItem defaultBottomNavBarItem({required String icon, required String label}) {
+ return BottomNavigationBarItem(
+ icon: SvgPicture.asset(icon),
+ activeIcon: SvgPicture.asset(
+ icon.replaceAll('.svg', '-fill.svg'),
+ colorFilter: const ColorFilter.mode(
+ ColorsManager.primaryColor,
+ BlendMode.srcIn,
+ ),
+ ),
+ label: label,
+ );
+}
diff --git a/lib/features/app_layout/bloc/home_state.dart b/lib/features/app_layout/bloc/home_state.dart
new file mode 100644
index 0000000..1125e01
--- /dev/null
+++ b/lib/features/app_layout/bloc/home_state.dart
@@ -0,0 +1,66 @@
+part of 'home_cubit.dart';
+
+abstract class HomeState {}
+
+class HomeInitial extends HomeState {}
+
+//base states
+class HomeLoading extends HomeState {}
+
+class HomeError extends HomeState {
+ final String errMessage;
+
+ HomeError(this.errMessage);
+}
+
+class HomeSuccess extends HomeState {}
+
+///specific states
+//get spaces
+class GetSpacesLoading extends HomeLoading {}
+
+class GetSpacesSuccess extends HomeSuccess {
+ final List spaces;
+
+ GetSpacesSuccess(this.spaces);
+}
+
+class GetSpacesError extends HomeError {
+ GetSpacesError(super.errMessage);
+}
+
+//get rooms
+class GetSpaceRoomsLoading extends HomeLoading {}
+
+class GetSpaceRoomsSuccess extends HomeSuccess {
+ final List rooms;
+
+ GetSpaceRoomsSuccess(this.rooms);
+}
+
+class GetSpaceRoomsError extends HomeError {
+ GetSpaceRoomsError(super.errMessage);
+}
+
+//UI states
+class SpaceSelected extends HomeState {
+ final SpaceModel space;
+
+ SpaceSelected(this.space);
+}
+
+class RoomSelected extends HomeState {
+ final RoomModel room;
+
+ RoomSelected(this.room);
+}
+
+class RoomUnSelected extends HomeState {}
+
+class NavChangePage extends HomeState {}
+// Define new state classes
+class HomeUserInfoLoaded extends HomeState {
+ final UserModel user;
+
+ HomeUserInfoLoaded(this.user);
+}
diff --git a/lib/features/app_layout/model/space_model.dart b/lib/features/app_layout/model/space_model.dart
new file mode 100644
index 0000000..8d7d5b8
--- /dev/null
+++ b/lib/features/app_layout/model/space_model.dart
@@ -0,0 +1,37 @@
+import 'package:syncrow_app/features/devices/model/room_model.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+
+class SpaceModel {
+ final String? id;
+ final String? name;
+ final SpaceType type;
+ late List? rooms;
+
+ SpaceModel({
+ required this.type,
+ required this.id,
+ required this.name,
+ required this.rooms,
+ });
+
+ Map toJson() {
+ return {
+ 'id': id,
+ 'name': name,
+ 'rooms': rooms,
+ };
+ }
+
+ factory SpaceModel.fromJson(Map json) {
+ return SpaceModel(
+ id: json['uuid'],
+ name: json['name'],
+ type: spaceTypesMap[json['type']]!,
+ rooms: [],
+ );
+ }
+
+ static List fromJsonList(List jsonList) {
+ return jsonList.map((item) => SpaceModel.fromJson(item)).toList();
+ }
+}
diff --git a/lib/features/app_layout/view/app_layout.dart b/lib/features/app_layout/view/app_layout.dart
new file mode 100644
index 0000000..214cce2
--- /dev/null
+++ b/lib/features/app_layout/view/app_layout.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/features/app_layout/view/widgets/app_body.dart';
+import 'package:syncrow_app/features/app_layout/view/widgets/default_app_bar.dart';
+import 'package:syncrow_app/features/app_layout/view/widgets/default_nav_bar.dart';
+import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
+
+class AppLayout extends StatelessWidget {
+ const AppLayout({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocProvider(
+ create: (context) => HomeCubit.getInstance(),
+ child: BlocBuilder(
+ builder: (context, state) {
+ return DefaultScaffold(
+ appBar: HomeCubit.getInstance().spaces != null ? const DefaultAppBar() : null,
+ bottomNavBar: const DefaultNavBar(),
+ child: const AppBody(),
+ );
+ },
+ ),
+ );
+ }
+}
diff --git a/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart b/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart
new file mode 100644
index 0000000..e00eae3
--- /dev/null
+++ b/lib/features/app_layout/view/widgets/app_bar_home_dropdown.dart
@@ -0,0 +1,78 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
+
+class AppBarHomeDropdown extends StatelessWidget {
+ const AppBarHomeDropdown({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return Padding(
+ padding: const EdgeInsets.only(left: 10, right: 10),
+ child: Center(
+ child: DropdownButton(
+ icon: const Icon(
+ Icons.expand_more,
+ color: ColorsManager.textPrimaryColor,
+ size: 16,
+ ),
+ underline: const SizedBox.shrink(),
+ padding: EdgeInsets.zero,
+ borderRadius: BorderRadius.circular(20),
+ value: HomeCubit.getInstance().selectedSpace!.id,
+ items: HomeCubit.getInstance().spaces!.map((space) {
+ return DropdownMenuItem(
+ alignment: AlignmentDirectional.centerStart,
+ value: space.id,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SvgPicture.asset(
+ Assets.assetsIconsHome,
+ width: 25,
+ height: 25,
+ colorFilter: const ColorFilter.mode(
+ ColorsManager.textPrimaryColor,
+ BlendMode.srcIn,
+ ),
+ ),
+ const SizedBox(width: 5),
+ Flexible(
+ fit: FlexFit.loose,
+ child: BodyMedium(
+ text: space.name ?? "??",
+ style: context.bodyMedium.copyWith(
+ fontSize: 15,
+ color: ColorsManager.textPrimaryColor,
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ ),
+ const SizedBox(width: 5),
+ ],
+ ),
+ );
+ }).toList(),
+ onChanged: (value) {
+ if (value != null) {
+ HomeCubit.getInstance().changeSelectedSpace(
+ HomeCubit.getInstance()
+ .spaces!
+ .firstWhere((element) => element.id == value));
+ }
+ },
+ ),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/app_layout/view/widgets/app_body.dart b/lib/features/app_layout/view/widgets/app_body.dart
new file mode 100644
index 0000000..f902db1
--- /dev/null
+++ b/lib/features/app_layout/view/widgets/app_body.dart
@@ -0,0 +1,32 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+
+class AppBody extends StatelessWidget {
+ const AppBody({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocConsumer(
+ listener: (context, state) {
+ if (state is GetSpacesError) {
+ ScaffoldMessenger.of(context).removeCurrentSnackBar();
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text(state.errMessage),
+ ),
+ );
+ }
+ },
+ builder: (context, state) {
+ return state is! GetSpacesLoading
+ ? state is! GetSpaceRoomsLoading
+ ? HomeCubit.getInstance().pages[HomeCubit.pageIndex]
+ : const Center(child: CircularProgressIndicator())
+ : const Center(child: CircularProgressIndicator());
+ },
+ );
+ }
+}
diff --git a/lib/features/app_layout/view/widgets/default_app_bar.dart b/lib/features/app_layout/view/widgets/default_app_bar.dart
new file mode 100644
index 0000000..6c67536
--- /dev/null
+++ b/lib/features/app_layout/view/widgets/default_app_bar.dart
@@ -0,0 +1,35 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+
+class DefaultAppBar extends StatelessWidget implements PreferredSizeWidget {
+ const DefaultAppBar({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return Padding(
+ padding: const EdgeInsets.only(
+ top: 20,
+ ),
+ child: AppBar(
+ backgroundColor: Colors.transparent,
+ leadingWidth: 150,
+ toolbarHeight: Constants.appBarHeight,
+ leading: HomeCubit.getInstance().spaces!.isNotEmpty
+ ? HomeCubit.appBarLeading[
+ HomeCubit.bottomNavItems[HomeCubit.pageIndex].label]
+ : null,
+ actions: HomeCubit.appBarActions[
+ HomeCubit.bottomNavItems[HomeCubit.pageIndex].label],
+ ));
+ },
+ );
+ }
+
+ @override
+ Size get preferredSize => Size.fromHeight(Constants.appBarHeight);
+}
diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart
new file mode 100644
index 0000000..79754a6
--- /dev/null
+++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
+
+class DefaultNavBar extends StatelessWidget {
+ const DefaultNavBar({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ var cubit = HomeCubit.getInstance();
+ return BottomNavigationBar(
+ backgroundColor: Colors.transparent,
+ onTap: (int index) {
+ cubit.updatePageIndex(index);
+ HomeCubit.getInstance().updatePageIndex(index);
+ },
+ currentIndex: HomeCubit.pageIndex,
+ selectedItemColor: ColorsManager.primaryColor,
+ selectedLabelStyle: const TextStyle(
+ color: ColorsManager.primaryColor,
+ fontSize: 10,
+ ),
+ showUnselectedLabels: true,
+ unselectedItemColor: Colors.grey,
+ type: BottomNavigationBarType.fixed,
+ elevation: 0,
+ items: HomeCubit.bottomNavItems,
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/bloc/auth_cubit.dart b/lib/features/auth/bloc/auth_cubit.dart
new file mode 100644
index 0000000..2b1ae24
--- /dev/null
+++ b/lib/features/auth/bloc/auth_cubit.dart
@@ -0,0 +1,340 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+import 'package:syncrow_app/features/auth/model/login_with_email_model.dart';
+import 'package:syncrow_app/features/auth/model/signup_model.dart';
+import 'package:syncrow_app/features/auth/model/token.dart';
+import 'package:syncrow_app/features/auth/model/user_model.dart';
+import 'package:syncrow_app/navigation/navigation_service.dart';
+import 'package:syncrow_app/navigation/routing_constants.dart';
+import 'package:syncrow_app/services/api/authentication_api.dart';
+import 'package:syncrow_app/services/api/profile_api.dart';
+import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart';
+import 'package:syncrow_app/utils/helpers/snack_bar.dart';
+import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
+part 'auth_state.dart';
+
+class AuthCubit extends Cubit {
+ AuthCubit() : super(AuthInitial());
+ static AuthCubit get(context) => BlocProvider.of(context);
+
+ final TextEditingController emailController = TextEditingController();
+ final TextEditingController passwordController = TextEditingController();
+
+ String fullName = '';
+ String email = '';
+ String forgetPasswordEmail = '';
+ String signUpPassword = '';
+ String newPassword = '';
+ String maskedEmail = '';
+ String otpCode = '';
+ final loginFormKey = GlobalKey();
+ final signUpFormKey = GlobalKey();
+ final checkEmailFormKey = GlobalKey();
+ final createNewPasswordKey = GlobalKey();
+
+ bool isPasswordVisible = false;
+ bool showValidationMessage = false;
+
+ void changePasswordVisibility() {
+ isPasswordVisible = !isPasswordVisible;
+ emit(AuthPasswordVisibilityChanged());
+ }
+
+ bool agreeToTerms = false;
+
+ void changeAgreeToTerms() {
+ agreeToTerms = !agreeToTerms;
+ emit(AuthAgreeToTermsChanged());
+ }
+
+ static UserModel? user;
+
+ static Token token = Token.emptyConstructor();
+
+ setOtpCode(String value) {
+ otpCode = value;
+ }
+
+/////////////////////////////////////VALIDATORS/////////////////////////////////////
+ String? passwordValidator(String? value) {
+ if (value == null || value.isEmpty) {
+ return "Please enter your password";
+ }
+
+ if (value.length < 8) {
+ return 'Password must be at least 8 characters long';
+ }
+
+ if (!RegExp(r'[a-z]').hasMatch(value)) {
+ return 'Password must contain at least one lowercase letter';
+ }
+
+ if (!RegExp(r'[A-Z]').hasMatch(value)) {
+ return 'Password must contain at least one uppercase letter';
+ }
+
+ if (!RegExp(r'\d').hasMatch(value)) {
+ return 'Password must contain at least one number';
+ }
+
+ if (!RegExp(r'[!"#$%&()*+,-./:;<=>?@[\]^_`{|}~]').hasMatch(value)) {
+ return 'Password must contain at least one special character';
+ }
+
+ return null;
+ }
+
+ String? fullNameValidator(String? value) {
+ if (value == null) return 'Full name is required';
+
+ final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim();
+
+ if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) {
+ return 'Full name must be between 2 and 30 characters long';
+ }
+
+ // Test if it contains anything but alphanumeric spaces and single quote
+
+ if (RegExp(r"/[^ a-zA-Z0-9-\']/").hasMatch(withoutExtraSpaces)) {
+ return 'Only alphanumeric characters, space, dash and single quote are allowed';
+ }
+
+ final parts = withoutExtraSpaces.split(' ');
+
+ if (parts.length < 2) return 'Full name must contain first and last names';
+
+ if (parts.length > 3) return 'Full name can at most contain 3 parts';
+
+ if (parts.any((part) => part.length < 2 || part.length > 30)) {
+ return 'Full name parts must be between 2 and 30 characters long';
+ }
+ return null;
+ }
+
+ String? reEnterPasswordCheck(String? value) {
+ passwordValidator(value);
+ if (signUpPassword == value) {
+ return null;
+ } else {
+ return 'Passwords do not match';
+ }
+ }
+
+ String? reEnterPasswordCheckForgetPass(String? value) {
+ passwordValidator(value);
+ if (newPassword == value) {
+ return null;
+ } else {
+ return 'Passwords do not match';
+ }
+ }
+
+ String? emailAddressValidator(String? value) {
+ if (value != null && value.isNotEmpty && value != "") {
+ if (checkValidityOfEmail(value)) {
+ return null;
+ } else {
+ return 'Please enter a valid email';
+ }
+ } else {
+ return 'Email address is required';
+ }
+ }
+
+ bool checkValidityOfEmail(String? email) {
+ if (email != null) {
+ return RegExp(
+ r"^[a-zA-Z0-9]+([.!#$%&'*+/=?^_`{|}~-]?[a-zA-Z0-9]+)*@[a-zA-Z0-9]+([.-]?[a-zA-Z0-9]+)*\.[a-zA-Z0-9]{2,}$")
+ .hasMatch(email);
+ } else {
+ return false;
+ }
+ }
+
+ // Function to mask the email
+ String maskEmail(String email) {
+ final emailParts = email.split('@');
+ if (emailParts.length != 2) return email;
+
+ final localPart = emailParts[0];
+ final domainPart = emailParts[1];
+
+ if (localPart.length < 3) return email;
+
+ final start = localPart.substring(0, 2);
+ final end = localPart.substring(localPart.length - 1);
+
+ final maskedLocalPart = '$start******$end';
+ return '$maskedLocalPart@$domainPart';
+ }
+
+/////////////////////////////////////API CALLS/////////////////////////////////////
+ login() async {
+ emit(AuthLoginLoading());
+ try {
+ if (emailController.text.isEmpty || passwordController.text.isEmpty) {
+ CustomSnackBar.displaySnackBar('Please enter your credentials');
+ emit(AuthLoginError(message: 'Something went wrong'));
+ return;
+ }
+
+ token = await AuthenticationAPI.loginWithEmail(
+ model: LoginWithEmailModel(
+ email: emailController.text.toLowerCase(),
+ password: passwordController.text,
+ ),
+ );
+ } catch (failure) {
+ emit(AuthLoginError(message: failure.toString()));
+ return;
+ }
+ if (token.accessTokenIsNotEmpty) {
+ debugPrint('token: ${token.accessToken}');
+ FlutterSecureStorage storage = const FlutterSecureStorage();
+ await storage.write(
+ key: Token.loginAccessTokenKey, value: token.accessToken);
+ const FlutterSecureStorage().write(
+ key: UserModel.userUuidKey,
+ value: Token.decodeToken(token.accessToken)['uuid'].toString());
+ user = UserModel.fromToken(token);
+ emailController.clear();
+ passwordController.clear();
+ emit(AuthLoginSuccess());
+ } else {
+ emit(AuthLoginError(message: 'Something went wrong'));
+ }
+ }
+
+ signUp() async {
+ emit(AuthLoginLoading());
+ final response;
+ try {
+ List userFullName = fullName.split(' ');
+ response = await AuthenticationAPI.signUp(
+ model: SignUpModel(
+ email: email.toLowerCase(),
+ password: signUpPassword,
+ firstName: userFullName[0],
+ lastName: userFullName[1]),
+ );
+ } catch (failure) {
+ emit(AuthLoginError(message: failure.toString()));
+ return;
+ }
+ if (response) {
+ maskedEmail = maskEmail(email);
+ await sendOtp();
+ } else {
+ emit(AuthLoginError(message: 'Something went wrong'));
+ }
+ }
+
+ sendOtp() async {
+ try {
+ emit(AuthLoading());
+ await AuthenticationAPI.sendOtp(
+ body: {'email': email, 'type': 'VERIFICATION'});
+ emit(AuthSignUpSuccess());
+ } catch (_) {
+ emit(AuthLoginError(message: 'Something went wrong'));
+ }
+ }
+
+ reSendOtp() async {
+ try {
+ emit(AuthLoading());
+ await AuthenticationAPI.sendOtp(
+ body: {'email': email, 'type': 'VERIFICATION'});
+ emit(ResendOtpSuccess());
+ } catch (_) {
+ emit(AuthLoginError(message: 'Something went wrong'));
+ }
+ }
+
+ verifyOtp(bool isForgotPass) async {
+ emit(AuthLoginLoading());
+ try {
+ final response = await AuthenticationAPI.verifyPassCode(
+ body: {'email': email, 'type': 'VERIFICATION', 'otpCode': otpCode});
+ if (response['statusCode'] == 200) {
+ if (!isForgotPass) {
+ emailController.text = email;
+ passwordController.text = signUpPassword;
+ await login();
+ }
+ emit(AuthOtpSuccess());
+ } else {
+ emit(AuthLoginError(message: 'Something went wrong'));
+ }
+ } catch (failure) {
+ emit(AuthLoginError(message: 'Something went wrong'));
+ return;
+ }
+ }
+
+ logout() async {
+ emit(AuthLogoutLoading());
+ try {
+ FlutterSecureStorage storage = const FlutterSecureStorage();
+ await storage.delete(key: Token.loginAccessTokenKey);
+ NavigationService.navigatorKey.currentState!.pushNamedAndRemoveUntil(
+ Routes.splash,
+ (Route route) => false,
+ );
+ } catch (failure) {
+ emit(AuthLogoutError(message: 'Something went wrong'));
+ return;
+ }
+ }
+
+ getTokenAndValidate() async {
+ try {
+ emit(AuthTokenLoading());
+ const storage = FlutterSecureStorage();
+ final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(
+ StringsManager.firstLaunch) ??
+ true;
+
+ if (firstLaunch) {
+ storage.deleteAll();
+ }
+
+ await SharedPreferencesHelper.saveBoolToSP(
+ StringsManager.firstLaunch, false);
+
+ final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
+ if (value.isEmpty) {
+ emit(AuthTokenError(message: "Token not found"));
+ return;
+ }
+
+ final tokenData = Token.decodeToken(value);
+
+ if (tokenData.containsKey('exp')) {
+ final exp = tokenData['exp'] ?? 0;
+ final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
+
+ if (currentTime < exp) {
+ emit(AuthTokenSuccess());
+ } else {
+ emit(AuthTokenError(message: "Token expired"));
+ }
+ } else {
+ emit(AuthTokenError(message: "Something went wrong"));
+ }
+ } catch (_) {
+ emit(AuthTokenError(message: "Something went wrong"));
+ }
+ }
+
+ sendToForgetPassword({required String password}) async {
+ try {
+ emit(AuthForgetPassLoading());
+ await AuthenticationAPI.forgetPassword(email: email, password: password);
+ emit(AuthForgetPassSuccess());
+ } catch (_) {
+ emit(AuthForgetPassError(message: 'Something went wrong'));
+ }
+ }
+}
diff --git a/lib/features/auth/bloc/auth_state.dart b/lib/features/auth/bloc/auth_state.dart
new file mode 100644
index 0000000..9dbcc2b
--- /dev/null
+++ b/lib/features/auth/bloc/auth_state.dart
@@ -0,0 +1,66 @@
+part of 'auth_cubit.dart';
+
+abstract class AuthState {}
+
+class AuthInitial extends AuthState {}
+
+//base states
+class AuthLoading extends AuthState {}
+
+class AuthError extends AuthState {
+ final String message;
+ String? code;
+ AuthError({required this.message, this.code});
+}
+
+class AuthSuccess extends AuthState {}
+
+//user log states
+class AuthLoginLoading extends AuthLoading {}
+
+class AuthLoginSuccess extends AuthSuccess {}
+
+class AuthOtpSuccess extends AuthSuccess {}
+
+class AuthSignUpSuccess extends AuthSuccess {}
+
+class ResendOtpSuccess extends AuthSuccess {}
+
+class AuthLoginError extends AuthError {
+ AuthLoginError({required super.message, super.code});
+}
+
+class AuthLogoutLoading extends AuthLoading {}
+
+class AuthLogoutSuccess extends AuthSuccess {}
+
+class AuthLogoutError extends AuthError {
+ AuthLogoutError({required super.message, super.code});
+}
+
+// UI states
+class AuthPasswordVisibilityChanged extends AuthState {}
+
+class AuthAgreeToTermsChanged extends AuthState {}
+
+//token states
+class AuthTokenLoading extends AuthLoading {}
+
+class AuthTokenSuccess extends AuthSuccess {}
+
+class AuthTokenError extends AuthError {
+ AuthTokenError({required super.message, super.code});
+}
+
+
+
+
+//ForgetPassword log states
+class AuthForgetPassLoading extends AuthLoading {}
+
+class AuthForgetPassSuccess extends AuthSuccess {}
+
+class AuthForgetPassError extends AuthError {
+ AuthForgetPassError({required super.message, super.code});
+}
+
diff --git a/lib/features/auth/model/login_with_email_model.dart b/lib/features/auth/model/login_with_email_model.dart
new file mode 100644
index 0000000..c387b0d
--- /dev/null
+++ b/lib/features/auth/model/login_with_email_model.dart
@@ -0,0 +1,23 @@
+class LoginWithEmailModel {
+ final String email;
+ final String password;
+
+ LoginWithEmailModel({
+ required this.email,
+ required this.password,
+ });
+
+ factory LoginWithEmailModel.fromJson(Map json) {
+ return LoginWithEmailModel(
+ email: json['email'],
+ password: json['password'],
+ );
+ }
+
+ Map toJson() {
+ return {
+ 'email': email,
+ 'password': password,
+ };
+ }
+}
diff --git a/lib/features/auth/model/signup_model.dart b/lib/features/auth/model/signup_model.dart
new file mode 100644
index 0000000..c4a0adf
--- /dev/null
+++ b/lib/features/auth/model/signup_model.dart
@@ -0,0 +1,29 @@
+class SignUpModel {
+ final String email;
+ final String password;
+ final String firstName;
+ final String lastName;
+
+ SignUpModel(
+ {required this.email,
+ required this.password,
+ required this.firstName,
+ required this.lastName});
+
+ factory SignUpModel.fromJson(Map json) {
+ return SignUpModel(
+ email: json['email'],
+ password: json['password'],
+ firstName: json['firstName'],
+ lastName: json['lastName']);
+ }
+
+ Map toJson() {
+ return {
+ 'email': email,
+ 'password': password,
+ 'firstName': firstName,
+ 'lastName': lastName,
+ };
+ }
+}
diff --git a/lib/features/auth/model/token.dart b/lib/features/auth/model/token.dart
new file mode 100644
index 0000000..7513673
--- /dev/null
+++ b/lib/features/auth/model/token.dart
@@ -0,0 +1,79 @@
+import 'dart:convert';
+
+import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+import 'package:syncrow_app/utils/helpers/decode_base64.dart';
+
+class Token {
+ static const String loginAccessTokenKey = 'accessToken';
+ static const String loginRefreshTokenKey = 'refreshToken';
+
+ final String accessToken;
+ final String refreshToken;
+
+ //{
+ // "email": "test@test.com",
+ // "userId": 3,
+ // "uuid": "563e22d2-cb30-46d3-8c48-fa7d762342f0",
+ // "sessionId": "f76aa067-c915-4921-b04d-9fbc71c4965a",
+ // "iat": 1710137435,
+ // "exp": 1710137735
+ // }
+
+ final String sessionId;
+
+ final int iat;
+ final int exp;
+
+ Token.emptyConstructor()
+ : accessToken = '',
+ refreshToken = '',
+ sessionId = '',
+ iat = 0,
+ exp = 0;
+
+ bool get accessTokenIsNotEmpty => accessToken.isNotEmpty;
+
+ bool get refreshTokenIsNotEmpty => refreshToken.isNotEmpty;
+
+ bool get isNotEmpty => accessToken.isNotEmpty && refreshToken.isNotEmpty;
+
+ Token(
+ this.accessToken,
+ this.refreshToken,
+ this.sessionId,
+ this.iat,
+ this.exp,
+ );
+
+ Token.refreshToken(this.refreshToken)
+ : accessToken = '',
+ sessionId = '',
+ iat = 0,
+ exp = 0;
+
+ factory Token.fromJson(Map json) {
+ //save token to secure storage
+ var storage = const FlutterSecureStorage();
+ storage.write(
+ key: loginAccessTokenKey, value: json[loginAccessTokenKey] ?? '');
+ storage.write(
+ key: loginRefreshTokenKey, value: json[loginRefreshTokenKey] ?? '');
+ //create token object ?
+ return Token(json[loginAccessTokenKey] ?? '',
+ json[loginRefreshTokenKey] ?? '', '', 0, 0);
+ }
+
+ Map refreshTokenToJson() =>
+ {loginRefreshTokenKey: refreshToken};
+
+ Map accessTokenToJson() => {loginAccessTokenKey: accessToken};
+
+ static Map decodeToken(String accessToken) {
+ final parts = accessToken.split('.');
+ if (parts.length != 3) {
+ throw Exception('invalid access token');
+ }
+ final payload = decodeBase64(parts[1]);
+ return json.decode(payload);
+ }
+}
diff --git a/lib/features/auth/model/user_model.dart b/lib/features/auth/model/user_model.dart
new file mode 100644
index 0000000..fd68fb4
--- /dev/null
+++ b/lib/features/auth/model/user_model.dart
@@ -0,0 +1,84 @@
+import 'dart:convert';
+
+import 'package:flutter/foundation.dart';
+import 'package:syncrow_app/features/auth/model/token.dart';
+
+class UserModel {
+ static String userUuidKey = 'userUuid';
+ final String? uuid;
+ final String? email;
+ final String? firstName;
+ final String? lastName;
+ final Uint8List? profilePicture;
+ final String? phoneNumber;
+ final bool? isEmailVerified;
+ final String? regionName;
+ final String? timeZone;
+ final bool? isAgreementAccepted;
+
+ UserModel({
+ required this.uuid,
+ required this.email,
+ required this.firstName,
+ required this.lastName,
+ required this.profilePicture,
+ required this.phoneNumber,
+ required this.isEmailVerified,
+ required this.isAgreementAccepted,
+ required this.regionName, // Add this line
+ required this.timeZone, // Add this line
+
+ });
+
+ factory UserModel.fromJson(Map json) {
+ return UserModel(
+ uuid: json['uuid'],
+ email: json['email'],
+ firstName: json['firstName'],
+ lastName: json['lastName'],
+ profilePicture: UserModel.decodeBase64Image(json['profilePicture']),
+ phoneNumber: json['phoneNumber'],
+ isEmailVerified: json['isEmailVerified'],
+ isAgreementAccepted: json['isAgreementAccepted'],
+ regionName: json['region']?['regionName'], // Extract regionName
+ timeZone: json['timeZone']?['timeZoneOffset'], // Extract regionName
+ );
+ }
+ //uuid to json
+ //from token
+ factory UserModel.fromToken(Token token) {
+ Map tempJson = Token.decodeToken(token.accessToken);
+ return UserModel(
+ uuid: tempJson['uuid'].toString(),
+ email: tempJson['email'],
+ lastName: tempJson['lastName'],
+ firstName:tempJson['firstName'] ,
+ profilePicture: UserModel.decodeBase64Image(tempJson['profilePicture']),
+ phoneNumber: null,
+ isEmailVerified: null,
+ isAgreementAccepted: null,
+ regionName: tempJson['region']?['regionName'],
+ timeZone: tempJson['timezone']?['timeZoneOffset'],
+ );
+ }
+
+ static Uint8List? decodeBase64Image(String? base64String) {
+ if (base64String != null) {
+ return base64.decode(base64String);
+ }
+ return null;
+ }
+
+ Map toJson() {
+ return {
+ 'id': uuid,
+ 'email': email,
+ 'lastName': lastName,
+ 'firstName': firstName,
+ 'photoUrl': profilePicture,
+ 'phoneNumber': phoneNumber,
+ 'isEmailVerified': isEmailVerified,
+ 'isAgreementAccepted': isAgreementAccepted,
+ };
+ }
+}
diff --git a/lib/features/auth/model/verify_code.dart b/lib/features/auth/model/verify_code.dart
new file mode 100644
index 0000000..da29c25
--- /dev/null
+++ b/lib/features/auth/model/verify_code.dart
@@ -0,0 +1,27 @@
+class VerifyPassCode {
+ static const String verificationPhone = 'phone';
+ static const String verificationPassCode = 'passCode';
+ static const String verificationAgent = 'agent';
+ static const String verificationDeviceId = 'deviceId';
+
+ final String phone;
+ final String passCode;
+ final String agent;
+ final String deviceId;
+
+ VerifyPassCode(
+ {required this.phone, required this.passCode, required this.agent, required this.deviceId});
+
+ factory VerifyPassCode.fromJson(Map json) => VerifyPassCode(
+ phone: json[verificationPhone],
+ passCode: json[verificationPassCode],
+ agent: json[verificationAgent],
+ deviceId: json[verificationDeviceId]);
+
+ Map toJson() => {
+ verificationPhone: phone,
+ verificationPassCode: passCode,
+ verificationAgent: agent,
+ verificationDeviceId: deviceId,
+ };
+}
diff --git a/lib/features/auth/view/check_email_page.dart b/lib/features/auth/view/check_email_page.dart
new file mode 100644
index 0000000..63fc691
--- /dev/null
+++ b/lib/features/auth/view/check_email_page.dart
@@ -0,0 +1,202 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
+import 'package:syncrow_app/features/auth/view/otp_view.dart';
+import 'package:syncrow_app/features/shared_widgets/default_button.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
+import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
+
+class checkEmailPage extends StatelessWidget {
+ const checkEmailPage({super.key});
+ @override
+ Widget build(BuildContext context) {
+ final formKey = AuthCubit.get(context).checkEmailFormKey;
+
+ SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
+ statusBarBrightness: Brightness.light, statusBarIconBrightness: Brightness.light));
+ return BlocConsumer(
+ listener: (context, state) {
+ if (state is AuthError) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(
+ content: Text(state.message),
+ ),
+ );
+ } else if (state is AuthSignUpSuccess) {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const OtpView(
+ isForgetPage: true,
+ ),
+ ));
+ }
+ },
+ builder: (context, state) {
+ return Scaffold(
+ body: Stack(
+ children: [
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(
+ Assets.assetsImagesBackground,
+ ),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(Assets.assetsImagesVector),
+ fit: BoxFit.cover,
+ opacity: 0.9,
+ ),
+ ),
+ ),
+ SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ right: Constants.defaultPadding,
+ left: Constants.defaultPadding,
+ top: Constants.defaultPadding,
+ ),
+ child: Form(
+ key: formKey,
+ child: SingleChildScrollView(
+ child: Center(
+ child: Column(
+ children: [
+ Center(
+ child: SvgPicture.asset(
+ Assets.assetsImagesLogo,
+ width: 160,
+ ),
+ ),
+ Center(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(
+ height: MediaQuery.sizeOf(context).height / 5.5,
+ ),
+ TitleMedium(
+ text: 'Forgot password?',
+ style: context.titleMedium.copyWith(
+ fontWeight: FontsManager.extraBold,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ const BodyMedium(
+ text: "Enter email address",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ enableSuggestions: false,
+ autofillHints: const [AutofillHints.email],
+ validator: AuthCubit.get(context).emailAddressValidator,
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ onChanged: (value) {
+ AuthCubit.get(context).email = value;
+ },
+ decoration: defaultInputDecoration(context,
+ hint: "Example@email.com"),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Expanded(
+ child: DefaultButton(
+ isDone: state is AuthLoginSuccess,
+ isLoading: state is AuthLoading,
+ customButtonStyle: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ Colors.black.withOpacity(.25),
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ Colors.white,
+ ),
+ ),
+ child: const Text(
+ 'Send Code',
+ ),
+ onPressed: () {
+ AuthCubit.get(context).showValidationMessage = true;
+ if (formKey.currentState!.validate()) {
+ if ((state is! AuthLoading)) {
+ AuthCubit.get(context).sendOtp();
+ FocusScope.of(context).unfocus();
+ }
+ }
+ },
+ ),
+ ),
+ ],
+ ),
+ Padding(
+ padding: EdgeInsets.only(
+ top: MediaQuery.sizeOf(context).height / 5.5),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ BodyLarge(
+ text: "Do you have an account? ",
+ style:
+ context.displaySmall.copyWith(color: Colors.white),
+ ),
+ TextButton(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ child: BodyLarge(
+ text: "Sign in",
+ style: context.displaySmall.copyWith(
+ color: Colors.black,
+ fontWeight: FontsManager.bold,
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ )),
+ )
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/view/create_new_password.dart b/lib/features/auth/view/create_new_password.dart
new file mode 100644
index 0000000..4452154
--- /dev/null
+++ b/lib/features/auth/view/create_new_password.dart
@@ -0,0 +1,186 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
+import 'package:syncrow_app/features/shared_widgets/default_button.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
+import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
+
+class CreateNewPasswordPage extends StatelessWidget {
+ const CreateNewPasswordPage({super.key,});
+
+ @override
+ Widget build(BuildContext context) {
+ final formKey = AuthCubit.get(context).createNewPasswordKey;
+
+ return BlocConsumer(
+ listener: (context, state) {
+ if (state is AuthForgetPassSuccess) {
+ Navigator.of(context).pop();
+ }
+ },
+ builder: (context, state) {
+ return Scaffold(
+ body: Stack(
+ children: [
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ padding: const EdgeInsets.symmetric(vertical: 24),
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(
+ Assets.assetsImagesBackground,
+ ),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(Assets.assetsImagesVector),
+ fit: BoxFit.cover,
+ opacity: 0.9,
+ ),
+ ),
+ ),
+ SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ right: Constants.defaultPadding,
+ left: Constants.defaultPadding,
+ top: Constants.defaultPadding,
+ ),
+ child: SingleChildScrollView(
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Center(
+ child: SvgPicture.asset(
+ Assets.assetsImagesLogo,
+ width: 160,
+ ),
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ TitleMedium(
+ text: 'Create new password',
+ style: context.titleMedium.copyWith(
+ fontWeight: FontsManager.extraBold,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ Form(
+ key: formKey,
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(height: 16),
+ const BodyMedium(
+ text: "Password",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ autofillHints: const [AutofillHints.password],
+ validator: AuthCubit.get(context).passwordValidator,
+ onChanged: (value) {
+ AuthCubit.get(context).newPassword = value;
+ },
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ obscureText: !AuthCubit.get(context).isPasswordVisible,
+ decoration: defaultInputDecoration(context,
+ hint: "At least 8 characters"),
+ ),
+ const SizedBox(height: 16),
+ const BodyMedium(
+ text: "Re-enter Password",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ autovalidateMode: AutovalidateMode.disabled,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ enableSuggestions: false,
+ autofillHints: const [AutofillHints.password],
+ onChanged: (value) {},
+ validator: AuthCubit.get(context).reEnterPasswordCheckForgetPass,
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ obscureText: !AuthCubit.get(context).isPasswordVisible,
+ decoration: defaultInputDecoration(context,
+ hint: "At least 8 characters"),
+ ),
+ const SizedBox(height: 40),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Expanded(
+ child: DefaultButton(
+ isDone: state is AuthLoginSuccess,
+ isLoading: state is AuthLoading,
+ customButtonStyle: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ Colors.black.withOpacity(.25),
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ Colors.white,
+ ),
+ ),
+ child: const Text(
+ 'Confirm',
+ ),
+ onPressed: () {
+ AuthCubit.get(context).showValidationMessage = true;
+ if (formKey.currentState!.validate()) {
+ if ((state is! AuthForgetPassLoading)) {
+ AuthCubit.get(context).sendToForgetPassword(password:AuthCubit.get(context).newPassword);
+ FocusScope.of(context).unfocus();
+ }
+ }
+ },
+ ),
+ ),
+ ],
+ )
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/view/login_view.dart b/lib/features/auth/view/login_view.dart
new file mode 100644
index 0000000..05e3b92
--- /dev/null
+++ b/lib/features/auth/view/login_view.dart
@@ -0,0 +1,114 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
+import 'package:syncrow_app/features/auth/view/widgets/dont_have_an_account.dart';
+import 'package:syncrow_app/features/auth/view/widgets/login_divider.dart';
+import 'package:syncrow_app/features/auth/view/widgets/login_form.dart';
+import 'package:syncrow_app/features/auth/view/widgets/login_with_google_facebook.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/navigation/routing_constants.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
+
+class LoginView extends StatelessWidget {
+ const LoginView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
+ statusBarBrightness: Brightness.light, statusBarIconBrightness: Brightness.light));
+ return BlocConsumer(
+ listener: (context, state) {
+ if (state is AuthError) {
+ // ScaffoldMessenger.of(context).showSnackBar(
+ // SnackBar(
+ // content: Text(state.message),
+ // ),
+ // );
+ }
+ else if (state is AuthLoginSuccess) {
+ Navigator.popAndPushNamed(context, Routes.homeRoute);
+ }
+ },
+ builder: (context, state) {
+ return Scaffold(
+ body: Stack(
+ children: [
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(
+ Assets.assetsImagesBackground,
+ ),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(Assets.assetsImagesVector),
+ fit: BoxFit.cover,
+ opacity: 0.9,
+ ),
+ ),
+ ),
+ SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ right: Constants.defaultPadding,
+ left: Constants.defaultPadding,
+ top: Constants.defaultPadding,
+ ),
+ child: SingleChildScrollView(
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Center(
+ child: SvgPicture.asset(
+ Assets.assetsImagesLogo,
+ width: 160,
+ ),
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ TitleMedium(
+ text: 'Login',
+ style: context.titleMedium.copyWith(
+ fontWeight: FontsManager.extraBold,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ const LoginForm(),
+ const LoginDivider(),
+ const LoginWithGoogleFacebook(),
+ const DontHaveAnAccount(),
+ ],
+ ),
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/view/otp_view.dart b/lib/features/auth/view/otp_view.dart
new file mode 100644
index 0000000..e8ca1da
--- /dev/null
+++ b/lib/features/auth/view/otp_view.dart
@@ -0,0 +1,366 @@
+import 'dart:async';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:pin_code_fields/pin_code_fields.dart';
+import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
+import 'package:syncrow_app/features/auth/view/create_new_password.dart';
+import 'package:syncrow_app/features/shared_widgets/default_button.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/navigation/routing_constants.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+import 'package:syncrow_app/utils/helpers/life_cycle_event_handler.dart';
+import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
+
+class OtpView extends StatefulWidget {
+ final bool isForgetPage;
+ const OtpView({super.key, this.isForgetPage = false});
+
+ @override
+ State createState() => _OtpViewState();
+}
+
+class _OtpViewState extends State {
+ bool timerCanceled = false;
+ Timer? countdownTimer;
+ Duration myDuration = const Duration();
+ late LifecycleEventHandler _lifecycleEventHandler;
+ String otpCode = '';
+ int? remainingSec = 30;
+
+ @override
+ void initState() {
+ super.initState();
+ bool timerStarted = false;
+ _lifecycleEventHandler = LifecycleEventHandler(
+ resumeCallBack: () async {
+ SharedPreferencesHelper.saveBoolToSP('timeStampSaved', false);
+ String timeStampInBackground = await SharedPreferencesHelper.readStringFromSP('timeStamp');
+ int savedCounter = await SharedPreferencesHelper.readIntFromSP('savedCounter');
+ DateTime currentTime = DateTime.now();
+ int differenceInSeconds = timeStampInBackground.isNotEmpty
+ ? currentTime.difference(DateTime.parse(timeStampInBackground)).inSeconds
+ : 0;
+ remainingSec = differenceInSeconds > savedCounter ? 0 : savedCounter - differenceInSeconds;
+ timerStarted = true;
+ startTimer(remainingSec ?? 0);
+ return;
+ },
+ suspendingCallBack: () async {
+ handleTimerOnBackground();
+ },
+ onPauseCallBack: () async {
+ handleTimerOnBackground();
+ },
+ inactiveCallBack: () async {
+ handleTimerOnBackground();
+ },
+ );
+ WidgetsBinding.instance.addObserver(_lifecycleEventHandler);
+ if (!timerStarted) {
+ timerStarted = false;
+ startTimer(remainingSec ?? 0);
+ }
+ }
+
+ @override
+ void dispose() {
+ WidgetsBinding.instance.removeObserver(_lifecycleEventHandler);
+ super.dispose();
+ }
+
+ handleTimerOnBackground() async {
+ bool timeStampSaved = await SharedPreferencesHelper.readBoolFromSP('timeStampSaved') ?? false;
+ if (!timeStampSaved) {
+ final dateInString = DateTime.now().toString();
+ SharedPreferencesHelper.saveIntToSP('savedCounter', remainingSec ?? 0);
+ SharedPreferencesHelper.saveStringToSP('timeStamp', dateInString);
+ SharedPreferencesHelper.saveBoolToSP('timeStampSaved', true);
+ }
+ }
+
+ void startTimer(int sec) {
+ timerCanceled = false;
+ if (countdownTimer != null) {
+ countdownTimer!.cancel();
+ countdownTimer = null;
+ }
+
+ myDuration = Duration(seconds: sec);
+ int seconds = sec;
+ countdownTimer = Timer.periodic(const Duration(seconds: 1), (values) {
+ seconds = seconds - 1;
+ remainingSec = seconds;
+
+ if (mounted) {
+ if (seconds < 0) {
+ setState(() {
+ countdownTimer!.cancel();
+ timerCanceled = true;
+ WidgetsBinding.instance.removeObserver(_lifecycleEventHandler);
+ });
+ } else {
+ setState(() {
+ myDuration = Duration(seconds: remainingSec ?? seconds);
+ });
+ }
+ }
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ String maskedEmail = AuthCubit.get(context).maskEmail(AuthCubit.get(context).email);
+ return BlocConsumer(
+ listener: (context, state) {
+ if (state is AuthOtpSuccess) {
+ Navigator.of(context).pop();
+ Navigator.of(context).pop();
+ widget.isForgetPage
+ ? Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => const CreateNewPasswordPage(),
+ ))
+ : Navigator.popAndPushNamed(context, Routes.homeRoute);
+ }
+ if (state is ResendOtpSuccess) {
+ startTimer(30);
+ }
+ },
+ builder: (context, state) {
+ return Scaffold(
+ body: Stack(
+ children: [
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(
+ Assets.assetsImagesBackground,
+ ),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(Assets.assetsImagesVector),
+ fit: BoxFit.cover,
+ opacity: 0.9,
+ ),
+ ),
+ ),
+ SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ right: Constants.defaultPadding,
+ left: Constants.defaultPadding,
+ top: Constants.defaultPadding,
+ ),
+ child: SingleChildScrollView(
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Center(
+ child: SvgPicture.asset(
+ Assets.assetsImagesLogo,
+ width: 160,
+ ),
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ TitleMedium(
+ text: 'Verification Code',
+ style: context.titleMedium.copyWith(
+ fontWeight: FontsManager.extraBold,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ GestureDetector(
+ onTap: () {
+ Navigator.of(context).pop();
+ },
+ child: RichText(
+ text: TextSpan(
+ text: 'We have sent the verification code to',
+ style: Theme.of(context).textTheme.titleSmall!.copyWith(
+ color: Colors.white,
+ fontWeight: FontsManager.regular,
+ fontSize: 14,
+ ),
+ children: [
+ TextSpan(
+ text: ' $maskedEmail',
+ style: Theme.of(context).textTheme.titleSmall!.copyWith(
+ color: Colors.black,
+ fontWeight: FontsManager.bold,
+ fontSize: 14,
+ ),
+ ),
+ TextSpan(
+ text: ' change email?',
+ style: Theme.of(context).textTheme.titleSmall!.copyWith(
+ color: const Color(0xFF87C7FF),
+ fontWeight: FontsManager.regular,
+ fontSize: 14,
+ ),
+ ),
+ ]),
+ ),
+ ),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const SizedBox(
+ height: 40,
+ ),
+ PinCodeTextField(
+ key: const Key('pin_code_text_field'),
+ appContext: context,
+ length: 6,
+ obscuringCharacter: '-',
+ cursorHeight: 25,
+ keyboardType: TextInputType.number,
+ autoFocus: true,
+ backgroundColor: Colors.transparent,
+ animationDuration: const Duration(milliseconds: 30),
+ beforeTextPaste: (text) {
+ // Allow pasting only if all characters are numeric
+ return int.tryParse(text!) != null;
+ },
+ textStyle: Theme.of(context)
+ .textTheme
+ .headlineMedium!
+ .copyWith(color: Colors.white),
+ hintStyle: Theme.of(context)
+ .textTheme
+ .headlineMedium!
+ .copyWith(color: Colors.white),
+ enablePinAutofill: true,
+ pinTheme: PinTheme(
+ borderRadius: BorderRadius.circular(8),
+ inactiveBorderWidth: 1,
+ disabledBorderWidth: 1,
+ selectedBorderWidth: 1,
+ activeBorderWidth: 1,
+ errorBorderWidth: 1,
+ borderWidth: 1,
+ errorBorderColor: Colors.red,
+ activeColor: state is AuthLoginError ? Colors.red : Colors.white,
+ inactiveColor:
+ state is AuthLoginError ? Colors.red : Colors.white,
+ activeFillColor:
+ state is AuthLoginError ? Colors.red : Colors.white,
+ inactiveFillColor:
+ state is AuthLoginError ? Colors.red : Colors.white,
+ selectedFillColor:
+ state is AuthLoginError ? Colors.red : Colors.white,
+ disabledColor: Colors.white,
+ fieldHeight: 56,
+ fieldWidth: MediaQuery.sizeOf(context).width > 340 ? 40 : 20,
+ // fieldWidth: 40,
+ selectedColor: Colors.white,
+ shape: PinCodeFieldShape.box,
+ ),
+ onChanged: (value) {
+ AuthCubit.get(context).setOtpCode(value);
+ },
+ onCompleted: (value) {},
+ onSubmitted: (value) {
+ // AuthCubit.get(context).setOtpCode(value);
+ },
+ ),
+ const SizedBox(height: 40),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Expanded(
+ child: DefaultButton(
+ isDone: state is AuthLoginSuccess,
+ isLoading: state is AuthLoading,
+ customButtonStyle: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ Colors.black.withOpacity(.25),
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ Colors.white,
+ ),
+ ),
+ child: const Text(
+ 'Verify',
+ ),
+ onPressed: () {
+ if ((state is! AuthLoading)) {
+ AuthCubit.get(context).verifyOtp(widget.isForgetPage);
+ FocusScope.of(context).unfocus();
+ }
+ },
+ ),
+ ),
+ const SizedBox(
+ width: 4,
+ ),
+ Expanded(
+ child: DefaultButton(
+ isDone: state is AuthLoginSuccess,
+ isLoading: state is AuthLoading,
+ customButtonStyle: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ Colors.black.withOpacity(.25),
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ Colors.white,
+ ),
+ ),
+ child: Text(
+ timerCanceled
+ ? 'Resend'
+ : myDuration.inSeconds
+ .remainder(60)
+ .toString()
+ .padLeft(2, '0'),
+ ),
+ onPressed: () async {
+ if (!timerCanceled) {
+ return;
+ }
+ if ((state is! AuthLoading)) {
+ await AuthCubit.get(context).reSendOtp();
+ FocusScope.of(context).unfocus();
+ }
+ },
+ ),
+ ),
+ ],
+ )
+ ],
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/view/sign_up_view.dart b/lib/features/auth/view/sign_up_view.dart
new file mode 100644
index 0000000..e2ba925
--- /dev/null
+++ b/lib/features/auth/view/sign_up_view.dart
@@ -0,0 +1,235 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
+import 'package:syncrow_app/features/shared_widgets/default_button.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/navigation/routing_constants.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
+import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
+
+class SignUpView extends StatelessWidget {
+ const SignUpView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final formKey = AuthCubit.get(context).signUpFormKey;
+ return BlocConsumer(
+ listener: (context, state) {
+ if (state is AuthSignUpSuccess) {
+ Navigator.pushNamed(context, Routes.otpRoute);
+ // Navigator.popAndPushNamed(context, Routes.otpRoute);
+ }
+ },
+ builder: (context, state) {
+ return Scaffold(
+ body: Stack(
+ children: [
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ padding: const EdgeInsets.symmetric(vertical: 24),
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(
+ Assets.assetsImagesBackground,
+ ),
+ fit: BoxFit.cover,
+ ),
+ ),
+ ),
+ Container(
+ width: MediaQuery.sizeOf(context).width,
+ height: MediaQuery.sizeOf(context).height,
+ decoration: const BoxDecoration(
+ image: DecorationImage(
+ image: AssetImage(Assets.assetsImagesVector),
+ fit: BoxFit.cover,
+ opacity: 0.9,
+ ),
+ ),
+ ),
+ SafeArea(
+ child: Padding(
+ padding: const EdgeInsets.only(
+ right: Constants.defaultPadding,
+ left: Constants.defaultPadding,
+ top: Constants.defaultPadding,
+ ),
+ child: SingleChildScrollView(
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Center(
+ child: SvgPicture.asset(
+ Assets.assetsImagesLogo,
+ width: 160,
+ ),
+ ),
+ const SizedBox(
+ height: 40,
+ ),
+ TitleMedium(
+ text: 'Create new account',
+ style: context.titleMedium.copyWith(
+ fontWeight: FontsManager.extraBold,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(
+ height: 20,
+ ),
+ Form(
+ key: formKey,
+ // autovalidateMode: AutovalidateMode.disabled,
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const BodyMedium(
+ text: "Full Name",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ // autovalidateMode: AutovalidateMode.disabled,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.name,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ autofillHints: const [AutofillHints.name],
+ // controller: AuthCubit.get(context).fullNameController,
+ validator: (value) =>
+ AuthCubit.get(context).fullNameValidator(value),
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ onChanged: (value) {
+ AuthCubit.get(context).fullName = value;
+ },
+ onTap: () {},
+ decoration: defaultInputDecoration(context, hint: "Full Name"),
+ ),
+ const SizedBox(height: 16),
+ const BodyMedium(
+ text: "Email",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ // autovalidateMode: AutovalidateMode.disabled,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ enableSuggestions: false,
+ autofillHints: const [AutofillHints.email],
+ validator: AuthCubit.get(context).emailAddressValidator,
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ onChanged: (value) {
+ AuthCubit.get(context).email = value;
+ },
+ decoration:
+ defaultInputDecoration(context, hint: "Example@email.com"),
+ ),
+ const SizedBox(height: 16),
+ const BodyMedium(
+ text: "Password",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ // autovalidateMode: AutovalidateMode.disabled,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ autofillHints: const [AutofillHints.password],
+ validator: AuthCubit.get(context).passwordValidator,
+ onChanged: (value) {
+ AuthCubit.get(context).signUpPassword = value;
+ },
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ obscureText: !AuthCubit.get(context).isPasswordVisible,
+ decoration: defaultInputDecoration(context,
+ hint: "At least 8 characters"),
+ ),
+ const SizedBox(height: 16),
+ const BodyMedium(
+ text: "Re-enter Password",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ autovalidateMode: AutovalidateMode.disabled,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ enableSuggestions: false,
+ autofillHints: const [AutofillHints.password],
+ onChanged: (value) {},
+ validator: AuthCubit.get(context).reEnterPasswordCheck,
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ obscureText: !AuthCubit.get(context).isPasswordVisible,
+ decoration: defaultInputDecoration(context,
+ hint: "At least 8 characters"),
+ ),
+ const SizedBox(height: 40),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Expanded(
+ child: DefaultButton(
+ isDone: state is AuthLoginSuccess,
+ isLoading: state is AuthLoading,
+ customButtonStyle: ButtonStyle(
+ backgroundColor: MaterialStateProperty.all(
+ Colors.black.withOpacity(.25),
+ ),
+ foregroundColor: MaterialStateProperty.all(
+ Colors.white,
+ ),
+ ),
+ child: const Text(
+ 'Sign up',
+ ),
+ onPressed: () {
+ AuthCubit.get(context).showValidationMessage = true;
+ if (formKey.currentState!.validate()) {
+ if ((state is! AuthLoading)) {
+ AuthCubit.get(context).signUp();
+ FocusScope.of(context).unfocus();
+ }
+ }
+ },
+ ),
+ ),
+ ],
+ )
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ )
+ ],
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/view/widgets/dont_have_an_account.dart b/lib/features/auth/view/widgets/dont_have_an_account.dart
new file mode 100644
index 0000000..4ad03db
--- /dev/null
+++ b/lib/features/auth/view/widgets/dont_have_an_account.dart
@@ -0,0 +1,39 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
+import 'package:syncrow_app/navigation/routing_constants.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
+
+class DontHaveAnAccount extends StatelessWidget {
+ const DontHaveAnAccount({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.only(top: 30),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ BodyLarge(
+ text: "Don't have an account?",
+ style: context.displaySmall.copyWith(color: Colors.white),
+ ),
+ TextButton(
+ onPressed: () {
+ Navigator.pushNamed(context, Routes.authSignUp);
+ },
+ child: BodyLarge(
+ text: "Sign Up",
+ style: context.displaySmall.copyWith(
+ color: Colors.black,
+ fontWeight: FontsManager.bold,
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/auth/view/widgets/forget_password.dart b/lib/features/auth/view/widgets/forget_password.dart
new file mode 100644
index 0000000..0b0f31e
--- /dev/null
+++ b/lib/features/auth/view/widgets/forget_password.dart
@@ -0,0 +1,30 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/auth/view/check_email_page.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+
+class ForgetPassword extends StatelessWidget {
+ const ForgetPassword({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ children: [
+ const Spacer(),
+ TextButton(
+ onPressed: () {
+ Navigator.push(context, MaterialPageRoute(builder: (context) => const checkEmailPage(),));
+ },
+ child: BodyMedium(
+ text: "Forgot Password?",
+ style: context.bodyMedium.copyWith(
+ color: Colors.white,
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/features/auth/view/widgets/login_divider.dart b/lib/features/auth/view/widgets/login_divider.dart
new file mode 100644
index 0000000..7193586
--- /dev/null
+++ b/lib/features/auth/view/widgets/login_divider.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+
+class LoginDivider extends StatelessWidget {
+ const LoginDivider({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return const Padding(
+ padding: EdgeInsets.symmetric(vertical: 20),
+ child: Row(
+ children: [
+ Expanded(
+ child: Divider(
+ color: Colors.white,
+ ),
+ ),
+ Padding(
+ padding: EdgeInsets.symmetric(horizontal: 10),
+ child: BodyMedium(
+ text: "or Sign in with",
+ style: TextStyle(
+ color: Colors.white,
+ ),
+ ),
+ ),
+ Expanded(
+ child: Divider(
+ color: Colors.white,
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/auth/view/widgets/login_form.dart b/lib/features/auth/view/widgets/login_form.dart
new file mode 100644
index 0000000..6493800
--- /dev/null
+++ b/lib/features/auth/view/widgets/login_form.dart
@@ -0,0 +1,118 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
+import 'package:syncrow_app/features/auth/view/widgets/forget_password.dart';
+import 'package:syncrow_app/features/shared_widgets/default_button.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/utils/resource_manager/styles_manager.dart';
+
+class LoginForm extends StatelessWidget {
+ const LoginForm({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ var pressed = false;
+ return BlocBuilder(
+ builder: (context, state) {
+ final formKey = AuthCubit.get(context).loginFormKey;
+ return Form(
+ key: formKey,
+ autovalidateMode: AutovalidateMode.onUserInteraction,
+ child: SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const BodyMedium(
+ text: "Email",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ autovalidateMode: AutovalidateMode.disabled,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ autofillHints: const [AutofillHints.email],
+ controller: AuthCubit.get(context).emailController,
+ validator: (value) {
+ if (state is AuthTokenError && !pressed) {
+ return null;
+ }
+ return AuthCubit.get(context).emailAddressValidator(value);
+ },
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ onChanged: (value) {},
+ decoration: defaultInputDecoration(context, hint: "Example@email.com"),
+ ),
+ const SizedBox(height: 10),
+ const BodyMedium(
+ text: "Password",
+ fontColor: Colors.white,
+ ),
+ TextFormField(
+ autovalidateMode: AutovalidateMode.disabled,
+ textInputAction: TextInputAction.done,
+ keyboardType: TextInputType.text,
+ scrollPadding: EdgeInsets.zero,
+ autocorrect: false,
+ autofillHints: const [AutofillHints.password],
+ controller: AuthCubit.get(context).passwordController,
+ validator: (value) {
+ if (state is AuthTokenError && !pressed) {
+ return null;
+ }
+ // return AuthCubit.get(context).passwordValidator(value);
+ },
+ onTapOutside: (event) {
+ FocusScope.of(context).unfocus();
+ },
+ obscureText: !AuthCubit.get(context).isPasswordVisible,
+ decoration: defaultInputDecoration(context, hint: "At least 8 characters"),
+ ),
+ const SizedBox(height: 10),
+ // const LoginUserAgreement(),
+ const ForgetPassword(),
+ const SizedBox(height: 10),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Expanded(
+ child: DefaultButton(
+ isDone: state is AuthLoginSuccess,
+ isLoading: state is AuthLoading,
+ customButtonStyle: ButtonStyle(
+ backgroundColor: WidgetStateProperty.all(
+ Colors.black.withOpacity(.25),
+ ),
+ foregroundColor: WidgetStateProperty.all(
+ Colors.white,
+ ),
+ ),
+ child: const Text(
+ 'Login',
+ ),
+ onPressed: () {
+ pressed = true;
+ if (formKey.currentState!.validate()) {
+ if ((state is! AuthLoading)) {
+ AuthCubit.get(context).login();
+ FocusScope.of(context).unfocus();
+ }
+ }
+ },
+ ),
+ ),
+ ],
+ )
+ ],
+ ),
+ ),
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/view/widgets/login_user_agreement.dart b/lib/features/auth/view/widgets/login_user_agreement.dart
new file mode 100644
index 0000000..a4e7ee8
--- /dev/null
+++ b/lib/features/auth/view/widgets/login_user_agreement.dart
@@ -0,0 +1,74 @@
+import 'package:flutter/gestures.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart';
+import 'package:syncrow_app/navigation/routing_constants.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+
+class LoginUserAgreement extends StatelessWidget {
+ const LoginUserAgreement({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return BlocBuilder(
+ builder: (context, state) {
+ return Row(
+ children: [
+ Checkbox(
+ value: AuthCubit.get(context).agreeToTerms,
+ onChanged: (value) => AuthCubit.get(context).changeAgreeToTerms(),
+ ),
+ Expanded(
+ child: RichText(
+ softWrap: true,
+ maxLines: 2,
+ text: TextSpan(
+ text: 'I Agree to the ',
+ style: context.bodySmall,
+ children: [
+ TextSpan(
+ text: 'Privacy Policy',
+ style: context.bodySmall.copyWith(
+ color: Colors.blue,
+ decoration: TextDecoration.underline,
+ decorationColor: Colors.blue,
+ ),
+ recognizer: TapGestureRecognizer()
+ ..onTap = () {
+ Navigator.pushNamed(context, Routes.policyRoute);
+ },
+ ),
+ TextSpan(
+ text: ' and ',
+ style: context.bodySmall,
+ ),
+ TextSpan(
+ text: 'User Agreement',
+ recognizer: TapGestureRecognizer()
+ ..onTap = () {
+ Navigator.pushNamed(context, Routes.termsRoute);
+ },
+ style: const TextStyle(
+ color: Colors.blue,
+ decoration: TextDecoration.underline,
+ decorationColor: Colors.blue,
+ ),
+ ),
+ const TextSpan(
+ text: '.',
+ style: TextStyle(
+ color: Colors.black,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ );
+ }
+}
diff --git a/lib/features/auth/view/widgets/login_with_google_facebook.dart b/lib/features/auth/view/widgets/login_with_google_facebook.dart
new file mode 100644
index 0000000..b7e2394
--- /dev/null
+++ b/lib/features/auth/view/widgets/login_with_google_facebook.dart
@@ -0,0 +1,60 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/shared_widgets/default_container.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/utils/context_extension.dart';
+
+class LoginWithGoogleFacebook extends StatelessWidget {
+ const LoginWithGoogleFacebook({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Expanded(
+ child: DefaultContainer(
+ child: SizedBox.square(
+ dimension: 24,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ SvgPicture.asset(Assets.assetsIconsGoogle),
+ const SizedBox(width: 10),
+ BodyMedium(
+ text: "Google",
+ style: context.bodyMedium.copyWith(
+ color: Colors.black,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ const SizedBox(width: 10),
+ Expanded(
+ child: DefaultContainer(
+ child: SizedBox.square(
+ dimension: 24,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ SvgPicture.asset(Assets.assetsIconsFacebook),
+ const SizedBox(width: 10),
+ BodyMedium(
+ text: "Facebook",
+ style: context.bodyMedium.copyWith(color: Colors.black),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/features/dashboard/bloc/dashboard_cubit.dart b/lib/features/dashboard/bloc/dashboard_cubit.dart
new file mode 100644
index 0000000..da13e50
--- /dev/null
+++ b/lib/features/dashboard/bloc/dashboard_cubit.dart
@@ -0,0 +1,9 @@
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+part 'dashboard_state.dart';
+
+class DashboardCubit extends Cubit {
+ DashboardCubit() : super(DashboardInitial());
+
+ static DashboardCubit of(context) => BlocProvider.of(context);
+}
diff --git a/lib/features/dashboard/bloc/dashboard_state.dart b/lib/features/dashboard/bloc/dashboard_state.dart
new file mode 100644
index 0000000..12e988c
--- /dev/null
+++ b/lib/features/dashboard/bloc/dashboard_state.dart
@@ -0,0 +1,5 @@
+part of 'dashboard_cubit.dart';
+
+abstract class DashboardState {}
+
+class DashboardInitial extends DashboardState {}
diff --git a/lib/features/dashboard/view/dashboard_view.dart b/lib/features/dashboard/view/dashboard_view.dart
new file mode 100644
index 0000000..601552b
--- /dev/null
+++ b/lib/features/dashboard/view/dashboard_view.dart
@@ -0,0 +1,52 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/carbon_emission.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/consumption.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/live_monitor_tab.dart';
+import 'package:syncrow_app/features/shared_widgets/create_unit.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/title_medium.dart';
+import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
+
+import 'widgets/energy_usage.dart';
+
+class DashboardView extends StatelessWidget {
+ const DashboardView({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ return HomeCubit.getInstance().spaces?.isEmpty ?? true
+ ? const CreateUnitWidget()
+ : SingleChildScrollView(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.stretch,
+ children: [
+ const TitleMedium(
+ text: StringsManager.dashboard,
+ style: TextStyle(
+ fontSize: 32,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ const LiveMonitorTab(),
+ const SizedBox(height: 10),
+ const EnergyUsage(),
+ Container(
+ padding: const EdgeInsets.only(top: 20),
+ constraints: const BoxConstraints(
+ minHeight: 220,
+ maxHeight: 240,
+ ),
+ child: const Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Consumption(),
+ SizedBox(height: 20),
+ CarbonEmission(),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/dashboard/view/widgets/carbon_emission.dart b/lib/features/dashboard/view/widgets/carbon_emission.dart
new file mode 100644
index 0000000..4823210
--- /dev/null
+++ b/lib/features/dashboard/view/widgets/carbon_emission.dart
@@ -0,0 +1,102 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/card_title.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
+import 'package:syncrow_app/features/shared_widgets/united_text.dart';
+import 'package:syncrow_app/generated/assets.dart';
+import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
+
+class CarbonEmission extends StatelessWidget {
+ const CarbonEmission({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.only(right: 20, left: 20, top: 10),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ constraints: const BoxConstraints(
+ minHeight: 80,
+ maxHeight: 100,
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const CardTitle(
+ title: "Carbon Emission",
+ ),
+ const SizedBox(height: 10),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox.square(
+ dimension: 30,
+ child: SvgPicture.asset(
+ Assets.assetsIconsCO2,
+ fit: BoxFit.contain,
+ ),
+ ),
+ const SizedBox(height: 5),
+ const Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ BodySmall(
+ text: StringsManager.emissions,
+ ),
+ UnitedText(
+ value: '120.00',
+ valueSize: 14,
+ unit: 'kg',
+ unitSize: 10,
+ ),
+ ],
+ ),
+ ],
+ ),
+ const SizedBox(width: 20),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox.square(
+ dimension: 30,
+ child: SvgPicture.asset(
+ Assets.assetsIconsSustainability,
+ fit: BoxFit.contain,
+ ),
+ ),
+ const SizedBox(width: 5),
+ const Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ BodySmall(
+ text: StringsManager.reductions,
+ ),
+ UnitedText(
+ value: '20.00',
+ valueSize: 14,
+ unit: 'kg',
+ unitSize: 10,
+ ),
+ ],
+ ),
+ ],
+ ),
+ ],
+ )
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/dashboard/view/widgets/card_title.dart b/lib/features/dashboard/view/widgets/card_title.dart
new file mode 100644
index 0000000..4e64e7c
--- /dev/null
+++ b/lib/features/dashboard/view/widgets/card_title.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
+
+class CardTitle extends StatelessWidget {
+ const CardTitle({
+ super.key,
+ required this.title,
+ });
+
+ final String title;
+
+ @override
+ Widget build(BuildContext context) {
+ return BodySmall(
+ text: title,
+ fontColor: Colors.grey,
+ fontSize: MediaQuery.sizeOf(context).height.ceil() > 680 ? 12 : 8,
+ );
+ }
+}
diff --git a/lib/features/dashboard/view/widgets/consumption.dart b/lib/features/dashboard/view/widgets/consumption.dart
new file mode 100644
index 0000000..0e39498
--- /dev/null
+++ b/lib/features/dashboard/view/widgets/consumption.dart
@@ -0,0 +1,72 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/card_title.dart';
+import 'package:syncrow_app/features/shared_widgets/united_text.dart';
+import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
+
+import 'package:syncrow_app/generated/assets.dart';
+
+class Consumption extends StatelessWidget {
+ const Consumption({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: const EdgeInsets.only(right: 20, left: 20, top: 10, bottom: 10),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(20),
+ ),
+ constraints: const BoxConstraints(
+ minHeight: 80,
+ maxHeight: 100,
+ ),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const CardTitle(
+ title: StringsManager.ACConsumption,
+ ),
+ const Spacer(),
+ Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ UnitedText(
+ value: "2",
+ valueSize: MediaQuery.sizeOf(context).height.ceil() > 680
+ ? 35
+ : 24,
+ valueWeight: FontWeight.normal,
+ unit: "Units",
+ ),
+ const SizedBox(width: 30),
+ UnitedText(
+ value: "${MediaQuery.sizeOf(context).height.ceil()}",
+ valueSize: MediaQuery.sizeOf(context).height.ceil() > 680
+ ? 35
+ : 24,
+ valueWeight: FontWeight.normal,
+ unit: "kWh",
+ ),
+ ],
+ ),
+ const Spacer(),
+ ],
+ ),
+ //TODO: Replace with actual pie chart
+ SizedBox.square(
+ dimension: 60,
+ child: Image.asset(
+ Assets.assetsImagesTestDash2,
+ fit: BoxFit.contain,
+ ),
+ )
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/dashboard/view/widgets/energy_usage.dart b/lib/features/dashboard/view/widgets/energy_usage.dart
new file mode 100644
index 0000000..9c4dd1a
--- /dev/null
+++ b/lib/features/dashboard/view/widgets/energy_usage.dart
@@ -0,0 +1,178 @@
+import 'package:fl_chart/fl_chart.dart';
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/energy_usage_header.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
+import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
+
+class EnergyUsage extends StatelessWidget {
+ const EnergyUsage({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return DecoratedBox(
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(15),
+ ),
+ child: Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ const EnergyUsageHeader(),
+ ConstrainedBox(
+ constraints: const BoxConstraints(
+ maxHeight: 150,
+ minHeight: 150,
+ ),
+ child: LineChart(
+ LineChartData(
+ gridData: FlGridData(
+ show: true,
+ drawHorizontalLine: true,
+ horizontalInterval: 2,
+ drawVerticalLine: false,
+ getDrawingHorizontalLine: (value) {
+ return FlLine(
+ color: Colors.grey.withOpacity(.5),
+ strokeWidth: 1,
+ );
+ },
+ ),
+ titlesData: FlTitlesData(
+ show: true,
+ rightTitles: AxisTitles(
+ sideTitles: SideTitles(
+ showTitles: true,
+ interval: 1,
+ getTitlesWidget: leftTitleWidgets,
+ reservedSize: 25,
+ ),
+ ),
+ topTitles: const AxisTitles(
+ sideTitles: SideTitles(showTitles: false),
+ ),
+ bottomTitles: AxisTitles(
+ sideTitles: SideTitles(
+ showTitles: true,
+ reservedSize: 30,
+ interval: 12,
+ getTitlesWidget: (value, meta) {
+ switch (value.toInt()) {
+ case 0:
+ return SideTitleWidget(
+ axisSide: meta.axisSide,
+ child: const BodySmall(text: '1'),
+ );
+
+ case 11:
+ return SideTitleWidget(
+ axisSide: meta.axisSide,
+ child: const BodySmall(text: '28'),
+ );
+ default:
+ return Container();
+ }
+ },
+ ),
+ ),
+ leftTitles: const AxisTitles(
+ sideTitles: SideTitles(showTitles: false),
+ ),
+ ),
+ minX: 0,
+ maxX: 11,
+ minY: 0,
+ maxY: 6,
+ lineBarsData: [
+ LineChartBarData(
+ spots: const [
+ FlSpot(0, 3),
+ FlSpot(2.6, 2),
+ FlSpot(4.9, 5),
+ FlSpot(6.8, 3.1),
+ FlSpot(8, 4),
+ FlSpot(9.5, 3),
+ FlSpot(11, 4),
+ ],
+ isCurved: true,
+ gradient: LinearGradient(
+ colors: [
+ ColorsManager.primaryColor,
+ ColorsManager.primaryColor.withOpacity(0.3),
+ ],
+ ),
+ barWidth: 5,
+ isStrokeCapRound: true,
+ dotData: const FlDotData(
+ show: false,
+ ),
+ belowBarData: BarAreaData(
+ show: true,
+ gradient: LinearGradient(
+ colors: [
+ ColorsManager.primaryColor.withOpacity(0.5),
+ ColorsManager.primaryColor.withOpacity(0.1),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ )
+ ],
+ ),
+ ),
+ );
+ }
+
+ Widget leftTitleWidgets(double value, TitleMeta meta) {
+ String text;
+ switch (value.toInt()) {
+ case 1:
+ text = '1K';
+ break;
+ case 3:
+ text = '3k';
+ break;
+ case 5:
+ text = '5k';
+ break;
+ default:
+ return Container();
+ }
+
+ return Center(child: BodySmall(text: text));
+ }
+
+ Widget bottomTitleWidgets(double value, TitleMeta meta) {
+ // const style = TextStyle(
+ // fontWeight: FontWeight.bold,
+ // fontSize: 16,
+ // );
+ // Widget text;
+ // switch (value.toInt()) {
+ // case 2:
+ // text = const Text('MAR', style: style);
+ // break;
+ // case 5:
+ // text = const Text('JUN', style: style);
+ // break;
+ // case 8:
+ // text = const Text('SEP', style: style);
+ // break;
+ // default:
+ // text = const Text('', style: style);
+ // break;
+ // }
+
+ return SideTitleWidget(
+ axisSide: meta.axisSide,
+ child: const BodySmall(text: 'Feb'),
+ );
+ }
+}
diff --git a/lib/features/dashboard/view/widgets/energy_usage_header.dart b/lib/features/dashboard/view/widgets/energy_usage_header.dart
new file mode 100644
index 0000000..ddd9a09
--- /dev/null
+++ b/lib/features/dashboard/view/widgets/energy_usage_header.dart
@@ -0,0 +1,74 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/card_title.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
+import 'package:syncrow_app/features/shared_widgets/united_text.dart';
+import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
+
+class EnergyUsageHeader extends StatelessWidget {
+ const EnergyUsageHeader({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return const Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ CardTitle(
+ title: StringsManager.energyUsage,
+ ),
+ Padding(
+ padding: EdgeInsets.only(top: 10),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ BodySmall(
+ text: StringsManager.totalConsumption,
+ ),
+ BodySmall(
+ text: "JAN 2024",
+ fontSize: 12,
+ fontColor: Colors.grey,
+ ),
+ ],
+ ),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.end,
+ children: [
+ UnitedText(
+ value: "1200.00",
+ valueStyle: TextStyle(
+ fontSize: 20,
+ fontWeight: FontWeight.bold,
+ height: 0,
+ ),
+ unit: "kWh",
+ ),
+ UnitedText(
+ value: "430",
+ valueStyle: TextStyle(
+ fontSize: 14,
+ color: Colors.grey,
+ ),
+ unit: "AED",
+ unitStyle: TextStyle(
+ fontSize: 12,
+ color: Colors.grey,
+ ),
+ )
+ ],
+ ),
+ ],
+ ),
+ )
+ ],
+ );
+ }
+}
diff --git a/lib/features/dashboard/view/widgets/live_monitor_tab.dart b/lib/features/dashboard/view/widgets/live_monitor_tab.dart
new file mode 100644
index 0000000..71de05a
--- /dev/null
+++ b/lib/features/dashboard/view/widgets/live_monitor_tab.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/material.dart';
+import 'package:syncrow_app/features/dashboard/view/widgets/live_monitor_widget.dart';
+import 'package:syncrow_app/utils/resource_manager/strings_manager.dart';
+
+import 'package:syncrow_app/generated/assets.dart';
+
+class LiveMonitorTab extends StatelessWidget {
+ const LiveMonitorTab({
+ super.key,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return const Row(
+ children: [
+ Expanded(
+ child: LiveMonitorWidget(
+ image: Assets.assetsIconsActive,
+ title: StringsManager.active,
+ value: '10.00w',
+ ),
+ ),
+ Expanded(
+ child: LiveMonitorWidget(
+ image: Assets.assetsIconsVoltMeter,
+ title: StringsManager.current,
+ value: '12.1 A',
+ ),
+ ),
+ Expanded(
+ child: LiveMonitorWidget(
+ image: Assets.assetsIconsFrequency,
+ title: StringsManager.frequency,
+ value: '50 Hz',
+ ),
+ ),
+ ],
+ );
+ }
+}
diff --git a/lib/features/dashboard/view/widgets/live_monitor_widget.dart b/lib/features/dashboard/view/widgets/live_monitor_widget.dart
new file mode 100644
index 0000000..87a97b8
--- /dev/null
+++ b/lib/features/dashboard/view/widgets/live_monitor_widget.dart
@@ -0,0 +1,61 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
+import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
+
+class LiveMonitorWidget extends StatelessWidget {
+ const LiveMonitorWidget({
+ super.key,
+ required this.image,
+ required this.title,
+ required this.value,
+ });
+
+ final String image;
+ final String title;
+ final String value;
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(15),
+ ),
+ padding: const EdgeInsets.only(left: 10, top: 5, bottom: 5),
+ margin: const EdgeInsets.only(right: 5),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SizedBox(
+ height: 23,
+ width: 20,
+ child: SvgPicture.asset(
+ image,
+ fit: BoxFit.contain,
+ ),
+ ),
+ const SizedBox(width: 5),
+ Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ BodySmall(
+ text: title,
+ style: const TextStyle(fontSize: 10, color: Colors.grey)),
+ BodyMedium(
+ text: value,
+ style: const TextStyle(
+ fontSize: 12,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ],
+ )
+ ],
+ ),
+ );
+ }
+}
diff --git a/lib/features/devices/bloc/acs_bloc/acs_bloc.dart b/lib/features/devices/bloc/acs_bloc/acs_bloc.dart
new file mode 100644
index 0000000..c8a8350
--- /dev/null
+++ b/lib/features/devices/bloc/acs_bloc/acs_bloc.dart
@@ -0,0 +1,399 @@
+import 'dart:async';
+import 'package:firebase_database/firebase_database.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
+import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
+import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
+import 'package:syncrow_app/features/devices/model/ac_model.dart';
+import 'package:syncrow_app/features/devices/model/device_control_model.dart';
+import 'package:syncrow_app/features/devices/model/device_model.dart';
+import 'package:syncrow_app/features/devices/model/status_model.dart';
+import 'package:syncrow_app/services/api/devices_api.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+
+class ACsBloc extends Bloc {
+ final String acId;
+ AcStatusModel deviceStatus = AcStatusModel(
+ uuid: '',
+ acSwitch: true,
+ modeString: 'hot',
+ tempSet: 300,
+ currentTemp: 315,
+ fanSpeedsString: 'low',
+ childLock: false);
+ List deviceStatusList = [];
+ List devicesList = [];
+ bool allAcsPage = false;
+ bool allAcsOn = true;
+ bool allTempSame = true;
+ int globalTemp = 25;
+ Timer? _timer;
+
+ ACsBloc({required this.acId}) : super(AcsInitialState()) {
+ on(_fetchAcsStatus);
+ on(_changeAcSwitch);
+ on(_increaseCoolTo);
+ on(_decreaseCoolTo);
+ on(_changeLockValue);
+ on(_changeAcMode);
+ on(_changeFanSpeed);
+ on(_changeAllAcSwitch);
+ on(_increaseAllTemp);
+ on(_decreaseAllTemp);
+ on(_onAcUpdated);
+ }
+
+ void _fetchAcsStatus(AcsInitial event, Emitter emit) async {
+ emit(AcsLoadingState());
+ try {
+ allAcsPage = event.allAcs;
+ if (event.allAcs) {
+ await _getAllAcs();
+ emit(GetAllAcsStatusState(
+ allAcsStatues: deviceStatusList,
+ allAcs: devicesList,
+ allOn: allAcsOn,
+ allTempSame: allTempSame,
+ temp: globalTemp));
+ } else {
+ var response = await DevicesAPI.getDeviceStatus(acId);
+ List statusModelList = [];
+ for (var status in response['status']) {
+ statusModelList.add(StatusModel.fromJson(status));
+ }
+ deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
+ emit(GetAcStatusState(acStatusModel: deviceStatus));
+ Future.delayed(const Duration(milliseconds: 500));
+ _listenToChanges();
+ }
+ } catch (e) {
+ emit(AcsFailedState(errorMessage: e.toString()));
+ return;
+ }
+ }
+
+ _listenToChanges() {
+ try {
+ DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$acId');
+ Stream stream = ref.onValue;
+
+ stream.listen((DatabaseEvent event) {
+ Map usersMap = event.snapshot.value as Map;
+ List statusList = [];
+
+ usersMap['status'].forEach((element) {
+ statusList.add(StatusModel(code: element['code'], value: element['value']));
+ });
+
+ deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
+ add(AcUpdated());
+ });
+ } catch (_) {}
+ }
+
+ _onAcUpdated(AcUpdated event, Emitter emit) {
+ emit(GetAcStatusState(acStatusModel: deviceStatus));
+ }
+
+ _getAllAcs() async {
+ deviceStatusList = [];
+ devicesList = [];
+ devicesList = await DevicesAPI.getDeviceByGroupName(
+ HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC');
+
+ for (int i = 0; i < devicesList.length; i++) {
+ var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
+ List statusModelList = [];
+ for (var status in response['status']) {
+ statusModelList.add(StatusModel.fromJson(status));
+ }
+ deviceStatusList.add(AcStatusModel.fromJson(response['productUuid'], statusModelList));
+ }
+ _setAllAcsTempsAndSwitches();
+ }
+
+ void _changeAcSwitch(AcSwitch event, Emitter emit) async {
+ final acSwitchValue = !event.acSwitch;
+ if (allAcsPage) {
+ emit(AcsLoadingState());
+ for (AcStatusModel ac in deviceStatusList) {
+ if (ac.uuid == event.productId) {
+ ac.acSwitch = acSwitchValue;
+ }
+ }
+ _setAllAcsTempsAndSwitches();
+ _emitAcsStatus(emit);
+ } else {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+ deviceStatus.acSwitch = acSwitchValue;
+ emit(AcModifyingState(acStatusModel: deviceStatus));
+ }
+
+ await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
+ }
+
+ void _changeAllAcSwitch(ChangeAllSwitch event, Emitter emit) async {
+ emit(AcsLoadingState());
+ if (deviceStatusList.length == devicesList.length) {
+ for (int i = 0; i < deviceStatusList.length; i++) {
+ deviceStatusList[i].acSwitch = event.value;
+ }
+ }
+ _setAllAcsTempsAndSwitches();
+ _emitAcsStatus(emit);
+ _runDeBouncerForAllAcs(code: 'switch', value: event.value);
+ }
+
+ void _increaseAllTemp(IncreaseAllTemp event, Emitter emit) async {
+ emit(AcsLoadingState());
+ double tempValue = event.value + 0.5;
+ int value = (tempValue * 10).toInt();
+
+ if (!_checkTemperatureValue(tempValue, emit)) {
+ return;
+ }
+
+ if (deviceStatusList.length == devicesList.length) {
+ for (int i = 0; i < deviceStatusList.length; i++) {
+ deviceStatusList[i].tempSet = value;
+ }
+ }
+ _setAllAcsTempsAndSwitches();
+ _emitAcsStatus(emit);
+ _runDeBouncerForAllAcs(code: 'temp_set', value: value);
+ }
+
+ void _decreaseAllTemp(DecreaseAllTemp event, Emitter emit) async {
+ emit(AcsLoadingState());
+
+ double tempValue = event.value - 0.5;
+ int value = (tempValue * 10).toInt();
+
+ if (!_checkTemperatureValue(tempValue, emit)) {
+ return;
+ }
+
+ if (deviceStatusList.length == devicesList.length) {
+ for (int i = 0; i < deviceStatusList.length; i++) {
+ deviceStatusList[i].tempSet = value;
+ }
+ }
+ _setAllAcsTempsAndSwitches();
+ _emitAcsStatus(emit);
+ _runDeBouncerForAllAcs(code: 'temp_set', value: value);
+ }
+
+ void _changeLockValue(ChangeLock event, Emitter emit) async {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+
+ final lockValue = !event.lockBool;
+ deviceStatus.childLock = lockValue;
+ emit(AcModifyingState(acStatusModel: deviceStatus));
+
+ await _runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue);
+ }
+
+ void _increaseCoolTo(IncreaseCoolToTemp event, Emitter emit) async {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+
+ double tempValue = event.value + 0.5;
+ int value = (tempValue * 10).toInt();
+
+ if (!_checkTemperatureValue(tempValue, emit)) {
+ return;
+ }
+
+ if (allAcsPage) {
+ emit(AcsLoadingState());
+ for (AcStatusModel ac in deviceStatusList) {
+ if (ac.uuid == event.productId) {
+ ac.tempSet = value;
+ }
+ }
+ _setAllAcsTempsAndSwitches();
+ _emitAcsStatus(emit);
+ } else {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+ deviceStatus.tempSet = value;
+ emit(AcModifyingState(acStatusModel: deviceStatus));
+ }
+
+ await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
+ }
+
+ void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter emit) async {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+
+ double tempValue = event.value - 0.5;
+ int value = (tempValue * 10).toInt();
+
+ if (!_checkTemperatureValue(tempValue, emit)) {
+ return;
+ }
+
+ if (allAcsPage) {
+ emit(AcsLoadingState());
+ for (AcStatusModel ac in deviceStatusList) {
+ if (ac.uuid == event.productId) {
+ ac.tempSet = value;
+ }
+ }
+ _setAllAcsTempsAndSwitches();
+ _emitAcsStatus(emit);
+ } else {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+ deviceStatus.tempSet = value;
+ emit(AcModifyingState(acStatusModel: deviceStatus));
+ }
+
+ await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
+ }
+
+ void _changeAcMode(ChangeAcMode event, Emitter emit) async {
+ final tempMode = tempModesMap[getNextItem(tempModesMap, event.tempModes)]!;
+ if (allAcsPage) {
+ emit(AcsLoadingState());
+ for (AcStatusModel ac in deviceStatusList) {
+ if (ac.uuid == event.productId) {
+ ac.modeString = getACModeString(tempMode);
+ ac.acMode = AcStatusModel.getACMode(getACModeString(tempMode));
+ }
+ }
+ _emitAcsStatus(emit);
+ } else {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+ deviceStatus.modeString = getACModeString(tempMode);
+ deviceStatus.acMode = AcStatusModel.getACMode(getACModeString(tempMode));
+ emit(AcModifyingState(acStatusModel: deviceStatus));
+ }
+
+ await _runDeBouncerForOneDevice(
+ deviceId: event.deviceId, code: 'mode', value: getACModeString(tempMode));
+ }
+
+ void _changeFanSpeed(ChangeFanSpeed event, Emitter emit) async {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+
+ final fanSpeed = event.fanSpeeds;
+
+ if (allAcsPage) {
+ emit(AcsLoadingState());
+ for (AcStatusModel ac in deviceStatusList) {
+ if (ac.uuid == event.productId) {
+ ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
+ ac.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
+ }
+ }
+ _emitAcsStatus(emit);
+ } else {
+ emit(AcChangeLoading(acStatusModel: deviceStatus));
+ deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
+ deviceStatus.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
+ emit(AcModifyingState(acStatusModel: deviceStatus));
+ }
+
+ await _runDeBouncerForOneDevice(
+ deviceId: event.deviceId, code: 'level', value: getNextFanSpeedKey(fanSpeed));
+ }
+
+ String getACModeString(TempModes value) {
+ if (value == TempModes.cold) {
+ return 'cold';
+ } else if (value == TempModes.hot) {
+ return 'hot';
+ } else if (value == TempModes.wind) {
+ return 'wind';
+ } else {
+ return 'cold';
+ }
+ }
+
+ void _setAllAcsTempsAndSwitches() {
+ allAcsOn = true;
+ allTempSame = true;
+ if (deviceStatusList.isNotEmpty) {
+ int temp = deviceStatusList[0].tempSet;
+ deviceStatusList.firstWhere((element) {
+ if (!element.acSwitch) {
+ allAcsOn = false;
+ }
+ if (element.tempSet != temp) {
+ allTempSame = false;
+ }
+
+ return true;
+ });
+ if (allTempSame) {
+ globalTemp = temp;
+ }
+ }
+ }
+
+ _runDeBouncerForAllAcs({required String code, required dynamic value}) {
+ if (_timer != null) {
+ _timer!.cancel();
+ }
+ _timer = Timer(const Duration(seconds: 1), () async {
+ if (deviceStatusList.length == devicesList.length) {
+ for (int i = 0; i < deviceStatusList.length; i++) {
+ try {
+ await DevicesAPI.controlDevice(
+ DeviceControlModel(deviceId: devicesList[i].uuid, code: code, value: value),
+ devicesList[i].uuid ?? '');
+ } catch (_) {
+ await Future.delayed(const Duration(milliseconds: 500));
+ add(const AcsInitial(allAcs: true));
+ }
+ }
+ }
+ });
+ }
+
+ _runDeBouncerForOneDevice({
+ required String deviceId,
+ required String code,
+ required dynamic value,
+ }) {
+ if (_timer != null) {
+ _timer!.cancel();
+ }
+ _timer = Timer(const Duration(seconds: 1), () async {
+ try {
+ final response = await DevicesAPI.controlDevice(
+ DeviceControlModel(deviceId: allAcsPage ? deviceId : acId, code: code, value: value),
+ allAcsPage ? deviceId : acId);
+
+ if (!response['success']) {
+ add(AcsInitial(allAcs: allAcsPage));
+ }
+ } catch (_) {
+ await Future.delayed(const Duration(milliseconds: 500));
+ add(AcsInitial(allAcs: allAcsPage));
+ }
+ });
+ }
+
+ bool _checkTemperatureValue(double value, Emitter emit) {
+ if (value >= 20 && value <= 30) {
+ return true;
+ } else {
+ emit(const AcsFailedState(errorMessage: 'The temperature must be between 20 and 30'));
+ emit(GetAllAcsStatusState(
+ allAcsStatues: deviceStatusList,
+ allAcs: devicesList,
+ allOn: allAcsOn,
+ allTempSame: allTempSame,
+ temp: globalTemp));
+ return false;
+ }
+ }
+
+ _emitAcsStatus(Emitter emit) {
+ emit(GetAllAcsStatusState(
+ allAcsStatues: deviceStatusList,
+ allAcs: devicesList,
+ allOn: allAcsOn,
+ allTempSame: allTempSame,
+ temp: globalTemp));
+ }
+}
diff --git a/lib/features/devices/bloc/acs_bloc/acs_event.dart b/lib/features/devices/bloc/acs_bloc/acs_event.dart
new file mode 100644
index 0000000..6a8eb12
--- /dev/null
+++ b/lib/features/devices/bloc/acs_bloc/acs_event.dart
@@ -0,0 +1,106 @@
+import 'package:equatable/equatable.dart';
+import 'package:syncrow_app/utils/resource_manager/constants.dart';
+
+abstract class AcsEvent extends Equatable {
+ const AcsEvent();
+
+ @override
+ List