| @ -0,0 +1,44 @@ | |||||||
|  | # Miscellaneous | ||||||
|  | *.class | ||||||
|  | *.log | ||||||
|  | *.pyc | ||||||
|  | *.swp | ||||||
|  | .DS_Store | ||||||
|  | .atom/ | ||||||
|  | .buildlog/ | ||||||
|  | .history | ||||||
|  | .svn/ | ||||||
|  | migrate_working_dir/ | ||||||
|  | 
 | ||||||
|  | # 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/ | ||||||
|  | 
 | ||||||
|  | # Flutter/Dart/Pub related | ||||||
|  | **/doc/api/ | ||||||
|  | **/ios/Flutter/.last_build_id | ||||||
|  | .dart_tool/ | ||||||
|  | .flutter-plugins | ||||||
|  | .flutter-plugins-dependencies | ||||||
|  | .packages | ||||||
|  | .pub-cache/ | ||||||
|  | .pub/ | ||||||
|  | /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 | ||||||
| @ -0,0 +1,45 @@ | |||||||
|  | # 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. | ||||||
|  | 
 | ||||||
|  | version: | ||||||
|  |   revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |   channel: stable | ||||||
|  | 
 | ||||||
|  | project_type: app | ||||||
|  | 
 | ||||||
|  | # Tracks metadata for the flutter migrate command | ||||||
|  | migration: | ||||||
|  |   platforms: | ||||||
|  |     - platform: root | ||||||
|  |       create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |       base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |     - platform: android | ||||||
|  |       create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |       base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |     - platform: ios | ||||||
|  |       create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |       base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |     - platform: linux | ||||||
|  |       create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |       base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |     - platform: macos | ||||||
|  |       create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |       base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |     - platform: web | ||||||
|  |       create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |       base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |     - platform: windows | ||||||
|  |       create_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  |       base_revision: b8f7f1f9869bb2d116aa6a70dbeac61000b52849 | ||||||
|  | 
 | ||||||
|  |   # 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' | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | # healthcare_user | ||||||
|  | 
 | ||||||
|  | A new Flutter 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. | ||||||
| @ -0,0 +1,29 @@ | |||||||
|  | # 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-lang.github.io/linter/lints/index.html. | ||||||
|  |   # | ||||||
|  |   # 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 | ||||||
| @ -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 | ||||||
| @ -0,0 +1,59 @@ | |||||||
|  | def localProperties = new Properties() | ||||||
|  | def localPropertiesFile = rootProject.file('local.properties') | ||||||
|  | if (localPropertiesFile.exists()) { | ||||||
|  |     localPropertiesFile.withReader('UTF-8') { reader -> | ||||||
|  |         localProperties.load(reader) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | def flutterRoot = localProperties.getProperty('flutter.sdk') | ||||||
|  | if (flutterRoot == null) { | ||||||
|  |     throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') | ||||||
|  | if (flutterVersionCode == null) { | ||||||
|  |     flutterVersionCode = '1' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | def flutterVersionName = localProperties.getProperty('flutter.versionName') | ||||||
|  | if (flutterVersionName == null) { | ||||||
|  |     flutterVersionName = '1.0' | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | apply plugin: 'com.android.application' | ||||||
|  | apply plugin: 'kotlin-android' | ||||||
|  | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" | ||||||
|  | 
 | ||||||
|  | android { | ||||||
|  |     compileSdkVersion 33 | ||||||
|  |     ndkVersion flutter.ndkVersion | ||||||
|  | 
 | ||||||
|  |     compileOptions { | ||||||
|  |         sourceCompatibility JavaVersion.VERSION_1_8 | ||||||
|  |         targetCompatibility JavaVersion.VERSION_1_8 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     defaultConfig { | ||||||
|  |         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). | ||||||
|  |         applicationId "com.arminta.healthcare_user" | ||||||
|  |         // You can update the following values to match your application needs. | ||||||
|  |         // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. | ||||||
|  |         minSdkVersion 28 | ||||||
|  |         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 '../..' | ||||||
|  | } | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     package="com.arminta.healthcare_user"> | ||||||
|  |     <!-- The INTERNET permission is required for development. Specifically, | ||||||
|  |          the Flutter tool needs it to communicate with the running application | ||||||
|  |          to allow setting breakpoints, to provide hot reload, etc. | ||||||
|  |     --> | ||||||
|  |     <uses-permission android:name="android.permission.INTERNET"/> | ||||||
|  | </manifest> | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     package="com.arminta.healthcare_user"> | ||||||
|  |     <uses-permission android:name="android.permission.INTERNET" /> | ||||||
|  |     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> | ||||||
|  |     <!--    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />--> | ||||||
|  |     <uses-permission android:name="android.permission.CAMERA" /> | ||||||
|  |     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | ||||||
|  |     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||||||
|  |     <uses-permission android:name="android.permission.READ_CONTACTS" /> | ||||||
|  |     <uses-permission android:name="android.permission.CALL_PHONE" /> | ||||||
|  |     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> | ||||||
|  |     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | ||||||
|  |     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/> | ||||||
|  |    <application | ||||||
|  |         android:label="HealthCare" | ||||||
|  |         android:name="${applicationName}" | ||||||
|  |         android:icon="@mipmap/ic_launcher"> | ||||||
|  |         <activity | ||||||
|  |             android:name=".MainActivity" | ||||||
|  |             android:exported="true" | ||||||
|  |             android:launchMode="singleTop" | ||||||
|  |             android:theme="@style/LaunchTheme" | ||||||
|  |             android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" | ||||||
|  |             android:hardwareAccelerated="true" | ||||||
|  |             android:windowSoftInputMode="adjustResize"> | ||||||
|  |             <!-- Specifies an Android theme to apply to this Activity as soon as | ||||||
|  |                  the Android process has started. This theme is visible to the user | ||||||
|  |                  while the Flutter UI initializes. After that, this theme continues | ||||||
|  |                  to determine the Window background behind the Flutter UI. --> | ||||||
|  |             <meta-data | ||||||
|  |               android:name="io.flutter.embedding.android.NormalTheme" | ||||||
|  |               android:resource="@style/NormalTheme" | ||||||
|  |               /> | ||||||
|  |             <intent-filter> | ||||||
|  |                 <action android:name="android.intent.action.MAIN"/> | ||||||
|  |                 <category android:name="android.intent.category.LAUNCHER"/> | ||||||
|  |             </intent-filter> | ||||||
|  |         </activity> | ||||||
|  |         <!-- Don't delete the meta-data below. | ||||||
|  |              This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> | ||||||
|  |         <meta-data | ||||||
|  |             android:name="flutterEmbedding" | ||||||
|  |             android:value="2" /> | ||||||
|  |        <meta-data android:name="com.google.android.geo.API_KEY" | ||||||
|  |            android:value="AIzaSyDJpK9RVhlBejtJu9xSGfneuTN6HOfJgSM"/> | ||||||
|  |     </application> | ||||||
|  | </manifest> | ||||||
| @ -0,0 +1,6 @@ | |||||||
|  | package com.example.healthcare_user | ||||||
|  | 
 | ||||||
|  | import io.flutter.embedding.android.FlutterActivity | ||||||
|  | 
 | ||||||
|  | class MainActivity: FlutterActivity() { | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!-- Modify this file to customize your launch splash screen --> | ||||||
|  | <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <item android:drawable="?android:colorBackground" /> | ||||||
|  | 
 | ||||||
|  |     <!-- You can insert your own image assets here --> | ||||||
|  |     <!-- <item> | ||||||
|  |         <bitmap | ||||||
|  |             android:gravity="center" | ||||||
|  |             android:src="@mipmap/launch_image" /> | ||||||
|  |     </item> --> | ||||||
|  | </layer-list> | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <!-- Modify this file to customize your launch splash screen --> | ||||||
|  | <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||
|  |     <item android:drawable="@android:color/white" /> | ||||||
|  | 
 | ||||||
|  |     <!-- You can insert your own image assets here --> | ||||||
|  |     <!-- <item> | ||||||
|  |         <bitmap | ||||||
|  |             android:gravity="center" | ||||||
|  |             android:src="@mipmap/launch_image" /> | ||||||
|  |     </item> --> | ||||||
|  | </layer-list> | ||||||
| After Width: | Height: | Size: 5.2 KiB | 
| After Width: | Height: | Size: 3.3 KiB | 
| After Width: | Height: | Size: 6.8 KiB | 
| After Width: | Height: | Size: 9.2 KiB | 
| After Width: | Height: | Size: 11 KiB | 
| @ -0,0 +1,18 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on --> | ||||||
|  |     <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||||||
|  |         <!-- Show a splash screen on the activity. Automatically removed when | ||||||
|  |              the Flutter engine draws its first frame --> | ||||||
|  |         <item name="android:windowBackground">@drawable/launch_background</item> | ||||||
|  |     </style> | ||||||
|  |     <!-- Theme applied to the Android Window as soon as the process has started. | ||||||
|  |          This theme determines the color of the Android Window while your | ||||||
|  |          Flutter UI initializes, as well as behind your Flutter UI while its | ||||||
|  |          running. | ||||||
|  | 
 | ||||||
|  |          This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||||||
|  |     <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> | ||||||
|  |         <item name="android:windowBackground">?android:colorBackground</item> | ||||||
|  |     </style> | ||||||
|  | </resources> | ||||||
| @ -0,0 +1,18 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <resources> | ||||||
|  |     <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off --> | ||||||
|  |     <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar"> | ||||||
|  |         <!-- Show a splash screen on the activity. Automatically removed when | ||||||
|  |              the Flutter engine draws its first frame --> | ||||||
|  |         <item name="android:windowBackground">@drawable/launch_background</item> | ||||||
|  |     </style> | ||||||
|  |     <!-- Theme applied to the Android Window as soon as the process has started. | ||||||
|  |          This theme determines the color of the Android Window while your | ||||||
|  |          Flutter UI initializes, as well as behind your Flutter UI while its | ||||||
|  |          running. | ||||||
|  | 
 | ||||||
|  |          This Theme is only used starting with V2 of Flutter's Android embedding. --> | ||||||
|  |     <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> | ||||||
|  |         <item name="android:windowBackground">?android:colorBackground</item> | ||||||
|  |     </style> | ||||||
|  | </resources> | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|  |     package="com.arminta.healthcare_user"> | ||||||
|  |     <!-- The INTERNET permission is required for development. Specifically, | ||||||
|  |          the Flutter tool needs it to communicate with the running application | ||||||
|  |          to allow setting breakpoints, to provide hot reload, etc. | ||||||
|  |     --> | ||||||
|  |     <uses-permission android:name="android.permission.INTERNET"/> | ||||||
|  | </manifest> | ||||||
| @ -0,0 +1,31 @@ | |||||||
|  | buildscript { | ||||||
|  |     ext.kotlin_version = '1.7.10' | ||||||
|  |     repositories { | ||||||
|  |         google() | ||||||
|  |         mavenCentral() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     dependencies { | ||||||
|  |         classpath 'com.android.tools.build:gradle:7.1.2' | ||||||
|  |         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') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | task clean(type: Delete) { | ||||||
|  |     delete rootProject.buildDir | ||||||
|  | } | ||||||
| @ -0,0 +1,3 @@ | |||||||
|  | org.gradle.jvmargs=-Xmx1536M | ||||||
|  | android.useAndroidX=true | ||||||
|  | android.enableJetifier=true | ||||||
| @ -0,0 +1,5 @@ | |||||||
|  | distributionBase=GRADLE_USER_HOME | ||||||
|  | distributionPath=wrapper/dists | ||||||
|  | zipStoreBase=GRADLE_USER_HOME | ||||||
|  | zipStorePath=wrapper/dists | ||||||
|  | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip | ||||||
| @ -0,0 +1,11 @@ | |||||||
|  | include ':app' | ||||||
|  | 
 | ||||||
|  | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") | ||||||
|  | def properties = new Properties() | ||||||
|  | 
 | ||||||
|  | assert localPropertiesFile.exists() | ||||||
|  | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } | ||||||
|  | 
 | ||||||
|  | def flutterSdkPath = properties.getProperty("flutter.sdk") | ||||||
|  | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" | ||||||
|  | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" | ||||||
| After Width: | Height: | Size: 5.8 KiB | 
| After Width: | Height: | Size: 7.3 KiB | 
| After Width: | Height: | Size: 28 KiB | 
| After Width: | Height: | Size: 4.2 KiB | 
| After Width: | Height: | Size: 27 KiB | 
| After Width: | Height: | Size: 678 B | 
| After Width: | Height: | Size: 932 B | 
| After Width: | Height: | Size: 42 KiB | 
| After Width: | Height: | Size: 1.5 KiB | 
| After Width: | Height: | Size: 7.2 KiB | 
| After Width: | Height: | Size: 7.2 KiB | 
| After Width: | Height: | Size: 4.9 KiB | 
| After Width: | Height: | Size: 957 B | 
| After Width: | Height: | Size: 3.6 KiB | 
| After Width: | Height: | Size: 5.3 KiB | 
| After Width: | Height: | Size: 58 KiB | 
| After Width: | Height: | Size: 11 KiB | 
| After Width: | Height: | Size: 80 KiB | 
| @ -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 | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  |   <key>CFBundleDevelopmentRegion</key> | ||||||
|  |   <string>en</string> | ||||||
|  |   <key>CFBundleExecutable</key> | ||||||
|  |   <string>App</string> | ||||||
|  |   <key>CFBundleIdentifier</key> | ||||||
|  |   <string>io.flutter.flutter.app</string> | ||||||
|  |   <key>CFBundleInfoDictionaryVersion</key> | ||||||
|  |   <string>6.0</string> | ||||||
|  |   <key>CFBundleName</key> | ||||||
|  |   <string>App</string> | ||||||
|  |   <key>CFBundlePackageType</key> | ||||||
|  |   <string>FMWK</string> | ||||||
|  |   <key>CFBundleShortVersionString</key> | ||||||
|  |   <string>1.0</string> | ||||||
|  |   <key>CFBundleSignature</key> | ||||||
|  |   <string>????</string> | ||||||
|  |   <key>CFBundleVersion</key> | ||||||
|  |   <string>1.0</string> | ||||||
|  |   <key>MinimumOSVersion</key> | ||||||
|  |   <string>11.0</string> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -0,0 +1 @@ | |||||||
|  | #include "Generated.xcconfig" | ||||||
| @ -0,0 +1 @@ | |||||||
|  | #include "Generated.xcconfig" | ||||||
| @ -0,0 +1,481 @@ | |||||||
|  | // !$*UTF8*$! | ||||||
|  | { | ||||||
|  | 	archiveVersion = 1; | ||||||
|  | 	classes = { | ||||||
|  | 	}; | ||||||
|  | 	objectVersion = 50; | ||||||
|  | 	objects = { | ||||||
|  | 
 | ||||||
|  | /* Begin PBXBuildFile section */ | ||||||
|  | 		1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; | ||||||
|  | 		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; | ||||||
|  | 		74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; | ||||||
|  | 		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 */; }; | ||||||
|  | /* End PBXBuildFile 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 = "<group>"; }; | ||||||
|  | 		1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; | ||||||
|  | 		3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; | ||||||
|  | 		74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; | ||||||
|  | 		74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; | ||||||
|  | 		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; | ||||||
|  | 		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; | ||||||
|  | 		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; | ||||||
|  | 		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 = "<group>"; }; | ||||||
|  | 		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; | ||||||
|  | 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; | ||||||
|  | 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; | ||||||
|  | /* End PBXFileReference section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXFrameworksBuildPhase section */ | ||||||
|  | 		97C146EB1CF9000F007C117D /* Frameworks */ = { | ||||||
|  | 			isa = PBXFrameworksBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 		}; | ||||||
|  | /* End PBXFrameworksBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXGroup section */ | ||||||
|  | 		9740EEB11CF90186004384FC /* Flutter */ = { | ||||||
|  | 			isa = PBXGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, | ||||||
|  | 				9740EEB21CF90195004384FC /* Debug.xcconfig */, | ||||||
|  | 				7AFA3C8E1D35360C0083082E /* Release.xcconfig */, | ||||||
|  | 				9740EEB31CF90195004384FC /* Generated.xcconfig */, | ||||||
|  | 			); | ||||||
|  | 			name = Flutter; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		97C146E51CF9000F007C117D = { | ||||||
|  | 			isa = PBXGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				9740EEB11CF90186004384FC /* Flutter */, | ||||||
|  | 				97C146F01CF9000F007C117D /* Runner */, | ||||||
|  | 				97C146EF1CF9000F007C117D /* Products */, | ||||||
|  | 			); | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		97C146EF1CF9000F007C117D /* Products */ = { | ||||||
|  | 			isa = PBXGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				97C146EE1CF9000F007C117D /* Runner.app */, | ||||||
|  | 			); | ||||||
|  | 			name = Products; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		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 = "<group>"; | ||||||
|  | 		}; | ||||||
|  | /* End PBXGroup section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXNativeTarget section */ | ||||||
|  | 		97C146ED1CF9000F007C117D /* Runner */ = { | ||||||
|  | 			isa = PBXNativeTarget; | ||||||
|  | 			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; | ||||||
|  | 			buildPhases = ( | ||||||
|  | 				9740EEB61CF901F6004384FC /* Run Script */, | ||||||
|  | 				97C146EA1CF9000F007C117D /* Sources */, | ||||||
|  | 				97C146EB1CF9000F007C117D /* Frameworks */, | ||||||
|  | 				97C146EC1CF9000F007C117D /* Resources */, | ||||||
|  | 				9705A1C41CF9048500538489 /* Embed Frameworks */, | ||||||
|  | 				3B06AD1E1E4923F5004D2608 /* Thin Binary */, | ||||||
|  | 			); | ||||||
|  | 			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 = { | ||||||
|  | 				LastUpgradeCheck = 1300; | ||||||
|  | 				ORGANIZATIONNAME = ""; | ||||||
|  | 				TargetAttributes = { | ||||||
|  | 					97C146ED1CF9000F007C117D = { | ||||||
|  | 						CreatedOnToolsVersion = 7.3.1; | ||||||
|  | 						LastSwiftMigration = 1100; | ||||||
|  | 					}; | ||||||
|  | 				}; | ||||||
|  | 			}; | ||||||
|  | 			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; | ||||||
|  | 			compatibilityVersion = "Xcode 9.3"; | ||||||
|  | 			developmentRegion = en; | ||||||
|  | 			hasScannedForEncodings = 0; | ||||||
|  | 			knownRegions = ( | ||||||
|  | 				en, | ||||||
|  | 				Base, | ||||||
|  | 			); | ||||||
|  | 			mainGroup = 97C146E51CF9000F007C117D; | ||||||
|  | 			productRefGroup = 97C146EF1CF9000F007C117D /* Products */; | ||||||
|  | 			projectDirPath = ""; | ||||||
|  | 			projectRoot = ""; | ||||||
|  | 			targets = ( | ||||||
|  | 				97C146ED1CF9000F007C117D /* Runner */, | ||||||
|  | 			); | ||||||
|  | 		}; | ||||||
|  | /* End PBXProject section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXResourcesBuildPhase section */ | ||||||
|  | 		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 */, | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 		}; | ||||||
|  | /* End PBXResourcesBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXShellScriptBuildPhase section */ | ||||||
|  | 		3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { | ||||||
|  | 			isa = PBXShellScriptBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 			); | ||||||
|  | 			inputPaths = ( | ||||||
|  | 			); | ||||||
|  | 			name = "Thin Binary"; | ||||||
|  | 			outputPaths = ( | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 			shellPath = /bin/sh; | ||||||
|  | 			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; | ||||||
|  | 		}; | ||||||
|  | 		9740EEB61CF901F6004384FC /* Run Script */ = { | ||||||
|  | 			isa = PBXShellScriptBuildPhase; | ||||||
|  | 			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 */ | ||||||
|  | 		97C146EA1CF9000F007C117D /* Sources */ = { | ||||||
|  | 			isa = PBXSourcesBuildPhase; | ||||||
|  | 			buildActionMask = 2147483647; | ||||||
|  | 			files = ( | ||||||
|  | 				74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, | ||||||
|  | 				1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, | ||||||
|  | 			); | ||||||
|  | 			runOnlyForDeploymentPostprocessing = 0; | ||||||
|  | 		}; | ||||||
|  | /* End PBXSourcesBuildPhase section */ | ||||||
|  | 
 | ||||||
|  | /* Begin PBXVariantGroup section */ | ||||||
|  | 		97C146FA1CF9000F007C117D /* Main.storyboard */ = { | ||||||
|  | 			isa = PBXVariantGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				97C146FB1CF9000F007C117D /* Base */, | ||||||
|  | 			); | ||||||
|  | 			name = Main.storyboard; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | 		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { | ||||||
|  | 			isa = PBXVariantGroup; | ||||||
|  | 			children = ( | ||||||
|  | 				97C147001CF9000F007C117D /* Base */, | ||||||
|  | 			); | ||||||
|  | 			name = LaunchScreen.storyboard; | ||||||
|  | 			sourceTree = "<group>"; | ||||||
|  | 		}; | ||||||
|  | /* End PBXVariantGroup section */ | ||||||
|  | 
 | ||||||
|  | /* Begin XCBuildConfiguration section */ | ||||||
|  | 		249021D3217E4FDB00AE95B9 /* Profile */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ALWAYS_SEARCH_USER_PATHS = NO; | ||||||
|  | 				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_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; | ||||||
|  | 				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 = 11.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; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||||||
|  | 				ENABLE_BITCODE = NO; | ||||||
|  | 				INFOPLIST_FILE = Runner/Info.plist; | ||||||
|  | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
|  | 					"$(inherited)", | ||||||
|  | 					"@executable_path/Frameworks", | ||||||
|  | 				); | ||||||
|  | 				PRODUCT_BUNDLE_IDENTIFIER = com.arminta.healthcareUser; | ||||||
|  | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; | ||||||
|  | 				SWIFT_VERSION = 5.0; | ||||||
|  | 				VERSIONING_SYSTEM = "apple-generic"; | ||||||
|  | 			}; | ||||||
|  | 			name = Profile; | ||||||
|  | 		}; | ||||||
|  | 		97C147031CF9000F007C117D /* Debug */ = { | ||||||
|  | 			isa = XCBuildConfiguration; | ||||||
|  | 			buildSettings = { | ||||||
|  | 				ALWAYS_SEARCH_USER_PATHS = NO; | ||||||
|  | 				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_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; | ||||||
|  | 				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 = 11.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; | ||||||
|  | 				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_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; | ||||||
|  | 				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 = 11.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; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||||||
|  | 				ENABLE_BITCODE = NO; | ||||||
|  | 				INFOPLIST_FILE = Runner/Info.plist; | ||||||
|  | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
|  | 					"$(inherited)", | ||||||
|  | 					"@executable_path/Frameworks", | ||||||
|  | 				); | ||||||
|  | 				PRODUCT_BUNDLE_IDENTIFIER = com.arminta.healthcareUser; | ||||||
|  | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				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; | ||||||
|  | 				CLANG_ENABLE_MODULES = YES; | ||||||
|  | 				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; | ||||||
|  | 				ENABLE_BITCODE = NO; | ||||||
|  | 				INFOPLIST_FILE = Runner/Info.plist; | ||||||
|  | 				LD_RUNPATH_SEARCH_PATHS = ( | ||||||
|  | 					"$(inherited)", | ||||||
|  | 					"@executable_path/Frameworks", | ||||||
|  | 				); | ||||||
|  | 				PRODUCT_BUNDLE_IDENTIFIER = com.arminta.healthcareUser; | ||||||
|  | 				PRODUCT_NAME = "$(TARGET_NAME)"; | ||||||
|  | 				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 */ | ||||||
|  | 		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 */; | ||||||
|  | } | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <Workspace | ||||||
|  |    version = "1.0"> | ||||||
|  |    <FileRef | ||||||
|  |       location = "self:"> | ||||||
|  |    </FileRef> | ||||||
|  | </Workspace> | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>IDEDidComputeMac32BitWarning</key> | ||||||
|  | 	<true/> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>PreviewsEnabled</key> | ||||||
|  | 	<false/> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -0,0 +1,87 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <Scheme | ||||||
|  |    LastUpgradeVersion = "1300" | ||||||
|  |    version = "1.3"> | ||||||
|  |    <BuildAction | ||||||
|  |       parallelizeBuildables = "YES" | ||||||
|  |       buildImplicitDependencies = "YES"> | ||||||
|  |       <BuildActionEntries> | ||||||
|  |          <BuildActionEntry | ||||||
|  |             buildForTesting = "YES" | ||||||
|  |             buildForRunning = "YES" | ||||||
|  |             buildForProfiling = "YES" | ||||||
|  |             buildForArchiving = "YES" | ||||||
|  |             buildForAnalyzing = "YES"> | ||||||
|  |             <BuildableReference | ||||||
|  |                BuildableIdentifier = "primary" | ||||||
|  |                BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||||||
|  |                BuildableName = "Runner.app" | ||||||
|  |                BlueprintName = "Runner" | ||||||
|  |                ReferencedContainer = "container:Runner.xcodeproj"> | ||||||
|  |             </BuildableReference> | ||||||
|  |          </BuildActionEntry> | ||||||
|  |       </BuildActionEntries> | ||||||
|  |    </BuildAction> | ||||||
|  |    <TestAction | ||||||
|  |       buildConfiguration = "Debug" | ||||||
|  |       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||||||
|  |       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||||||
|  |       shouldUseLaunchSchemeArgsEnv = "YES"> | ||||||
|  |       <MacroExpansion> | ||||||
|  |          <BuildableReference | ||||||
|  |             BuildableIdentifier = "primary" | ||||||
|  |             BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||||||
|  |             BuildableName = "Runner.app" | ||||||
|  |             BlueprintName = "Runner" | ||||||
|  |             ReferencedContainer = "container:Runner.xcodeproj"> | ||||||
|  |          </BuildableReference> | ||||||
|  |       </MacroExpansion> | ||||||
|  |       <Testables> | ||||||
|  |       </Testables> | ||||||
|  |    </TestAction> | ||||||
|  |    <LaunchAction | ||||||
|  |       buildConfiguration = "Debug" | ||||||
|  |       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||||||
|  |       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||||||
|  |       launchStyle = "0" | ||||||
|  |       useCustomWorkingDirectory = "NO" | ||||||
|  |       ignoresPersistentStateOnLaunch = "NO" | ||||||
|  |       debugDocumentVersioning = "YES" | ||||||
|  |       debugServiceExtension = "internal" | ||||||
|  |       allowLocationSimulation = "YES"> | ||||||
|  |       <BuildableProductRunnable | ||||||
|  |          runnableDebuggingMode = "0"> | ||||||
|  |          <BuildableReference | ||||||
|  |             BuildableIdentifier = "primary" | ||||||
|  |             BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||||||
|  |             BuildableName = "Runner.app" | ||||||
|  |             BlueprintName = "Runner" | ||||||
|  |             ReferencedContainer = "container:Runner.xcodeproj"> | ||||||
|  |          </BuildableReference> | ||||||
|  |       </BuildableProductRunnable> | ||||||
|  |    </LaunchAction> | ||||||
|  |    <ProfileAction | ||||||
|  |       buildConfiguration = "Profile" | ||||||
|  |       shouldUseLaunchSchemeArgsEnv = "YES" | ||||||
|  |       savedToolIdentifier = "" | ||||||
|  |       useCustomWorkingDirectory = "NO" | ||||||
|  |       debugDocumentVersioning = "YES"> | ||||||
|  |       <BuildableProductRunnable | ||||||
|  |          runnableDebuggingMode = "0"> | ||||||
|  |          <BuildableReference | ||||||
|  |             BuildableIdentifier = "primary" | ||||||
|  |             BlueprintIdentifier = "97C146ED1CF9000F007C117D" | ||||||
|  |             BuildableName = "Runner.app" | ||||||
|  |             BlueprintName = "Runner" | ||||||
|  |             ReferencedContainer = "container:Runner.xcodeproj"> | ||||||
|  |          </BuildableReference> | ||||||
|  |       </BuildableProductRunnable> | ||||||
|  |    </ProfileAction> | ||||||
|  |    <AnalyzeAction | ||||||
|  |       buildConfiguration = "Debug"> | ||||||
|  |    </AnalyzeAction> | ||||||
|  |    <ArchiveAction | ||||||
|  |       buildConfiguration = "Release" | ||||||
|  |       revealArchiveInOrganizer = "YES"> | ||||||
|  |    </ArchiveAction> | ||||||
|  | </Scheme> | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <Workspace | ||||||
|  |    version = "1.0"> | ||||||
|  |    <FileRef | ||||||
|  |       location = "group:Runner.xcodeproj"> | ||||||
|  |    </FileRef> | ||||||
|  | </Workspace> | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>IDEDidComputeMac32BitWarning</key> | ||||||
|  | 	<true/> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -0,0 +1,8 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>PreviewsEnabled</key> | ||||||
|  | 	<false/> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -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) | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,122 @@ | |||||||
|  | { | ||||||
|  |   "images" : [ | ||||||
|  |     { | ||||||
|  |       "size" : "20x20", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-20x20@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "20x20", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-20x20@3x.png", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "29x29", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-29x29@1x.png", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "29x29", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-29x29@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "29x29", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-29x29@3x.png", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "40x40", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-40x40@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "40x40", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-40x40@3x.png", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "60x60", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-60x60@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "60x60", | ||||||
|  |       "idiom" : "iphone", | ||||||
|  |       "filename" : "Icon-App-60x60@3x.png", | ||||||
|  |       "scale" : "3x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "20x20", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-20x20@1x.png", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "20x20", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-20x20@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "29x29", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-29x29@1x.png", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "29x29", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-29x29@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "40x40", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-40x40@1x.png", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "40x40", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-40x40@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "76x76", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-76x76@1x.png", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "76x76", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-76x76@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "83.5x83.5", | ||||||
|  |       "idiom" : "ipad", | ||||||
|  |       "filename" : "Icon-App-83.5x83.5@2x.png", | ||||||
|  |       "scale" : "2x" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "size" : "1024x1024", | ||||||
|  |       "idiom" : "ios-marketing", | ||||||
|  |       "filename" : "Icon-App-1024x1024@1x.png", | ||||||
|  |       "scale" : "1x" | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "info" : { | ||||||
|  |     "version" : 1, | ||||||
|  |     "author" : "xcode" | ||||||
|  |   } | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 149 KiB | 
| After Width: | Height: | Size: 882 B | 
| After Width: | Height: | Size: 2.1 KiB | 
| After Width: | Height: | Size: 3.4 KiB | 
| After Width: | Height: | Size: 1.4 KiB | 
| After Width: | Height: | Size: 3.3 KiB | 
| After Width: | Height: | Size: 5.1 KiB | 
| After Width: | Height: | Size: 2.1 KiB | 
| After Width: | Height: | Size: 4.6 KiB | 
| After Width: | Height: | Size: 6.7 KiB | 
| After Width: | Height: | Size: 6.7 KiB | 
| After Width: | Height: | Size: 9.4 KiB | 
| After Width: | Height: | Size: 4.5 KiB | 
| After Width: | Height: | Size: 8.2 KiB | 
| After Width: | Height: | Size: 8.8 KiB | 
| @ -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" | ||||||
|  |   } | ||||||
|  | } | ||||||
| After Width: | Height: | Size: 68 B | 
| After Width: | Height: | Size: 68 B | 
| After Width: | Height: | Size: 68 B | 
| @ -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. | ||||||
| @ -0,0 +1,37 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> | ||||||
|  |     <dependencies> | ||||||
|  |         <deployment identifier="iOS"/> | ||||||
|  |         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/> | ||||||
|  |     </dependencies> | ||||||
|  |     <scenes> | ||||||
|  |         <!--View Controller--> | ||||||
|  |         <scene sceneID="EHf-IW-A2E"> | ||||||
|  |             <objects> | ||||||
|  |                 <viewController id="01J-lp-oVM" sceneMemberID="viewController"> | ||||||
|  |                     <layoutGuides> | ||||||
|  |                         <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/> | ||||||
|  |                         <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/> | ||||||
|  |                     </layoutGuides> | ||||||
|  |                     <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> | ||||||
|  |                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||||||
|  |                         <subviews> | ||||||
|  |                             <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4"> | ||||||
|  |                             </imageView> | ||||||
|  |                         </subviews> | ||||||
|  |                         <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | ||||||
|  |                         <constraints> | ||||||
|  |                             <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/> | ||||||
|  |                             <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/> | ||||||
|  |                         </constraints> | ||||||
|  |                     </view> | ||||||
|  |                 </viewController> | ||||||
|  |                 <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> | ||||||
|  |             </objects> | ||||||
|  |             <point key="canvasLocation" x="53" y="375"/> | ||||||
|  |         </scene> | ||||||
|  |     </scenes> | ||||||
|  |     <resources> | ||||||
|  |         <image name="LaunchImage" width="168" height="185"/> | ||||||
|  |     </resources> | ||||||
|  | </document> | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r"> | ||||||
|  |     <dependencies> | ||||||
|  |         <deployment identifier="iOS"/> | ||||||
|  |         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/> | ||||||
|  |     </dependencies> | ||||||
|  |     <scenes> | ||||||
|  |         <!--Flutter View Controller--> | ||||||
|  |         <scene sceneID="tne-QT-ifu"> | ||||||
|  |             <objects> | ||||||
|  |                 <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController"> | ||||||
|  |                     <layoutGuides> | ||||||
|  |                         <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/> | ||||||
|  |                         <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/> | ||||||
|  |                     </layoutGuides> | ||||||
|  |                     <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> | ||||||
|  |                         <rect key="frame" x="0.0" y="0.0" width="600" height="600"/> | ||||||
|  |                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||||||
|  |                         <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/> | ||||||
|  |                     </view> | ||||||
|  |                 </viewController> | ||||||
|  |                 <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> | ||||||
|  |             </objects> | ||||||
|  |         </scene> | ||||||
|  |     </scenes> | ||||||
|  | </document> | ||||||
| @ -0,0 +1,51 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||||
|  | <plist version="1.0"> | ||||||
|  | <dict> | ||||||
|  | 	<key>CFBundleDevelopmentRegion</key> | ||||||
|  | 	<string>$(DEVELOPMENT_LANGUAGE)</string> | ||||||
|  | 	<key>CFBundleDisplayName</key> | ||||||
|  | 	<string>Healthcare User</string> | ||||||
|  | 	<key>CFBundleExecutable</key> | ||||||
|  | 	<string>$(EXECUTABLE_NAME)</string> | ||||||
|  | 	<key>CFBundleIdentifier</key> | ||||||
|  | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> | ||||||
|  | 	<key>CFBundleInfoDictionaryVersion</key> | ||||||
|  | 	<string>6.0</string> | ||||||
|  | 	<key>CFBundleName</key> | ||||||
|  | 	<string>healthcare_user</string> | ||||||
|  | 	<key>CFBundlePackageType</key> | ||||||
|  | 	<string>APPL</string> | ||||||
|  | 	<key>CFBundleShortVersionString</key> | ||||||
|  | 	<string>$(FLUTTER_BUILD_NAME)</string> | ||||||
|  | 	<key>CFBundleSignature</key> | ||||||
|  | 	<string>????</string> | ||||||
|  | 	<key>CFBundleVersion</key> | ||||||
|  | 	<string>$(FLUTTER_BUILD_NUMBER)</string> | ||||||
|  | 	<key>LSRequiresIPhoneOS</key> | ||||||
|  | 	<true/> | ||||||
|  | 	<key>UILaunchStoryboardName</key> | ||||||
|  | 	<string>LaunchScreen</string> | ||||||
|  | 	<key>UIMainStoryboardFile</key> | ||||||
|  | 	<string>Main</string> | ||||||
|  | 	<key>UISupportedInterfaceOrientations</key> | ||||||
|  | 	<array> | ||||||
|  | 		<string>UIInterfaceOrientationPortrait</string> | ||||||
|  | 		<string>UIInterfaceOrientationLandscapeLeft</string> | ||||||
|  | 		<string>UIInterfaceOrientationLandscapeRight</string> | ||||||
|  | 	</array> | ||||||
|  | 	<key>UISupportedInterfaceOrientations~ipad</key> | ||||||
|  | 	<array> | ||||||
|  | 		<string>UIInterfaceOrientationPortrait</string> | ||||||
|  | 		<string>UIInterfaceOrientationPortraitUpsideDown</string> | ||||||
|  | 		<string>UIInterfaceOrientationLandscapeLeft</string> | ||||||
|  | 		<string>UIInterfaceOrientationLandscapeRight</string> | ||||||
|  | 	</array> | ||||||
|  | 	<key>UIViewControllerBasedStatusBarAppearance</key> | ||||||
|  | 	<false/> | ||||||
|  | 	<key>CADisableMinimumFrameDurationOnPhone</key> | ||||||
|  | 	<true/> | ||||||
|  | 	<key>UIApplicationSupportsIndirectInputEvents</key> | ||||||
|  | 	<true/> | ||||||
|  | </dict> | ||||||
|  | </plist> | ||||||
| @ -0,0 +1 @@ | |||||||
|  | #import "GeneratedPluginRegistrant.h" | ||||||
| @ -0,0 +1,41 @@ | |||||||
|  | { | ||||||
|  |   "status_code": 200, | ||||||
|  |   "data": [ | ||||||
|  |     { | ||||||
|  |       "boreName": "bore1", | ||||||
|  |       "typeofwater":  "bore", | ||||||
|  |       "description": "this is bore 1", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "boreName": "bore2", | ||||||
|  |       "typeofwater":  "drinking", | ||||||
|  |       "description": "this is bore 2", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "boreName": "bore3", | ||||||
|  |       "typeofwater":  "bore", | ||||||
|  |       "description": "this is bore 3", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "boreName": "bore4", | ||||||
|  |       "typeofwater":  "drinking", | ||||||
|  |       "description": "this is bore 4", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "boreName": "bore5", | ||||||
|  |       "typeofwater":  "bore", | ||||||
|  |       "description": "this is bore 5", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "count": 1 | ||||||
|  | } | ||||||
| @ -0,0 +1,151 @@ | |||||||
|  | { | ||||||
|  |   "status_code": 200, | ||||||
|  |   "data": [ | ||||||
|  |     { | ||||||
|  |       "connections": { | ||||||
|  |         "inputConnections": [], | ||||||
|  |         "outputConnections": [] | ||||||
|  |       }, | ||||||
|  |       "userName": "testuser1", | ||||||
|  |       "tankName": "tank3", | ||||||
|  |       "blockName": "sriram", | ||||||
|  |       "capacity": "5000", | ||||||
|  |       "typeOfWater": "mineral", | ||||||
|  |       "type": "supplier", | ||||||
|  |       "tankLocation": "", | ||||||
|  |       "tankId": 1, | ||||||
|  |       "_id": "63ca4d187d797729224c1127", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "connections": { | ||||||
|  |         "inputConnections": [ | ||||||
|  |           { | ||||||
|  |             "_id": "63ce510b7a899c297d081c08", | ||||||
|  |             "inputConnections": "TankerA" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "outputConnections": [ | ||||||
|  |           { | ||||||
|  |             "_id": "63ce510b7a899c297d081c09", | ||||||
|  |             "outputConnections": "overheadAb" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "source": "TestA" | ||||||
|  |       }, | ||||||
|  |       "userName": "testuser1", | ||||||
|  |       "tankName": "TestA", | ||||||
|  |       "blockName": "blockA", | ||||||
|  |       "capacity": "8000000", | ||||||
|  |       "typeOfWater": "bore", | ||||||
|  |       "type": "tank", | ||||||
|  |       "tankLocation": "sump", | ||||||
|  |       "tankId": 2, | ||||||
|  |       "_id": "63ce28397c8d731709b62f1d", | ||||||
|  |       "__v": 2 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "connections": { | ||||||
|  |         "inputConnections": [ | ||||||
|  |           { | ||||||
|  |             "_id": "63d0d239e0fa16109d08e613", | ||||||
|  |             "inputConnections": "bore22" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "outputConnections": [ | ||||||
|  |           { | ||||||
|  |             "_id": "63d0d239e0fa16109d08e614", | ||||||
|  |             "outputConnections": "oh22" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "source": "tank22" | ||||||
|  |       }, | ||||||
|  |       "userName": "testuser1", | ||||||
|  |       "tankName": "tank22", | ||||||
|  |       "blockName": "block22", | ||||||
|  |       "capacity": "9000", | ||||||
|  |       "typeOfWater": "bore", | ||||||
|  |       "type": "tank", | ||||||
|  |       "tankLocation": "overhead", | ||||||
|  |       "tankId": 3, | ||||||
|  |       "_id": "63ce5b0ce587f12d52284b5b", | ||||||
|  |       "__v": 2 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "connections": { | ||||||
|  |         "inputConnections": [ | ||||||
|  |           { | ||||||
|  |             "_id": "63ce616cfe4b9731adb91d6d", | ||||||
|  |             "inputConnections": "sump254" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "outputConnections": [ | ||||||
|  |           { | ||||||
|  |             "_id": "63ce616cfe4b9731adb91d6e", | ||||||
|  |             "outputConnections": "oh254" | ||||||
|  |           } | ||||||
|  |         ], | ||||||
|  |         "source": "test24" | ||||||
|  |       }, | ||||||
|  |       "userName": "testuser1", | ||||||
|  |       "tankName": "test24", | ||||||
|  |       "blockName": "block24", | ||||||
|  |       "capacity": "3000", | ||||||
|  |       "typeOfWater": "bore", | ||||||
|  |       "type": "tank", | ||||||
|  |       "tankLocation": "overhead", | ||||||
|  |       "tankId": 4, | ||||||
|  |       "_id": "63ce6085fe4b9731adb91d62", | ||||||
|  |       "__v": 3 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "connections": { | ||||||
|  |         "inputConnections": [], | ||||||
|  |         "outputConnections": [] | ||||||
|  |       }, | ||||||
|  |       "userName": "testuser1", | ||||||
|  |       "tankName": "tank26", | ||||||
|  |       "blockName": "block25", | ||||||
|  |       "capacity": "100", | ||||||
|  |       "typeOfWater": "ghmc", | ||||||
|  |       "type": "tank", | ||||||
|  |       "tankLocation": "sump", | ||||||
|  |       "tankId": 5, | ||||||
|  |       "_id": "63cf7e57e99a8523fe0807dd", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "connections": { | ||||||
|  |         "inputConnections": [], | ||||||
|  |         "outputConnections": [] | ||||||
|  |       }, | ||||||
|  |       "userName": "testuser1", | ||||||
|  |       "tankName": "tank", | ||||||
|  |       "blockName": "sri", | ||||||
|  |       "capacity": "8000", | ||||||
|  |       "typeOfWater": "drinking", | ||||||
|  |       "type": "tank", | ||||||
|  |       "tankLocation": "sump", | ||||||
|  |       "tankId":6, | ||||||
|  |       "_id": "63cf8535f023b02aaef29cc5", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "connections": { | ||||||
|  |         "inputConnections": [], | ||||||
|  |         "outputConnections": [] | ||||||
|  |       }, | ||||||
|  |       "userName": "testuser1", | ||||||
|  |       "tankName": "sri", | ||||||
|  |       "blockName": "blockb", | ||||||
|  |       "capacity": "100", | ||||||
|  |       "typeOfWater": "ghmc", | ||||||
|  |       "type": "supplier", | ||||||
|  |       "tankLocation": "sump", | ||||||
|  |       "tankId": 7, | ||||||
|  |       "_id": "63cfa943e4c64f3251a5e4e1", | ||||||
|  |       "__v": 0 | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "count": 7 | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |   "status_code": 200, | ||||||
|  |   "data": [ | ||||||
|  |     { | ||||||
|  |       "pipelineName": "ghmc 1", | ||||||
|  |       "typeofwater":  "drinking", | ||||||
|  |       "description": "this is first pipeline", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "pipelineName": "ghmc 2", | ||||||
|  |       "typeofwater":  "drinking", | ||||||
|  |       "description": "this is second pipeline", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   ], | ||||||
|  |   "count": 1 | ||||||
|  | } | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | { | ||||||
|  |   "status_code": 200, | ||||||
|  |   "data": [ | ||||||
|  |     { | ||||||
|  |       "tankerName": "tanker1", | ||||||
|  |       "phoneNumber": "9912995084", | ||||||
|  |       "typeofwater":  "bore", | ||||||
|  |       "capacity": "5000", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "tankerName": "tanker2", | ||||||
|  |       "phoneNumber": "9912995083", | ||||||
|  |       "typeofwater":  "drinking", | ||||||
|  |       "capacity": "5000", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "tankerName": "tanker3", | ||||||
|  |       "phoneNumber": "9912995085", | ||||||
|  |       "typeofwater":  "bore", | ||||||
|  |       "capacity": "3000", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "tankerName": "tanker4", | ||||||
|  |       "phoneNumber": "9912995086", | ||||||
|  |       "typeofwater":  "drinking", | ||||||
|  |       "capacity": "2000", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     },{ | ||||||
|  |       "tankerName": "tanker5", | ||||||
|  |       "phoneNumber": "9912995087", | ||||||
|  |       "typeofwater":  "bore", | ||||||
|  |       "capacity": "4000", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     },{ | ||||||
|  |       "tankerName": "tanker6", | ||||||
|  |       "phoneNumber": "9912995088", | ||||||
|  |       "typeofwater":  "bore", | ||||||
|  |       "capacity": "10000", | ||||||
|  |       "_id": "63e1e80dbd430f5ec4c5badc", | ||||||
|  |       "__v": 0 | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "count": 1 | ||||||
|  | } | ||||||
| @ -0,0 +1,579 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter/services.dart'; | ||||||
|  | import 'package:flutter_svg/flutter_svg.dart'; | ||||||
|  | import 'package:healthcare_user/settings.dart'; | ||||||
|  | import 'package:image_picker/image_picker.dart'; | ||||||
|  | import 'dart:io'; | ||||||
|  | import 'dart:ui' as ui; | ||||||
|  | 
 | ||||||
|  | import 'login.dart'; | ||||||
|  | 
 | ||||||
|  | class Dashboard extends StatefulWidget { | ||||||
|  |   const Dashboard({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   State<Dashboard> createState() => _DashboardState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _DashboardState extends State<Dashboard> { | ||||||
|  |   int _selectedIndex = 0; | ||||||
|  | 
 | ||||||
|  |   TextEditingController tankNameController = TextEditingController(); | ||||||
|  |   TextEditingController blockNameController = TextEditingController(); | ||||||
|  |   TextEditingController capacityController = TextEditingController(); | ||||||
|  |   String dropdownTypeOfWater = 'General'; | ||||||
|  |   String dropdownTankLocation = 'Sump'; | ||||||
|  |   var typeOfWaterItems = [ | ||||||
|  |     'General', | ||||||
|  |     'Bore', | ||||||
|  |     'Tanker', | ||||||
|  |   ]; | ||||||
|  |   var typeOfTankLocationItems = [ | ||||||
|  |     'Sump', | ||||||
|  |     'Overhead', | ||||||
|  |   ]; | ||||||
|  | 
 | ||||||
|  |   bool isT1Checked = false; | ||||||
|  |   bool isT2Checked = false; | ||||||
|  |   bool isT3Checked = false; | ||||||
|  |   bool isS2T1Checked = false; | ||||||
|  |   bool isS2T2Checked = false; | ||||||
|  |   bool isS2T3Checked = false; | ||||||
|  |   bool isS3T1Checked = false; | ||||||
|  |   bool isS3T2Checked = false; | ||||||
|  |   bool isS3T3Checked = false; | ||||||
|  |   static const TextStyle optionStyle = | ||||||
|  |       TextStyle(fontSize: 30, fontWeight: FontWeight.bold); | ||||||
|  | 
 | ||||||
|  |   final ImagePicker _picker = ImagePicker(); | ||||||
|  |   bool isTablet = false; | ||||||
|  |   bool isPhone = true; | ||||||
|  | 
 | ||||||
|  |   final double devicePixelRatio = ui.window.devicePixelRatio; | ||||||
|  |   static final ui.Size size1 = ui.window.physicalSize; | ||||||
|  |   final double width = size1.width; | ||||||
|  |   final double height = size1.height; | ||||||
|  | 
 | ||||||
|  |   devicedetection() { | ||||||
|  |     if (devicePixelRatio < 2 && (width >= 1000 || height >= 1000)) { | ||||||
|  |       isTablet = true; | ||||||
|  |       isPhone = false; | ||||||
|  |     } else if (devicePixelRatio == 2 && (width >= 1920 || height >= 1920)) { | ||||||
|  |       isTablet = true; | ||||||
|  |       isPhone = false; | ||||||
|  |     } else { | ||||||
|  |       isTablet = false; | ||||||
|  |       isPhone = true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   Widget _dashBoard() { | ||||||
|  |     return Container( | ||||||
|  |       color: screenBackgroundColor, | ||||||
|  |       child: Column( | ||||||
|  |         children: <Widget>[ | ||||||
|  |           Container( | ||||||
|  |               height: MediaQuery.of(context).size.height * .250, | ||||||
|  |               width: double.infinity, | ||||||
|  |               decoration: BoxDecoration( | ||||||
|  |                 borderRadius: BorderRadius.circular(0), | ||||||
|  |               ), | ||||||
|  |               //color: Colors.red, | ||||||
|  |               child: FittedBox( | ||||||
|  |                 child: Image( | ||||||
|  |                   image: isTablet | ||||||
|  |                       ? AssetImage('images/appbg.png') | ||||||
|  |                       : AssetImage('images/mobilebg.png'), | ||||||
|  |                 ), | ||||||
|  |                 fit: BoxFit.fill, | ||||||
|  |               )), | ||||||
|  |           SizedBox(height: 5), | ||||||
|  |           Row( | ||||||
|  |             mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |             children: <Widget>[ | ||||||
|  |               Expanded( | ||||||
|  |                   child: GestureDetector( | ||||||
|  |                 onTap: () { | ||||||
|  |                   /*Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => TankLevelsNew()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |                 child: Container( | ||||||
|  |                   padding: EdgeInsets.all(05), | ||||||
|  |                   margin: | ||||||
|  |                       EdgeInsets.only(left: 15, top: 10, right: 0, bottom: 0), | ||||||
|  |                   //height: MediaQuery.of(context).size.height * .05, | ||||||
|  |                   //width: MediaQuery.of(context).size.width * .45, | ||||||
|  |                   decoration: BoxDecoration( | ||||||
|  |                     color: Colors.white, | ||||||
|  |                     borderRadius: BorderRadius.circular(12), | ||||||
|  |                   ), | ||||||
|  |                   // Change button text when light changes state. | ||||||
|  | 
 | ||||||
|  |                   child: Column( | ||||||
|  |                     children: [ | ||||||
|  |                       Container( | ||||||
|  |                           padding: EdgeInsets.fromLTRB(35, 10, 0, 0), | ||||||
|  |                           child: new SvgPicture.asset( | ||||||
|  |                               "assets/images/tanklevels.svg")), | ||||||
|  |                       Text( | ||||||
|  |                         'Tank Levels', | ||||||
|  |                         style: dashboardTextStyle(), | ||||||
|  |                       ), | ||||||
|  |                     ], | ||||||
|  |                   ), | ||||||
|  |                 ), | ||||||
|  |               )), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     devicedetection(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   showLogoutAlertDialog(context) { | ||||||
|  |     return showDialog( | ||||||
|  |         context: context, | ||||||
|  |         barrierDismissible: false, | ||||||
|  |         builder: (BuildContext context) { | ||||||
|  |           return StatefulBuilder( | ||||||
|  |               builder: (BuildContext context, StateSetter setState) { | ||||||
|  |             return AlertDialog( | ||||||
|  |                 title: const Text('Do you really want to logout?'), | ||||||
|  |                 actions: <Widget>[ | ||||||
|  |                   TextButton( | ||||||
|  |                     child: Text('No', style: textButtonStyle()), | ||||||
|  |                     onPressed: () { | ||||||
|  |                       Navigator.of(context).pop(); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                   TextButton( | ||||||
|  |                     child: Text('Yes', style: textButtonStyle()), | ||||||
|  |                     onPressed: () async { | ||||||
|  |                       await AppSettings.clearSharedPreferences(); | ||||||
|  |                       await Navigator.pushAndRemoveUntil( | ||||||
|  |                         context, | ||||||
|  |                         MaterialPageRoute(builder: (context) => Login()), | ||||||
|  |                         (Route<dynamic> route) => false, | ||||||
|  |                       ); | ||||||
|  |                     }, | ||||||
|  |                   ), | ||||||
|  |                 ]); | ||||||
|  |           }); | ||||||
|  |         }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return WillPopScope( | ||||||
|  |       onWillPop: () async { | ||||||
|  |         if (_selectedIndex == 0) { | ||||||
|  |           final shouldPop = await showDialog<bool>( | ||||||
|  |             context: context, | ||||||
|  |             builder: (context) { | ||||||
|  |               return AlertDialog( | ||||||
|  |                 title: const Text('Do you want to exit app?', | ||||||
|  |                     style: TextStyle( | ||||||
|  |                       color: primaryColor, | ||||||
|  |                       fontSize: 20, | ||||||
|  |                     )), | ||||||
|  |                 actionsAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |                 actions: [ | ||||||
|  |                   TextButton( | ||||||
|  |                     onPressed: () { | ||||||
|  |                       SystemNavigator.pop(); | ||||||
|  |                     }, | ||||||
|  |                     child: const Text('Yes', | ||||||
|  |                         style: TextStyle( | ||||||
|  |                           color: primaryColor, | ||||||
|  |                           fontSize: 20, | ||||||
|  |                         )), | ||||||
|  |                   ), | ||||||
|  |                   TextButton( | ||||||
|  |                     onPressed: () { | ||||||
|  |                       Navigator.of(context).pop(false); | ||||||
|  |                     }, | ||||||
|  |                     child: const Text('No', | ||||||
|  |                         style: TextStyle( | ||||||
|  |                           color: primaryColor, | ||||||
|  |                           fontSize: 20, | ||||||
|  |                         )), | ||||||
|  |                   ), | ||||||
|  |                 ], | ||||||
|  |               ); | ||||||
|  |             }, | ||||||
|  |           ); | ||||||
|  |           return shouldPop!; | ||||||
|  |         } else { | ||||||
|  |           setState(() { | ||||||
|  |             _selectedIndex = 0; | ||||||
|  |           }); | ||||||
|  |           return false; | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       child: Scaffold( | ||||||
|  |         resizeToAvoidBottomInset: false, | ||||||
|  |         appBar: AppSettings.appBar('Arminta Water Management'), | ||||||
|  |         drawer: Drawer( | ||||||
|  |           // Add a ListView to the drawer. This ensures the user can scroll | ||||||
|  |           // through the options in the drawer if there isn't enough vertical | ||||||
|  |           // space to fit everything. | ||||||
|  |           //backgroundColor: screenBackgroundColor, | ||||||
|  |           child: ListView( | ||||||
|  |             // Important: Remove any padding from the ListView. | ||||||
|  |             padding: EdgeInsets.zero, | ||||||
|  |             children: [ | ||||||
|  |               DrawerHeader( | ||||||
|  |                   decoration: const BoxDecoration( | ||||||
|  |                     color: primaryColor, | ||||||
|  |                   ), | ||||||
|  |                   child: Row( | ||||||
|  |                     children: [ | ||||||
|  |                       Column( | ||||||
|  |                         crossAxisAlignment: CrossAxisAlignment.start, | ||||||
|  |                         children: [ | ||||||
|  |                           Expanded( | ||||||
|  |                             child: GestureDetector( | ||||||
|  |                               child: Container( | ||||||
|  |                                 width: MediaQuery.of(context).size.width * .20, | ||||||
|  |                                 height: | ||||||
|  |                                     MediaQuery.of(context).size.height * .15, | ||||||
|  |                                 decoration: BoxDecoration( | ||||||
|  |                                     shape: BoxShape.circle, | ||||||
|  |                                     image: DecorationImage( | ||||||
|  |                                         image: (AppSettings.updatedImage != | ||||||
|  |                                                 null) | ||||||
|  |                                             ? FileImage( | ||||||
|  |                                                     AppSettings.updatedImage!) | ||||||
|  |                                                 as ImageProvider | ||||||
|  |                                             : AssetImage( | ||||||
|  |                                                 "images/profile_pic.png"), // picked file | ||||||
|  |                                         fit: BoxFit.cover)), | ||||||
|  |                               ), | ||||||
|  |                               onTap: () { | ||||||
|  |                                 /*showModalBottomSheet<void>( | ||||||
|  |                                     context: context, | ||||||
|  |                                     builder: (BuildContext context) { | ||||||
|  |                                       return SizedBox( | ||||||
|  |                                         height: 200, | ||||||
|  |                                         child: Center( | ||||||
|  |                                           child: Row( | ||||||
|  |                                             mainAxisAlignment: | ||||||
|  |                                                 MainAxisAlignment.center, | ||||||
|  |                                             children: <Widget>[ | ||||||
|  |                                               GestureDetector( | ||||||
|  |                                                 child: Icon( | ||||||
|  |                                                   Icons.camera_alt_outlined, | ||||||
|  |                                                   size: 100, | ||||||
|  |                                                   color: greyColor, | ||||||
|  |                                                 ), | ||||||
|  |                                                 onTap: () async { | ||||||
|  |                                                   await takeImageFromCamera(); | ||||||
|  |                                                   Navigator.pop(context); | ||||||
|  |                                                 }, | ||||||
|  |                                               ), | ||||||
|  |                                               SizedBox( | ||||||
|  |                                                 width: MediaQuery.of(context) | ||||||
|  |                                                         .size | ||||||
|  |                                                         .width * | ||||||
|  |                                                     .20, | ||||||
|  |                                               ), | ||||||
|  |                                               GestureDetector( | ||||||
|  |                                                 child: Icon( | ||||||
|  |                                                   Icons.photo, | ||||||
|  |                                                   size: 100, | ||||||
|  |                                                   color: greyColor, | ||||||
|  |                                                 ), | ||||||
|  |                                                 onTap: () async { | ||||||
|  |                                                   await pickImageFromGallery(); | ||||||
|  |                                                   Navigator.pop(context); | ||||||
|  |                                                 }, | ||||||
|  |                                               ), | ||||||
|  |                                             ], | ||||||
|  |                                           ), | ||||||
|  |                                         ), | ||||||
|  |                                       ); | ||||||
|  |                                     });*/ | ||||||
|  |                               }, | ||||||
|  |                             ), | ||||||
|  |                           ), | ||||||
|  |                           Text( | ||||||
|  |                             AppSettings.userName, | ||||||
|  |                             style: TextStyle(color: Colors.white, fontSize: 15), | ||||||
|  |                           ), | ||||||
|  |                           Text( | ||||||
|  |                             AppSettings.phoneNumber, | ||||||
|  |                             style: TextStyle(color: Colors.white, fontSize: 15), | ||||||
|  |                           ), | ||||||
|  |                           Text( | ||||||
|  |                             AppSettings.email, | ||||||
|  |                             style: TextStyle(color: Colors.white, fontSize: 15), | ||||||
|  |                           ), | ||||||
|  |                         ], | ||||||
|  |                       ), | ||||||
|  |                       Container() | ||||||
|  |                     ], | ||||||
|  |                   )), | ||||||
|  | 
 | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/editprofileblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Edit Profile', style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                  /* Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => UpdateProfile()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               // Add Tanks | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/addtankerblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Add Tanks', style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                   /*Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => AddTanks()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/tankviewblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Tanks View', style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                   /*Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => TanksView()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               //Add Tanker | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/suppliersblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Add Water Suppliers', | ||||||
|  |                         style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                  /* Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => Suppliers()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/connectionsblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Connections', style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                  /* Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => ConnectionsView()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/resourceblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Resources', style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                   /*Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => Resources()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/customercareblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Accounts', style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                   /*Navigator.push( | ||||||
|  |                     context, | ||||||
|  |                     MaterialPageRoute(builder: (context) => UserAccounts()), | ||||||
|  |                   );*/ | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/customercareblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Customer Support', | ||||||
|  |                         style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () {}, | ||||||
|  |               ), | ||||||
|  |               Divider( | ||||||
|  |                 color: Colors.grey, | ||||||
|  |               ), | ||||||
|  |               ListTile( | ||||||
|  |                 title: Row( | ||||||
|  |                   children: const [ | ||||||
|  |                     Image( | ||||||
|  |                         image: const AssetImage('images/logoutblue.png'), | ||||||
|  |                         height: 25, | ||||||
|  |                         width: 25, | ||||||
|  |                         fit: BoxFit.fill), | ||||||
|  |                     const SizedBox( | ||||||
|  |                       width: 10, | ||||||
|  |                     ), | ||||||
|  |                     Text('Logout', style: TextStyle(color: primaryColor)), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |                 onTap: () async { | ||||||
|  |                   showLogoutAlertDialog(context); | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         body: _dashBoard(), | ||||||
|  |         /*body: IndexedStack( | ||||||
|  |           index: _selectedIndex, | ||||||
|  |           children: screens, | ||||||
|  |         ),*/ | ||||||
|  |         /* bottomNavigationBar: Container( | ||||||
|  |           //height: MediaQuery.of(context).size.height, | ||||||
|  |           child: BottomNavigationBar( | ||||||
|  |             items: const <BottomNavigationBarItem>[ | ||||||
|  |               BottomNavigationBarItem( | ||||||
|  |                 icon: Icon( | ||||||
|  |                   Icons.home, | ||||||
|  |                 ), | ||||||
|  |                 label: 'Home', | ||||||
|  |               ), | ||||||
|  |               BottomNavigationBarItem( | ||||||
|  |                 icon: Icon(Icons.propane_tank), | ||||||
|  |                 label: 'Add Tanks', | ||||||
|  |               ), | ||||||
|  |               */ /*BottomNavigationBarItem( | ||||||
|  |                 icon: Icon(Icons.private_connectivity_outlined), | ||||||
|  |                 label: 'CreateConnections', | ||||||
|  |               ),*/ /* | ||||||
|  |               BottomNavigationBarItem( | ||||||
|  |                 icon: Icon(Icons.list_alt), | ||||||
|  |                 label: 'Add Tanker', | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |             currentIndex: _selectedIndex, | ||||||
|  |             selectedItemColor: primaryColor, | ||||||
|  |             unselectedItemColor: greyColor, | ||||||
|  |             showUnselectedLabels: true, | ||||||
|  |             onTap: _onItemTapped, | ||||||
|  |           ), | ||||||
|  |         ),*/ | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | library google_maps_place_picker_mb; | ||||||
|  | 
 | ||||||
|  | export 'src/models/pick_result.dart'; | ||||||
|  | export 'src/components/floating_card.dart'; | ||||||
|  | export 'src/components/rounded_frame.dart'; | ||||||
|  | export 'src/models/circle_area.dart'; | ||||||
|  | export 'src/place_picker.dart'; | ||||||
| @ -0,0 +1,161 @@ | |||||||
|  | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/widgets.dart'; | ||||||
|  | import 'package:geolocator/geolocator.dart'; | ||||||
|  | import 'package:google_maps_flutter/google_maps_flutter.dart'; | ||||||
|  | import 'package:google_maps_webservice/geocoding.dart'; | ||||||
|  | import 'package:google_maps_webservice/places.dart'; | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  | 
 | ||||||
|  | import '../src/models/pick_result.dart'; | ||||||
|  | import '../src/place_picker.dart'; | ||||||
|  | 
 | ||||||
|  | class PlaceProvider extends ChangeNotifier { | ||||||
|  |   PlaceProvider( | ||||||
|  |     String apiKey, | ||||||
|  |     String? proxyBaseUrl, | ||||||
|  |     Client? httpClient, | ||||||
|  |     Map<String, dynamic> apiHeaders, | ||||||
|  |   ) { | ||||||
|  |     places = GoogleMapsPlaces( | ||||||
|  |       apiKey: apiKey, | ||||||
|  |       baseUrl: proxyBaseUrl, | ||||||
|  |       httpClient: httpClient, | ||||||
|  |       apiHeaders: apiHeaders as Map<String, String>?, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     geocoding = GoogleMapsGeocoding( | ||||||
|  |       apiKey: apiKey, | ||||||
|  |       baseUrl: proxyBaseUrl, | ||||||
|  |       httpClient: httpClient, | ||||||
|  |       apiHeaders: apiHeaders as Map<String, String>?, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static PlaceProvider of(BuildContext context, {bool listen = true}) => | ||||||
|  |       Provider.of<PlaceProvider>(context, listen: listen); | ||||||
|  | 
 | ||||||
|  |   late GoogleMapsPlaces places; | ||||||
|  |   late GoogleMapsGeocoding geocoding; | ||||||
|  |   String? sessionToken; | ||||||
|  |   bool isOnUpdateLocationCooldown = false; | ||||||
|  |   LocationAccuracy? desiredAccuracy; | ||||||
|  |   bool isAutoCompleteSearching = false; | ||||||
|  | 
 | ||||||
|  |   Future<void> updateCurrentLocation(bool forceAndroidLocationManager) async { | ||||||
|  |     bool serviceEnabled; | ||||||
|  |     LocationPermission permission; | ||||||
|  | 
 | ||||||
|  |     // Test if location services are enabled. | ||||||
|  |     serviceEnabled = await Geolocator.isLocationServiceEnabled(); | ||||||
|  |     if (!serviceEnabled) { | ||||||
|  |       // Location services are not enabled don't continue | ||||||
|  |       // accessing the position and request users of the | ||||||
|  |       // App to enable the location services. | ||||||
|  |       return Future.error('Location services are disabled.'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     permission = await Geolocator.checkPermission(); | ||||||
|  |     if (permission == LocationPermission.denied) { | ||||||
|  |       permission = await Geolocator.requestPermission(); | ||||||
|  |       if (permission == LocationPermission.denied) { | ||||||
|  |         // Permissions are denied, next time you could try | ||||||
|  |         // requesting permissions again (this is also where | ||||||
|  |         // Android's shouldShowRequestPermissionRationale | ||||||
|  |         // returned true. According to Android guidelines | ||||||
|  |         // your App should show an explanatory UI now. | ||||||
|  |         return Future.error('Location permissions are denied'); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (permission == LocationPermission.deniedForever) { | ||||||
|  |       // Permissions are denied forever, handle appropriately. | ||||||
|  |       return Future.error( | ||||||
|  |           'Location permissions are permanently denied, we cannot request permissions.'); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Position position = await Geolocator.getCurrentPosition( | ||||||
|  |       desiredAccuracy: LocationAccuracy.best, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     currentPosition = position; | ||||||
|  | 
 | ||||||
|  |     // notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Position? _currentPosition; | ||||||
|  |   Position? get currentPosition => _currentPosition; | ||||||
|  |   set currentPosition(Position? newPosition) { | ||||||
|  |     _currentPosition = newPosition; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Timer? _debounceTimer; | ||||||
|  |   Timer? get debounceTimer => _debounceTimer; | ||||||
|  |   set debounceTimer(Timer? timer) { | ||||||
|  |     _debounceTimer = timer; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   CameraPosition? _previousCameraPosition; | ||||||
|  |   CameraPosition? get prevCameraPosition => _previousCameraPosition; | ||||||
|  |   setPrevCameraPosition(CameraPosition? prePosition) { | ||||||
|  |     _previousCameraPosition = prePosition; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   CameraPosition? _currentCameraPosition; | ||||||
|  |   CameraPosition? get cameraPosition => _currentCameraPosition; | ||||||
|  |   setCameraPosition(CameraPosition? newPosition) { | ||||||
|  |     _currentCameraPosition = newPosition; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   PickResult? _selectedPlace; | ||||||
|  |   PickResult? get selectedPlace => _selectedPlace; | ||||||
|  |   set selectedPlace(PickResult? result) { | ||||||
|  |     _selectedPlace = result; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   SearchingState _placeSearchingState = SearchingState.Idle; | ||||||
|  |   SearchingState get placeSearchingState => _placeSearchingState; | ||||||
|  |   set placeSearchingState(SearchingState newState) { | ||||||
|  |     _placeSearchingState = newState; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   GoogleMapController? _mapController; | ||||||
|  |   GoogleMapController? get mapController => _mapController; | ||||||
|  |   set mapController(GoogleMapController? controller) { | ||||||
|  |     _mapController = controller; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   PinState _pinState = PinState.Preparing; | ||||||
|  |   PinState get pinState => _pinState; | ||||||
|  |   set pinState(PinState newState) { | ||||||
|  |     _pinState = newState; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   bool _isSeachBarFocused = false; | ||||||
|  |   bool get isSearchBarFocused => _isSeachBarFocused; | ||||||
|  |   set isSearchBarFocused(bool focused) { | ||||||
|  |     _isSeachBarFocused = focused; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   MapType _mapType = MapType.normal; | ||||||
|  |   MapType get mapType => _mapType; | ||||||
|  |   setMapType(MapType mapType, {bool notify = false}) { | ||||||
|  |     _mapType = mapType; | ||||||
|  |     if (notify) notifyListeners(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   switchMapType() { | ||||||
|  |     _mapType = MapType.values[(_mapType.index + 1) % MapType.values.length]; | ||||||
|  |     if (_mapType == MapType.none) _mapType = MapType.normal; | ||||||
|  | 
 | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | import 'package:flutter/widgets.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  | 
 | ||||||
|  | class SearchProvider extends ChangeNotifier { | ||||||
|  |   static SearchProvider of(BuildContext context, {bool listen = true}) => | ||||||
|  |       Provider.of<SearchProvider>(context, listen: listen); | ||||||
|  | 
 | ||||||
|  |   String prevSearchTerm = ""; | ||||||
|  |   String _searchTerm = ""; | ||||||
|  |   String get searchTerm => _searchTerm; | ||||||
|  | 
 | ||||||
|  |   set searchTerm(String newValue) { | ||||||
|  |     _searchTerm = newValue; | ||||||
|  |     notifyListeners(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,341 @@ | |||||||
|  | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:google_maps_webservice/places.dart'; | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/google_maps_place_picker.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/providers/place_provider.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/providers/search_provider.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/components/prediction_tile.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/components/rounded_frame.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/controllers/autocomplete_search_controller.dart'; | ||||||
|  | 
 | ||||||
|  | class AutoCompleteSearch extends StatefulWidget { | ||||||
|  |   const AutoCompleteSearch( | ||||||
|  |       {Key? key, | ||||||
|  |         required this.sessionToken, | ||||||
|  |         required this.onPicked, | ||||||
|  |         required this.appBarKey, | ||||||
|  |         this.hintText = "Search here", | ||||||
|  |         this.searchingText = "Searching...", | ||||||
|  |         this.hidden = false, | ||||||
|  |         this.height = 40, | ||||||
|  |         this.contentPadding = EdgeInsets.zero, | ||||||
|  |         this.debounceMilliseconds, | ||||||
|  |         this.onSearchFailed, | ||||||
|  |         required this.searchBarController, | ||||||
|  |         this.autocompleteOffset, | ||||||
|  |         this.autocompleteRadius, | ||||||
|  |         this.autocompleteLanguage, | ||||||
|  |         this.autocompleteComponents, | ||||||
|  |         this.autocompleteTypes, | ||||||
|  |         this.strictbounds, | ||||||
|  |         this.region, | ||||||
|  |         this.initialSearchString, | ||||||
|  |         this.searchForInitialValue, | ||||||
|  |         this.autocompleteOnTrailingWhitespace}) | ||||||
|  |       : super(key: key); | ||||||
|  | 
 | ||||||
|  |   final String? sessionToken; | ||||||
|  |   final String? hintText; | ||||||
|  |   final String? searchingText; | ||||||
|  |   final bool hidden; | ||||||
|  |   final double height; | ||||||
|  |   final EdgeInsetsGeometry contentPadding; | ||||||
|  |   final int? debounceMilliseconds; | ||||||
|  |   final ValueChanged<Prediction> onPicked; | ||||||
|  |   final ValueChanged<String>? onSearchFailed; | ||||||
|  |   final SearchBarController searchBarController; | ||||||
|  |   final num? autocompleteOffset; | ||||||
|  |   final num? autocompleteRadius; | ||||||
|  |   final String? autocompleteLanguage; | ||||||
|  |   final List<String>? autocompleteTypes; | ||||||
|  |   final List<Component>? autocompleteComponents; | ||||||
|  |   final bool? strictbounds; | ||||||
|  |   final String? region; | ||||||
|  |   final GlobalKey appBarKey; | ||||||
|  |   final String? initialSearchString; | ||||||
|  |   final bool? searchForInitialValue; | ||||||
|  |   final bool? autocompleteOnTrailingWhitespace; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   AutoCompleteSearchState createState() => AutoCompleteSearchState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class AutoCompleteSearchState extends State<AutoCompleteSearch> { | ||||||
|  |   TextEditingController controller = TextEditingController(); | ||||||
|  |   FocusNode focus = FocusNode(); | ||||||
|  |   OverlayEntry? overlayEntry; | ||||||
|  |   SearchProvider provider = SearchProvider(); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     if (widget.initialSearchString != null) { | ||||||
|  |       WidgetsBinding.instance.addPostFrameCallback((_) { | ||||||
|  |         controller.text = widget.initialSearchString!; | ||||||
|  |         if (widget.searchForInitialValue!) { | ||||||
|  |           _onSearchInputChange(); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |     controller.addListener(_onSearchInputChange); | ||||||
|  |     focus.addListener(_onFocusChanged); | ||||||
|  | 
 | ||||||
|  |     widget.searchBarController.attach(this); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     controller.removeListener(_onSearchInputChange); | ||||||
|  |     controller.dispose(); | ||||||
|  | 
 | ||||||
|  |     focus.removeListener(_onFocusChanged); | ||||||
|  |     focus.dispose(); | ||||||
|  |     _clearOverlay(); | ||||||
|  | 
 | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return !widget.hidden | ||||||
|  |         ? ChangeNotifierProvider.value( | ||||||
|  |       value: provider, | ||||||
|  |       child: RoundedFrame( | ||||||
|  |         height: widget.height, | ||||||
|  |         padding: const EdgeInsets.only(right: 10), | ||||||
|  |         color: Theme.of(context).brightness == Brightness.dark | ||||||
|  |             ? Colors.black54 | ||||||
|  |             : Colors.white, | ||||||
|  |         borderRadius: BorderRadius.circular(20), | ||||||
|  |         elevation: 4.0, | ||||||
|  |         child: Row( | ||||||
|  |           children: <Widget>[ | ||||||
|  |             SizedBox(width: 10), | ||||||
|  |             Icon(Icons.search), | ||||||
|  |             SizedBox(width: 10), | ||||||
|  |             Expanded(child: _buildSearchTextField()), | ||||||
|  |             _buildTextClearIcon(), | ||||||
|  |           ], | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ) | ||||||
|  |         : Container(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildSearchTextField() { | ||||||
|  |     return TextField( | ||||||
|  |       controller: controller, | ||||||
|  |       focusNode: focus, | ||||||
|  |       decoration: InputDecoration( | ||||||
|  |         hintText: widget.hintText, | ||||||
|  |         border: InputBorder.none, | ||||||
|  |         errorBorder: InputBorder.none, | ||||||
|  |         enabledBorder: InputBorder.none, | ||||||
|  |         focusedBorder: InputBorder.none, | ||||||
|  |         disabledBorder: InputBorder.none, | ||||||
|  |         focusedErrorBorder: InputBorder.none, | ||||||
|  |         isDense: true, | ||||||
|  |         contentPadding: widget.contentPadding, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildTextClearIcon() { | ||||||
|  |     return Selector<SearchProvider, String>( | ||||||
|  |         selector: (_, provider) => provider.searchTerm, | ||||||
|  |         builder: (_, data, __) { | ||||||
|  |           if (data.length > 0) { | ||||||
|  |             return Padding( | ||||||
|  |               padding: const EdgeInsets.only(right: 8.0), | ||||||
|  |               child: GestureDetector( | ||||||
|  |                 child: Icon( | ||||||
|  |                   Icons.clear, | ||||||
|  |                   color: Theme.of(context).brightness == Brightness.dark | ||||||
|  |                       ? Colors.white | ||||||
|  |                       : Colors.black, | ||||||
|  |                 ), | ||||||
|  |                 onTap: () { | ||||||
|  |                   clearText(); | ||||||
|  |                 }, | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |           } else { | ||||||
|  |             return SizedBox(width: 10); | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _onSearchInputChange() { | ||||||
|  |     if (!mounted) return; | ||||||
|  |     this.provider.searchTerm = controller.text; | ||||||
|  | 
 | ||||||
|  |     PlaceProvider provider = PlaceProvider.of(context, listen: false); | ||||||
|  | 
 | ||||||
|  |     if (controller.text.isEmpty) { | ||||||
|  |       provider.debounceTimer?.cancel(); | ||||||
|  |       _searchPlace(controller.text); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (controller.text.trim() == this.provider.prevSearchTerm.trim()) { | ||||||
|  |       provider.debounceTimer?.cancel(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (!widget.autocompleteOnTrailingWhitespace! && | ||||||
|  |         controller.text.substring(controller.text.length - 1) == " ") { | ||||||
|  |       provider.debounceTimer?.cancel(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (provider.debounceTimer?.isActive ?? false) { | ||||||
|  |       provider.debounceTimer!.cancel(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     provider.debounceTimer = | ||||||
|  |         Timer(Duration(milliseconds: widget.debounceMilliseconds!), () { | ||||||
|  |           _searchPlace(controller.text.trim()); | ||||||
|  |         }); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _onFocusChanged() { | ||||||
|  |     PlaceProvider provider = PlaceProvider.of(context, listen: false); | ||||||
|  |     provider.isSearchBarFocused = focus.hasFocus; | ||||||
|  |     provider.debounceTimer?.cancel(); | ||||||
|  |     provider.placeSearchingState = SearchingState.Idle; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _searchPlace(String searchTerm) { | ||||||
|  |     this.provider.prevSearchTerm = searchTerm; | ||||||
|  | 
 | ||||||
|  |     _clearOverlay(); | ||||||
|  | 
 | ||||||
|  |     if (searchTerm.length < 1) return; | ||||||
|  | 
 | ||||||
|  |     _displayOverlay(_buildSearchingOverlay()); | ||||||
|  | 
 | ||||||
|  |     _performAutoCompleteSearch(searchTerm); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _clearOverlay() { | ||||||
|  |     if (overlayEntry != null) { | ||||||
|  |       overlayEntry!.remove(); | ||||||
|  |       overlayEntry = null; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _displayOverlay(Widget overlayChild) { | ||||||
|  |     _clearOverlay(); | ||||||
|  | 
 | ||||||
|  |     final RenderBox? appBarRenderBox = | ||||||
|  |     widget.appBarKey.currentContext!.findRenderObject() as RenderBox?; | ||||||
|  |     final translation = appBarRenderBox?.getTransformTo(null).getTranslation(); | ||||||
|  |     final Offset offset = translation != null | ||||||
|  |         ? Offset(translation.x, translation.y) | ||||||
|  |         : Offset(0.0, 0.0); | ||||||
|  |     final screenWidth = MediaQuery.of(context).size.width; | ||||||
|  | 
 | ||||||
|  |     overlayEntry = OverlayEntry( | ||||||
|  |       builder: (context) => Positioned( | ||||||
|  |         top: appBarRenderBox!.paintBounds.shift(offset).top + | ||||||
|  |             appBarRenderBox.size.height, | ||||||
|  |         left: screenWidth * 0.025, | ||||||
|  |         right: screenWidth * 0.025, | ||||||
|  |         child: Material( | ||||||
|  |           elevation: 4.0, | ||||||
|  |           child: overlayChild, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     Overlay.of(context)!.insert(overlayEntry!); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildSearchingOverlay() { | ||||||
|  |     return Container( | ||||||
|  |       padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), | ||||||
|  |       child: Row( | ||||||
|  |         children: <Widget>[ | ||||||
|  |           SizedBox( | ||||||
|  |             height: 24, | ||||||
|  |             width: 24, | ||||||
|  |             child: CircularProgressIndicator(strokeWidth: 3), | ||||||
|  |           ), | ||||||
|  |           SizedBox(width: 24), | ||||||
|  |           Expanded( | ||||||
|  |             child: Text( | ||||||
|  |               widget.searchingText ?? "Searching...", | ||||||
|  |               style: TextStyle(fontSize: 16), | ||||||
|  |             ), | ||||||
|  |           ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildPredictionOverlay(List<Prediction> predictions) { | ||||||
|  |     return ListBody( | ||||||
|  |       children: predictions | ||||||
|  |           .map( | ||||||
|  |             (p) => PredictionTile( | ||||||
|  |           prediction: p, | ||||||
|  |           onTap: (selectedPrediction) { | ||||||
|  |             resetSearchBar(); | ||||||
|  |             widget.onPicked(selectedPrediction); | ||||||
|  |           }, | ||||||
|  |         ), | ||||||
|  |       ) | ||||||
|  |           .toList(), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _performAutoCompleteSearch(String searchTerm) async { | ||||||
|  |     PlaceProvider provider = PlaceProvider.of(context, listen: false); | ||||||
|  | 
 | ||||||
|  |     if (searchTerm.isNotEmpty) { | ||||||
|  |       final PlacesAutocompleteResponse response = | ||||||
|  |       await provider.places.autocomplete( | ||||||
|  |         searchTerm, | ||||||
|  |         sessionToken: widget.sessionToken, | ||||||
|  |         location: provider.currentPosition == null | ||||||
|  |             ? null | ||||||
|  |             : Location( | ||||||
|  |             lat: provider.currentPosition!.latitude, | ||||||
|  |             lng: provider.currentPosition!.longitude), | ||||||
|  |         offset: widget.autocompleteOffset, | ||||||
|  |         radius: widget.autocompleteRadius, | ||||||
|  |         language: widget.autocompleteLanguage, | ||||||
|  |         types: widget.autocompleteTypes ?? const [], | ||||||
|  |         components: widget.autocompleteComponents ?? const [], | ||||||
|  |         strictbounds: widget.strictbounds ?? false, | ||||||
|  |         region: widget.region, | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |       if (response.errorMessage?.isNotEmpty == true || | ||||||
|  |           response.status == "REQUEST_DENIED") { | ||||||
|  |         if (widget.onSearchFailed != null) { | ||||||
|  |           widget.onSearchFailed!(response.status); | ||||||
|  |         } | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       _displayOverlay(_buildPredictionOverlay(response.predictions)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   clearText() { | ||||||
|  |     provider.searchTerm = ""; | ||||||
|  |     controller.clear(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   resetSearchBar() { | ||||||
|  |     clearText(); | ||||||
|  |     focus.unfocus(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   clearOverlay() { | ||||||
|  |     _clearOverlay(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,58 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | 
 | ||||||
|  | class AnimatedPin extends StatefulWidget { | ||||||
|  |   AnimatedPin({ | ||||||
|  |     Key? key, | ||||||
|  |     this.child, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   final Widget? child; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   _AnimatedPinState createState() => _AnimatedPinState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _AnimatedPinState extends State<AnimatedPin> | ||||||
|  |     with TickerProviderStateMixin { | ||||||
|  |   late AnimationController _controller; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     _controller = AnimationController( | ||||||
|  |       duration: const Duration(seconds: 1), | ||||||
|  |       vsync: this, | ||||||
|  |     )..repeat(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     _controller.dispose(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return JumpingContainer(controller: _controller, child: widget.child); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class JumpingContainer extends AnimatedWidget { | ||||||
|  |   const JumpingContainer({ | ||||||
|  |     Key? key, | ||||||
|  |     required AnimationController controller, | ||||||
|  |     this.child, | ||||||
|  |   }) : super(key: key, listenable: controller); | ||||||
|  | 
 | ||||||
|  |   final Widget? child; | ||||||
|  | 
 | ||||||
|  |   Animation<double> get _progress => listenable as Animation<double>; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Transform.translate( | ||||||
|  |       offset: Offset(0, -10 + _progress.value * 10), | ||||||
|  |       child: child, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/components/rounded_frame.dart'; | ||||||
|  | 
 | ||||||
|  | class FloatingCard extends StatelessWidget { | ||||||
|  |   const FloatingCard({ | ||||||
|  |     Key? key, | ||||||
|  |     this.topPosition, | ||||||
|  |     this.leftPosition, | ||||||
|  |     this.rightPosition, | ||||||
|  |     this.bottomPosition, | ||||||
|  |     this.width, | ||||||
|  |     this.height, | ||||||
|  |     this.borderRadius = BorderRadius.zero, | ||||||
|  |     this.elevation = 0.0, | ||||||
|  |     this.color, | ||||||
|  |     this.child, | ||||||
|  |   }) : super(key: key); | ||||||
|  | 
 | ||||||
|  |   final double? topPosition; | ||||||
|  |   final double? leftPosition; | ||||||
|  |   final double? bottomPosition; | ||||||
|  |   final double? rightPosition; | ||||||
|  |   final double? width; | ||||||
|  |   final double? height; | ||||||
|  |   final BorderRadius borderRadius; | ||||||
|  |   final double elevation; | ||||||
|  |   final Color? color; | ||||||
|  |   final Widget? child; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Positioned( | ||||||
|  |       top: topPosition, | ||||||
|  |       left: leftPosition, | ||||||
|  |       right: rightPosition, | ||||||
|  |       bottom: bottomPosition, | ||||||
|  |       child: RoundedFrame( | ||||||
|  |         width: width, | ||||||
|  |         height: height, | ||||||
|  |         borderRadius: borderRadius, | ||||||
|  |         elevation: elevation, | ||||||
|  |         color: color, | ||||||
|  |         child: child, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,81 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:google_maps_webservice/places.dart'; | ||||||
|  | 
 | ||||||
|  | class PredictionTile extends StatelessWidget { | ||||||
|  |   final Prediction prediction; | ||||||
|  |   final ValueChanged<Prediction>? onTap; | ||||||
|  | 
 | ||||||
|  |   PredictionTile({required this.prediction, this.onTap}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return ListTile( | ||||||
|  |       leading: Icon(Icons.location_on), | ||||||
|  |       title: RichText( | ||||||
|  |         text: TextSpan( | ||||||
|  |           children: _buildPredictionText(context), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |       onTap: () { | ||||||
|  |         if (onTap != null) { | ||||||
|  |           onTap!(prediction); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   List<TextSpan> _buildPredictionText(BuildContext context) { | ||||||
|  |     final List<TextSpan> result = <TextSpan>[]; | ||||||
|  |     final textColor = Theme.of(context).textTheme.bodyText2!.color; | ||||||
|  | 
 | ||||||
|  |     if (prediction.matchedSubstrings.length > 0) { | ||||||
|  |       MatchedSubstring matchedSubString = prediction.matchedSubstrings[0]; | ||||||
|  |       // There is no matched string at the beginning. | ||||||
|  |       if (matchedSubString.offset > 0) { | ||||||
|  |         result.add( | ||||||
|  |           TextSpan( | ||||||
|  |             text: prediction.description | ||||||
|  |                 ?.substring(0, matchedSubString.offset as int?), | ||||||
|  |             style: TextStyle( | ||||||
|  |                 color: textColor, fontSize: 16, fontWeight: FontWeight.w300), | ||||||
|  |           ), | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // Matched strings. | ||||||
|  |       result.add( | ||||||
|  |         TextSpan( | ||||||
|  |           text: prediction.description?.substring( | ||||||
|  |               matchedSubString.offset as int, | ||||||
|  |               matchedSubString.offset + matchedSubString.length as int?), | ||||||
|  |           style: TextStyle( | ||||||
|  |               color: textColor, fontSize: 16, fontWeight: FontWeight.w500), | ||||||
|  |         ), | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |       // Other strings. | ||||||
|  |       if (matchedSubString.offset + matchedSubString.length < | ||||||
|  |           (prediction.description?.length ?? 0)) { | ||||||
|  |         result.add( | ||||||
|  |           TextSpan( | ||||||
|  |             text: prediction.description?.substring( | ||||||
|  |                 matchedSubString.offset + matchedSubString.length as int), | ||||||
|  |             style: TextStyle( | ||||||
|  |                 color: textColor, fontSize: 16, fontWeight: FontWeight.w300), | ||||||
|  |           ), | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |       // If there is no matched strings, but there are predicts. (Not sure if this happens though) | ||||||
|  |     } else { | ||||||
|  |       result.add( | ||||||
|  |         TextSpan( | ||||||
|  |           text: prediction.description, | ||||||
|  |           style: TextStyle( | ||||||
|  |               color: textColor, fontSize: 16, fontWeight: FontWeight.w300), | ||||||
|  |         ), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return result; | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,51 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | 
 | ||||||
|  | class RoundedFrame extends StatelessWidget { | ||||||
|  |   const RoundedFrame({ | ||||||
|  |     Key? key, | ||||||
|  |     this.margin, | ||||||
|  |     this.padding, | ||||||
|  |     this.width, | ||||||
|  |     this.height, | ||||||
|  |     this.child, | ||||||
|  |     this.color, | ||||||
|  |     this.borderRadius = BorderRadius.zero, | ||||||
|  |     this.borderColor = Colors.transparent, | ||||||
|  |     this.elevation = 0.0, | ||||||
|  |     this.materialType, | ||||||
|  |   }) : super(key: key); | ||||||
|  | 
 | ||||||
|  |   final EdgeInsetsGeometry? margin; | ||||||
|  |   final EdgeInsetsGeometry? padding; | ||||||
|  |   final double? width; | ||||||
|  |   final double? height; | ||||||
|  |   final Widget? child; | ||||||
|  |   final Color? color; | ||||||
|  |   final Color borderColor; | ||||||
|  |   final BorderRadius borderRadius; | ||||||
|  |   final double elevation; | ||||||
|  |   final MaterialType? materialType; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Container( | ||||||
|  |       width: width, | ||||||
|  |       height: height, | ||||||
|  |       margin: margin, | ||||||
|  |       padding: padding, | ||||||
|  |       child: Material( | ||||||
|  |         type: color == Colors.transparent | ||||||
|  |             ? MaterialType.transparency | ||||||
|  |             : materialType ?? MaterialType.canvas, | ||||||
|  |         color: color, | ||||||
|  |         shape: RoundedRectangleBorder( | ||||||
|  |             borderRadius: borderRadius, side: BorderSide(color: borderColor)), | ||||||
|  |         elevation: elevation, | ||||||
|  |         child: ClipRRect( | ||||||
|  |           borderRadius: borderRadius, | ||||||
|  |           child: child, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,24 @@ | |||||||
|  | import 'package:flutter/cupertino.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/autocomplete_search.dart'; | ||||||
|  | 
 | ||||||
|  | class SearchBarController extends ChangeNotifier { | ||||||
|  |   late AutoCompleteSearchState _autoCompleteSearch; | ||||||
|  | 
 | ||||||
|  |   attach(AutoCompleteSearchState searchWidget) { | ||||||
|  |     _autoCompleteSearch = searchWidget; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Just clears text. | ||||||
|  |   clear() { | ||||||
|  |     _autoCompleteSearch.clearText(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /// Clear and remove focus (Dismiss keyboard) | ||||||
|  |   reset() { | ||||||
|  |     _autoCompleteSearch.resetSearchBar(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   clearOverlay() { | ||||||
|  |     _autoCompleteSearch.clearOverlay(); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,612 @@ | |||||||
|  | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/foundation.dart'; | ||||||
|  | import 'package:flutter/gestures.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:geolocator/geolocator.dart'; | ||||||
|  | import 'package:google_maps_flutter/google_maps_flutter.dart'; | ||||||
|  | import 'package:google_maps_webservice/geocoding.dart'; | ||||||
|  | import 'package:google_maps_webservice/places.dart'; | ||||||
|  | 
 | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  | import 'package:tuple/tuple.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/google_maps_place_picker.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/providers/place_provider.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/components/animated_pin.dart'; | ||||||
|  | 
 | ||||||
|  | typedef SelectedPlaceWidgetBuilder = Widget Function( | ||||||
|  |   BuildContext context, | ||||||
|  |   PickResult? selectedPlace, | ||||||
|  |   SearchingState state, | ||||||
|  |   bool isSearchBarFocused, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | typedef PinBuilder = Widget Function( | ||||||
|  |   BuildContext context, | ||||||
|  |   PinState state, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | class GoogleMapPlacePicker extends StatelessWidget { | ||||||
|  |   const GoogleMapPlacePicker({ | ||||||
|  |     Key? key, | ||||||
|  |     required this.initialTarget, | ||||||
|  |     required this.appBarKey, | ||||||
|  |     this.selectedPlaceWidgetBuilder, | ||||||
|  |     this.pinBuilder, | ||||||
|  |     this.onSearchFailed, | ||||||
|  |     this.onMoveStart, | ||||||
|  |     this.onMapCreated, | ||||||
|  |     this.debounceMilliseconds, | ||||||
|  |     this.enableMapTypeButton, | ||||||
|  |     this.enableMyLocationButton, | ||||||
|  |     this.onToggleMapType, | ||||||
|  |     this.onMyLocation, | ||||||
|  |     this.onPlacePicked, | ||||||
|  |     this.usePinPointingSearch, | ||||||
|  |     this.usePlaceDetailSearch, | ||||||
|  |     this.selectInitialPosition, | ||||||
|  |     this.language, | ||||||
|  |     this.pickArea, | ||||||
|  |     this.forceSearchOnZoomChanged, | ||||||
|  |     this.hidePlaceDetailsWhenDraggingPin, | ||||||
|  |     this.onCameraMoveStarted, | ||||||
|  |     this.onCameraMove, | ||||||
|  |     this.onCameraIdle, | ||||||
|  |     this.selectText, | ||||||
|  |     this.outsideOfPickAreaText, | ||||||
|  |     this.zoomGesturesEnabled = true, | ||||||
|  |     this.zoomControlsEnabled = false, | ||||||
|  |     this.fullMotion = false, | ||||||
|  |   }) : super(key: key); | ||||||
|  | 
 | ||||||
|  |   final LatLng initialTarget; | ||||||
|  |   final GlobalKey appBarKey; | ||||||
|  | 
 | ||||||
|  |   final SelectedPlaceWidgetBuilder? selectedPlaceWidgetBuilder; | ||||||
|  |   final PinBuilder? pinBuilder; | ||||||
|  | 
 | ||||||
|  |   final ValueChanged<String>? onSearchFailed; | ||||||
|  |   final VoidCallback? onMoveStart; | ||||||
|  |   final MapCreatedCallback? onMapCreated; | ||||||
|  |   final VoidCallback? onToggleMapType; | ||||||
|  |   final VoidCallback? onMyLocation; | ||||||
|  |   final ValueChanged<PickResult>? onPlacePicked; | ||||||
|  | 
 | ||||||
|  |   final int? debounceMilliseconds; | ||||||
|  |   final bool? enableMapTypeButton; | ||||||
|  |   final bool? enableMyLocationButton; | ||||||
|  | 
 | ||||||
|  |   final bool? usePinPointingSearch; | ||||||
|  |   final bool? usePlaceDetailSearch; | ||||||
|  | 
 | ||||||
|  |   final bool? selectInitialPosition; | ||||||
|  | 
 | ||||||
|  |   final String? language; | ||||||
|  |   final CircleArea? pickArea; | ||||||
|  | 
 | ||||||
|  |   final bool? forceSearchOnZoomChanged; | ||||||
|  |   final bool? hidePlaceDetailsWhenDraggingPin; | ||||||
|  | 
 | ||||||
|  |   /// GoogleMap pass-through events: | ||||||
|  |   final Function(PlaceProvider)? onCameraMoveStarted; | ||||||
|  |   final CameraPositionCallback? onCameraMove; | ||||||
|  |   final Function(PlaceProvider)? onCameraIdle; | ||||||
|  | 
 | ||||||
|  |   // strings | ||||||
|  |   final String? selectText; | ||||||
|  |   final String? outsideOfPickAreaText; | ||||||
|  | 
 | ||||||
|  |   /// Zoom feature toggle | ||||||
|  |   final bool zoomGesturesEnabled; | ||||||
|  |   final bool zoomControlsEnabled; | ||||||
|  | 
 | ||||||
|  |   /// Use never scrollable scroll-view with maximum dimensions to prevent unnecessary re-rendering. | ||||||
|  |   final bool fullMotion; | ||||||
|  | 
 | ||||||
|  |   _searchByCameraLocation(PlaceProvider provider) async { | ||||||
|  |     // We don't want to search location again if camera location is changed by zooming in/out. | ||||||
|  |     if (forceSearchOnZoomChanged == false && | ||||||
|  |         provider.prevCameraPosition != null && | ||||||
|  |         provider.prevCameraPosition!.target.latitude == | ||||||
|  |             provider.cameraPosition!.target.latitude && | ||||||
|  |         provider.prevCameraPosition!.target.longitude == | ||||||
|  |             provider.cameraPosition!.target.longitude) { | ||||||
|  |       provider.placeSearchingState = SearchingState.Idle; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     provider.placeSearchingState = SearchingState.Searching; | ||||||
|  | 
 | ||||||
|  |     final GeocodingResponse response = | ||||||
|  |         await provider.geocoding.searchByLocation( | ||||||
|  |       Location( | ||||||
|  |           lat: provider.cameraPosition!.target.latitude, | ||||||
|  |           lng: provider.cameraPosition!.target.longitude), | ||||||
|  |       language: language, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if (response.errorMessage?.isNotEmpty == true || | ||||||
|  |         response.status == "REQUEST_DENIED") { | ||||||
|  |       print("Camera Location Search Error: " + response.errorMessage!); | ||||||
|  |       if (onSearchFailed != null) { | ||||||
|  |         onSearchFailed!(response.status); | ||||||
|  |       } | ||||||
|  |       provider.placeSearchingState = SearchingState.Idle; | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (usePlaceDetailSearch!) { | ||||||
|  |       final PlacesDetailsResponse detailResponse = | ||||||
|  |           await provider.places.getDetailsByPlaceId( | ||||||
|  |         response.results[0].placeId, | ||||||
|  |         language: language, | ||||||
|  |       ); | ||||||
|  | 
 | ||||||
|  |       if (detailResponse.errorMessage?.isNotEmpty == true || | ||||||
|  |           detailResponse.status == "REQUEST_DENIED") { | ||||||
|  |         print("Fetching details by placeId Error: " + | ||||||
|  |             detailResponse.errorMessage!); | ||||||
|  |         if (onSearchFailed != null) { | ||||||
|  |           onSearchFailed!(detailResponse.status); | ||||||
|  |         } | ||||||
|  |         provider.placeSearchingState = SearchingState.Idle; | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       provider.selectedPlace = | ||||||
|  |           PickResult.fromPlaceDetailResult(detailResponse.result); | ||||||
|  |     } else { | ||||||
|  |       provider.selectedPlace = | ||||||
|  |           PickResult.fromGeocodingResult(response.results[0]); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     provider.placeSearchingState = SearchingState.Idle; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Stack( | ||||||
|  |       children: <Widget>[ | ||||||
|  |         if (this.fullMotion) | ||||||
|  |           SingleChildScrollView( | ||||||
|  |               physics: const NeverScrollableScrollPhysics(), | ||||||
|  |               child: SizedBox( | ||||||
|  |                   width: MediaQuery.of(context).size.width, | ||||||
|  |                   height: MediaQuery.of(context).size.height, | ||||||
|  |                   child: Stack( | ||||||
|  |                     alignment: AlignmentDirectional.center, | ||||||
|  |                     children: [ | ||||||
|  |                       _buildGoogleMap(context), | ||||||
|  |                       _buildPin(), | ||||||
|  |                     ], | ||||||
|  |                   ))), | ||||||
|  |         if (!this.fullMotion) _buildGoogleMap(context), | ||||||
|  |         if (!this.fullMotion) _buildPin(), | ||||||
|  |         _buildFloatingCard(), | ||||||
|  |         _buildMapIcons(context), | ||||||
|  |         _buildZoomButtons() | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildGoogleMapInner(PlaceProvider? provider, MapType mapType) { | ||||||
|  |     CameraPosition initialCameraPosition = | ||||||
|  |         CameraPosition(target: this.initialTarget, zoom: 15); | ||||||
|  |     return GoogleMap( | ||||||
|  |       zoomGesturesEnabled: this.zoomGesturesEnabled, | ||||||
|  |       zoomControlsEnabled: | ||||||
|  |           false, // we use our own implementation that supports iOS as well, see _buildZoomButtons() | ||||||
|  |       myLocationButtonEnabled: false, | ||||||
|  |       compassEnabled: false, | ||||||
|  |       mapToolbarEnabled: false, | ||||||
|  |       initialCameraPosition: initialCameraPosition, | ||||||
|  |       mapType: mapType, | ||||||
|  |       myLocationEnabled: true, | ||||||
|  |       circles: pickArea != null && pickArea!.radius > 0 | ||||||
|  |           ? Set<Circle>.from([pickArea]) | ||||||
|  |           : Set<Circle>(), | ||||||
|  |       onMapCreated: (GoogleMapController controller) { | ||||||
|  |         if (provider == null) return; | ||||||
|  |         provider.mapController = controller; | ||||||
|  |         provider.setCameraPosition(null); | ||||||
|  |         provider.pinState = PinState.Idle; | ||||||
|  | 
 | ||||||
|  |         // When select initialPosition set to true. | ||||||
|  |         if (selectInitialPosition!) { | ||||||
|  |           provider.setCameraPosition(initialCameraPosition); | ||||||
|  |           _searchByCameraLocation(provider); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (onMapCreated != null) { | ||||||
|  |           onMapCreated!(controller); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       onCameraIdle: () { | ||||||
|  |         if (provider == null) return; | ||||||
|  |         if (provider.isAutoCompleteSearching) { | ||||||
|  |           provider.isAutoCompleteSearching = false; | ||||||
|  |           provider.pinState = PinState.Idle; | ||||||
|  |           provider.placeSearchingState = SearchingState.Idle; | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Perform search only if the setting is to true. | ||||||
|  |         if (usePinPointingSearch!) { | ||||||
|  |           // Search current camera location only if camera has moved (dragged) before. | ||||||
|  |           if (provider.pinState == PinState.Dragging) { | ||||||
|  |             // Cancel previous timer. | ||||||
|  |             if (provider.debounceTimer?.isActive ?? false) { | ||||||
|  |               provider.debounceTimer!.cancel(); | ||||||
|  |             } | ||||||
|  |             provider.debounceTimer = | ||||||
|  |                 Timer(Duration(milliseconds: debounceMilliseconds!), () { | ||||||
|  |               _searchByCameraLocation(provider); | ||||||
|  |             }); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         provider.pinState = PinState.Idle; | ||||||
|  | 
 | ||||||
|  |         if (onCameraIdle != null) { | ||||||
|  |           onCameraIdle!(provider); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       onCameraMoveStarted: () { | ||||||
|  |         if (provider == null) return; | ||||||
|  |         if (onCameraMoveStarted != null) { | ||||||
|  |           onCameraMoveStarted!(provider); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         provider.setPrevCameraPosition(provider.cameraPosition); | ||||||
|  | 
 | ||||||
|  |         // Cancel any other timer. | ||||||
|  |         provider.debounceTimer?.cancel(); | ||||||
|  | 
 | ||||||
|  |         // Update state, dismiss keyboard and clear text. | ||||||
|  |         provider.pinState = PinState.Dragging; | ||||||
|  | 
 | ||||||
|  |         // Begins the search state if the hide details is enabled | ||||||
|  |         if (this.hidePlaceDetailsWhenDraggingPin!) { | ||||||
|  |           provider.placeSearchingState = SearchingState.Searching; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         onMoveStart!(); | ||||||
|  |       }, | ||||||
|  |       onCameraMove: (CameraPosition position) { | ||||||
|  |         if (provider == null) return; | ||||||
|  |         provider.setCameraPosition(position); | ||||||
|  |         if (onCameraMove != null) { | ||||||
|  |           onCameraMove!(position); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       // gestureRecognizers make it possible to navigate the map when it's a | ||||||
|  |       // child in a scroll view e.g ListView, SingleChildScrollView... | ||||||
|  |       gestureRecognizers: Set() | ||||||
|  |         ..add(Factory<EagerGestureRecognizer>(() => EagerGestureRecognizer())), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildGoogleMap(BuildContext context) { | ||||||
|  |     return Selector<PlaceProvider, MapType>( | ||||||
|  |         selector: (_, provider) => provider.mapType, | ||||||
|  |         builder: (_, data, __) => this._buildGoogleMapInner( | ||||||
|  |             PlaceProvider.of(context, listen: false), data)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildPin() { | ||||||
|  |     return Center( | ||||||
|  |       child: Selector<PlaceProvider, PinState>( | ||||||
|  |         selector: (_, provider) => provider.pinState, | ||||||
|  |         builder: (context, state, __) { | ||||||
|  |           if (pinBuilder == null) { | ||||||
|  |             return _defaultPinBuilder(context, state); | ||||||
|  |           } else { | ||||||
|  |             return Builder( | ||||||
|  |                 builder: (builderContext) => | ||||||
|  |                     pinBuilder!(builderContext, state)); | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _defaultPinBuilder(BuildContext context, PinState state) { | ||||||
|  |     if (state == PinState.Preparing) { | ||||||
|  |       return Container(); | ||||||
|  |     } else if (state == PinState.Idle) { | ||||||
|  |       return Stack( | ||||||
|  |         children: <Widget>[ | ||||||
|  |           Center( | ||||||
|  |             child: Column( | ||||||
|  |               mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |               children: <Widget>[ | ||||||
|  |                 Icon(Icons.place, size: 36, color: Colors.red), | ||||||
|  |                 SizedBox(height: 42), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           Center( | ||||||
|  |             child: Container( | ||||||
|  |               width: 5, | ||||||
|  |               height: 5, | ||||||
|  |               decoration: BoxDecoration( | ||||||
|  |                 color: Colors.black, | ||||||
|  |                 shape: BoxShape.circle, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ); | ||||||
|  |     } else { | ||||||
|  |       return Stack( | ||||||
|  |         children: <Widget>[ | ||||||
|  |           Center( | ||||||
|  |             child: Column( | ||||||
|  |               mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |               children: <Widget>[ | ||||||
|  |                 AnimatedPin( | ||||||
|  |                     child: Icon(Icons.place, size: 36, color: Colors.red)), | ||||||
|  |                 SizedBox(height: 42), | ||||||
|  |               ], | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |           Center( | ||||||
|  |             child: Container( | ||||||
|  |               width: 5, | ||||||
|  |               height: 5, | ||||||
|  |               decoration: BoxDecoration( | ||||||
|  |                 color: Colors.black, | ||||||
|  |                 shape: BoxShape.circle, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildFloatingCard() { | ||||||
|  |     return Selector<PlaceProvider, | ||||||
|  |         Tuple4<PickResult?, SearchingState, bool, PinState>>( | ||||||
|  |       selector: (_, provider) => Tuple4( | ||||||
|  |           provider.selectedPlace, | ||||||
|  |           provider.placeSearchingState, | ||||||
|  |           provider.isSearchBarFocused, | ||||||
|  |           provider.pinState), | ||||||
|  |       builder: (context, data, __) { | ||||||
|  |         if ((data.item1 == null && data.item2 == SearchingState.Idle) || | ||||||
|  |             data.item3 == true || | ||||||
|  |             data.item4 == PinState.Dragging && | ||||||
|  |                 this.hidePlaceDetailsWhenDraggingPin!) { | ||||||
|  |           return Container(); | ||||||
|  |         } else { | ||||||
|  |           if (selectedPlaceWidgetBuilder == null) { | ||||||
|  |             return _defaultPlaceWidgetBuilder(context, data.item1, data.item2); | ||||||
|  |           } else { | ||||||
|  |             return Builder( | ||||||
|  |                 builder: (builderContext) => selectedPlaceWidgetBuilder!( | ||||||
|  |                     builderContext, data.item1, data.item2, data.item3)); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildZoomButtons() { | ||||||
|  |     return Selector<PlaceProvider, Tuple2<GoogleMapController?, LatLng?>>( | ||||||
|  |       selector: (_, provider) => new Tuple2<GoogleMapController?, LatLng?>( | ||||||
|  |           provider.mapController, provider.cameraPosition?.target), | ||||||
|  |       builder: (context, data, __) { | ||||||
|  |         if (!this.zoomControlsEnabled || | ||||||
|  |             data.item1 == null || | ||||||
|  |             data.item2 == null) { | ||||||
|  |           return Container(); | ||||||
|  |         } else { | ||||||
|  |           return Positioned( | ||||||
|  |             bottom: 50, | ||||||
|  |             right: 10, | ||||||
|  |             child: Card( | ||||||
|  |               elevation: 4.0, | ||||||
|  |               child: Container( | ||||||
|  |                 width: 40, | ||||||
|  |                 height: 100, | ||||||
|  |                 child: Column( | ||||||
|  |                   children: <Widget>[ | ||||||
|  |                     IconButton( | ||||||
|  |                         icon: Icon(Icons.add), | ||||||
|  |                         onPressed: () async { | ||||||
|  |                           double currentZoomLevel = | ||||||
|  |                               await data.item1!.getZoomLevel(); | ||||||
|  |                           currentZoomLevel = currentZoomLevel + 2; | ||||||
|  |                           data.item1!.animateCamera( | ||||||
|  |                             CameraUpdate.newCameraPosition( | ||||||
|  |                               CameraPosition( | ||||||
|  |                                 target: data.item2!, | ||||||
|  |                                 zoom: currentZoomLevel, | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                           ); | ||||||
|  |                         }), | ||||||
|  |                     SizedBox(height: 2), | ||||||
|  |                     IconButton( | ||||||
|  |                         icon: Icon(Icons.remove), | ||||||
|  |                         onPressed: () async { | ||||||
|  |                           double currentZoomLevel = | ||||||
|  |                               await data.item1!.getZoomLevel(); | ||||||
|  |                           currentZoomLevel = currentZoomLevel - 2; | ||||||
|  |                           if (currentZoomLevel < 0) currentZoomLevel = 0; | ||||||
|  |                           data.item1!.animateCamera( | ||||||
|  |                             CameraUpdate.newCameraPosition( | ||||||
|  |                               CameraPosition( | ||||||
|  |                                 target: data.item2!, | ||||||
|  |                                 zoom: currentZoomLevel, | ||||||
|  |                               ), | ||||||
|  |                             ), | ||||||
|  |                           ); | ||||||
|  |                         }), | ||||||
|  |                   ], | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _defaultPlaceWidgetBuilder( | ||||||
|  |       BuildContext context, PickResult? data, SearchingState state) { | ||||||
|  |     return FloatingCard( | ||||||
|  |       bottomPosition: MediaQuery.of(context).size.height * 0.1, | ||||||
|  |       leftPosition: MediaQuery.of(context).size.width * 0.15, | ||||||
|  |       rightPosition: MediaQuery.of(context).size.width * 0.15, | ||||||
|  |       width: MediaQuery.of(context).size.width * 0.7, | ||||||
|  |       borderRadius: BorderRadius.circular(12.0), | ||||||
|  |       elevation: 4.0, | ||||||
|  |       color: Theme.of(context).cardColor, | ||||||
|  |       child: state == SearchingState.Searching | ||||||
|  |           ? _buildLoadingIndicator() | ||||||
|  |           : _buildSelectionDetails(context, data!), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildLoadingIndicator() { | ||||||
|  |     return Container( | ||||||
|  |       height: 48, | ||||||
|  |       child: const Center( | ||||||
|  |         child: SizedBox( | ||||||
|  |           width: 24, | ||||||
|  |           height: 24, | ||||||
|  |           child: CircularProgressIndicator(), | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildSelectionDetails(BuildContext context, PickResult result) { | ||||||
|  |     bool canBePicked = pickArea == null || | ||||||
|  |         pickArea!.radius <= 0 || | ||||||
|  |         Geolocator.distanceBetween( | ||||||
|  |                 pickArea!.center.latitude, | ||||||
|  |                 pickArea!.center.longitude, | ||||||
|  |                 result.geometry!.location.lat, | ||||||
|  |                 result.geometry!.location.lng) <= | ||||||
|  |             pickArea!.radius; | ||||||
|  |     MaterialStateColor buttonColor = MaterialStateColor.resolveWith( | ||||||
|  |         (states) => canBePicked ? Colors.lightGreen : Colors.red); | ||||||
|  |     return Container( | ||||||
|  |       margin: EdgeInsets.all(10), | ||||||
|  |       child: Column( | ||||||
|  |         children: <Widget>[ | ||||||
|  |           Text( | ||||||
|  |             result.types!.length==1? | ||||||
|  |             result.formattedAddress!:result.name!+', '+result.formattedAddress!, | ||||||
|  |             style: TextStyle(fontSize: 18), | ||||||
|  |             textAlign: TextAlign.center, | ||||||
|  |           ), | ||||||
|  |           SizedBox(height: 10), | ||||||
|  |           (canBePicked && (selectText?.isEmpty ?? true)) || | ||||||
|  |                   (!canBePicked && (outsideOfPickAreaText?.isEmpty ?? true)) | ||||||
|  |               ? SizedBox.fromSize( | ||||||
|  |                   size: Size(56, 56), // button width and height | ||||||
|  |                   child: ClipOval( | ||||||
|  |                     child: Material( | ||||||
|  |                       child: InkWell( | ||||||
|  |                           overlayColor: buttonColor, | ||||||
|  |                           onTap: () { | ||||||
|  |                             if (canBePicked) { | ||||||
|  |                               onPlacePicked!(result); | ||||||
|  |                             } | ||||||
|  |                           }, | ||||||
|  |                           child: Icon( | ||||||
|  |                               canBePicked | ||||||
|  |                                   ? Icons.check_sharp | ||||||
|  |                                   : Icons.app_blocking_sharp, | ||||||
|  |                               color: buttonColor)), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ) | ||||||
|  |               : SizedBox.fromSize( | ||||||
|  |                   size: Size(MediaQuery.of(context).size.width * 0.8, | ||||||
|  |                       56), // button width and height | ||||||
|  |                   child: ClipRRect( | ||||||
|  |                     borderRadius: BorderRadius.circular(10.0), | ||||||
|  |                     child: Material( | ||||||
|  |                       child: InkWell( | ||||||
|  |                           overlayColor: buttonColor, | ||||||
|  |                           onTap: () { | ||||||
|  |                             if (canBePicked) { | ||||||
|  |                               onPlacePicked!(result); | ||||||
|  |                             } | ||||||
|  |                           }, | ||||||
|  |                           child: Row( | ||||||
|  |                             mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |                             children: [ | ||||||
|  |                               Icon( | ||||||
|  |                                   canBePicked | ||||||
|  |                                       ? Icons.check_sharp | ||||||
|  |                                       : Icons.app_blocking_sharp, | ||||||
|  |                                   color: buttonColor), | ||||||
|  |                               SizedBox.fromSize(size: new Size(10, 0)), | ||||||
|  |                               Text( | ||||||
|  |                                   canBePicked | ||||||
|  |                                       ? selectText! | ||||||
|  |                                       : outsideOfPickAreaText!, | ||||||
|  |                                   style: TextStyle(color: buttonColor)) | ||||||
|  |                             ], | ||||||
|  |                           )), | ||||||
|  |                     ), | ||||||
|  |                   ), | ||||||
|  |                 ) | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildMapIcons(BuildContext context) { | ||||||
|  |     if (appBarKey.currentContext == null) { | ||||||
|  |       return Container(); | ||||||
|  |     } | ||||||
|  |     final RenderBox appBarRenderBox = | ||||||
|  |         appBarKey.currentContext!.findRenderObject() as RenderBox; | ||||||
|  |     return Positioned( | ||||||
|  |       top: appBarRenderBox.size.height, | ||||||
|  |       right: 15, | ||||||
|  |       child: Column( | ||||||
|  |         children: <Widget>[ | ||||||
|  |           enableMapTypeButton! | ||||||
|  |               ? Container( | ||||||
|  |                   width: 35, | ||||||
|  |                   height: 35, | ||||||
|  |                   child: RawMaterialButton( | ||||||
|  |                     shape: CircleBorder(), | ||||||
|  |                     fillColor: Theme.of(context).brightness == Brightness.dark | ||||||
|  |                         ? Colors.black54 | ||||||
|  |                         : Colors.white, | ||||||
|  |                     elevation: 4.0, | ||||||
|  |                     onPressed: onToggleMapType, | ||||||
|  |                     child: Icon(Icons.layers), | ||||||
|  |                   ), | ||||||
|  |                 ) | ||||||
|  |               : Container(), | ||||||
|  |           SizedBox(height: 10), | ||||||
|  |           enableMyLocationButton! | ||||||
|  |               ? Container( | ||||||
|  |                   width: 35, | ||||||
|  |                   height: 35, | ||||||
|  |                   child: RawMaterialButton( | ||||||
|  |                     shape: CircleBorder(), | ||||||
|  |                     fillColor: Theme.of(context).brightness == Brightness.dark | ||||||
|  |                         ? Colors.black54 | ||||||
|  |                         : Colors.white, | ||||||
|  |                     elevation: 4.0, | ||||||
|  |                     onPressed: onMyLocation, | ||||||
|  |                     child: Icon(Icons.my_location), | ||||||
|  |                   ), | ||||||
|  |                 ) | ||||||
|  |               : Container(), | ||||||
|  |         ], | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | import 'dart:ui'; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:google_maps_flutter/google_maps_flutter.dart'; | ||||||
|  | import 'package:uuid/uuid.dart'; | ||||||
|  | 
 | ||||||
|  | class CircleArea extends Circle { | ||||||
|  |   CircleArea({ | ||||||
|  |     required LatLng center, | ||||||
|  |     required double radius, | ||||||
|  |     Color? fillColor, | ||||||
|  |     Color? strokeColor, | ||||||
|  |     int strokeWidth = 2, | ||||||
|  |   }) : super( | ||||||
|  |           circleId: CircleId(Uuid().v4()), | ||||||
|  |           center: center, | ||||||
|  |           radius: radius, | ||||||
|  |           fillColor: fillColor ?? Colors.blue.withAlpha(32), | ||||||
|  |           strokeColor: strokeColor ?? Colors.blue.withAlpha(192), | ||||||
|  |           strokeWidth: strokeWidth, | ||||||
|  |         ); | ||||||
|  | } | ||||||
| @ -0,0 +1,91 @@ | |||||||
|  | import 'package:google_maps_webservice/geocoding.dart'; | ||||||
|  | import 'package:google_maps_webservice/places.dart'; | ||||||
|  | 
 | ||||||
|  | class PickResult { | ||||||
|  |   PickResult({ | ||||||
|  |     this.placeId, | ||||||
|  |     this.geometry, | ||||||
|  |     this.formattedAddress, | ||||||
|  |     this.types, | ||||||
|  |     this.addressComponents, | ||||||
|  |     this.adrAddress, | ||||||
|  |     this.formattedPhoneNumber, | ||||||
|  |     this.id, | ||||||
|  |     this.reference, | ||||||
|  |     this.icon, | ||||||
|  |     this.name, | ||||||
|  |     this.openingHours, | ||||||
|  |     this.photos, | ||||||
|  |     this.internationalPhoneNumber, | ||||||
|  |     this.priceLevel, | ||||||
|  |     this.rating, | ||||||
|  |     this.scope, | ||||||
|  |     this.url, | ||||||
|  |     this.vicinity, | ||||||
|  |     this.utcOffset, | ||||||
|  |     this.website, | ||||||
|  |     this.reviews, | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   final String? placeId; | ||||||
|  |   final Geometry? geometry; | ||||||
|  |   final String? formattedAddress; | ||||||
|  |   final List<String>? types; | ||||||
|  |   final List<AddressComponent>? addressComponents; | ||||||
|  | 
 | ||||||
|  |   // Below results will not be fetched if 'usePlaceDetailSearch' is set to false (Defaults to false). | ||||||
|  |   final String? adrAddress; | ||||||
|  |   final String? formattedPhoneNumber; | ||||||
|  |   final String? id; | ||||||
|  |   final String? reference; | ||||||
|  |   final String? icon; | ||||||
|  |   final String? name; | ||||||
|  |   final OpeningHoursDetail? openingHours; | ||||||
|  |   final List<Photo>? photos; | ||||||
|  |   final String? internationalPhoneNumber; | ||||||
|  |   final PriceLevel? priceLevel; | ||||||
|  |   final num? rating; | ||||||
|  |   final String? scope; | ||||||
|  |   final String? url; | ||||||
|  |   final String? vicinity; | ||||||
|  |   final num? utcOffset; | ||||||
|  |   final String? website; | ||||||
|  |   final List<Review>? reviews; | ||||||
|  | 
 | ||||||
|  |   factory PickResult.fromGeocodingResult(GeocodingResult result) { | ||||||
|  |     return PickResult( | ||||||
|  |       placeId: result.placeId, | ||||||
|  |       geometry: result.geometry, | ||||||
|  |       formattedAddress: result.formattedAddress, | ||||||
|  |       types: result.types, | ||||||
|  |       addressComponents: result.addressComponents, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   factory PickResult.fromPlaceDetailResult(PlaceDetails result) { | ||||||
|  |     return PickResult( | ||||||
|  |       placeId: result.placeId, | ||||||
|  |       geometry: result.geometry, | ||||||
|  |       formattedAddress: result.formattedAddress, | ||||||
|  |       types: result.types, | ||||||
|  |       addressComponents: result.addressComponents, | ||||||
|  |       adrAddress: result.adrAddress, | ||||||
|  |       formattedPhoneNumber: result.formattedPhoneNumber, | ||||||
|  |       id: result.id, | ||||||
|  |       reference: result.reference, | ||||||
|  |       icon: result.icon, | ||||||
|  |       name: result.name, | ||||||
|  |       openingHours: result.openingHours, | ||||||
|  |       photos: result.photos, | ||||||
|  |       internationalPhoneNumber: result.internationalPhoneNumber, | ||||||
|  |       priceLevel: result.priceLevel, | ||||||
|  |       rating: result.rating, | ||||||
|  |       scope: result.scope, | ||||||
|  |       url: result.url, | ||||||
|  |       vicinity: result.vicinity, | ||||||
|  |       utcOffset: result.utcOffset, | ||||||
|  |       website: result.website, | ||||||
|  |       reviews: result.reviews, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,535 @@ | |||||||
|  | import 'dart:async'; | ||||||
|  | import 'dart:io' show Platform; | ||||||
|  | 
 | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:geolocator/geolocator.dart'; | ||||||
|  | import 'package:google_api_headers/google_api_headers.dart'; | ||||||
|  | import 'package:google_maps_flutter/google_maps_flutter.dart'; | ||||||
|  | import 'package:google_maps_webservice/places.dart'; | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | 
 | ||||||
|  | import 'package:provider/provider.dart'; | ||||||
|  | import 'package:uuid/uuid.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/google_maps_place_picker.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/providers/place_provider.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/autocomplete_search.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/controllers/autocomplete_search_controller.dart'; | ||||||
|  | import 'package:healthcare_user/google_maps_place_picker_mb/src/google_map_place_picker.dart'; | ||||||
|  | 
 | ||||||
|  | typedef IntroModalWidgetBuilder = Widget Function( | ||||||
|  |   BuildContext context, | ||||||
|  |   Function? close, | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | enum PinState { Preparing, Idle, Dragging } | ||||||
|  | 
 | ||||||
|  | enum SearchingState { Idle, Searching } | ||||||
|  | 
 | ||||||
|  | class PlacePicker extends StatefulWidget { | ||||||
|  |   const PlacePicker({ | ||||||
|  |     Key? key, | ||||||
|  |     required this.apiKey, | ||||||
|  |     this.onPlacePicked, | ||||||
|  |     required this.initialPosition, | ||||||
|  |     this.useCurrentLocation, | ||||||
|  |     this.desiredLocationAccuracy = LocationAccuracy.high, | ||||||
|  |     this.onMapCreated, | ||||||
|  |     this.hintText, | ||||||
|  |     this.searchingText, | ||||||
|  |     this.selectText, | ||||||
|  |     this.outsideOfPickAreaText, | ||||||
|  |     this.onAutoCompleteFailed, | ||||||
|  |     this.onGeocodingSearchFailed, | ||||||
|  |     this.proxyBaseUrl, | ||||||
|  |     this.httpClient, | ||||||
|  |     this.selectedPlaceWidgetBuilder, | ||||||
|  |     this.pinBuilder, | ||||||
|  |     this.introModalWidgetBuilder, | ||||||
|  |     this.autoCompleteDebounceInMilliseconds = 500, | ||||||
|  |     this.cameraMoveDebounceInMilliseconds = 750, | ||||||
|  |     this.initialMapType = MapType.normal, | ||||||
|  |     this.enableMapTypeButton = true, | ||||||
|  |     this.enableMyLocationButton = true, | ||||||
|  |     this.myLocationButtonCooldown = 10, | ||||||
|  |     this.usePinPointingSearch = true, | ||||||
|  |     this.usePlaceDetailSearch = false, | ||||||
|  |     this.autocompleteOffset, | ||||||
|  |     this.autocompleteRadius, | ||||||
|  |     this.autocompleteLanguage, | ||||||
|  |     this.autocompleteComponents, | ||||||
|  |     this.autocompleteTypes, | ||||||
|  |     this.strictbounds, | ||||||
|  |     this.region, | ||||||
|  |     this.pickArea, | ||||||
|  |     this.selectInitialPosition = false, | ||||||
|  |     this.resizeToAvoidBottomInset = true, | ||||||
|  |     this.initialSearchString, | ||||||
|  |     this.searchForInitialValue = false, | ||||||
|  |     this.forceAndroidLocationManager = false, | ||||||
|  |     this.forceSearchOnZoomChanged = false, | ||||||
|  |     this.automaticallyImplyAppBarLeading = true, | ||||||
|  |     this.autocompleteOnTrailingWhitespace = false, | ||||||
|  |     this.hidePlaceDetailsWhenDraggingPin = true, | ||||||
|  |     this.onTapBack, | ||||||
|  |     this.onCameraMoveStarted, | ||||||
|  |     this.onCameraMove, | ||||||
|  |     this.onCameraIdle, | ||||||
|  |     this.onMapTypeChanged, | ||||||
|  |     this.zoomGesturesEnabled = true, | ||||||
|  |     this.zoomControlsEnabled = false, | ||||||
|  |   }) : super(key: key); | ||||||
|  | 
 | ||||||
|  |   final String apiKey; | ||||||
|  | 
 | ||||||
|  |   final LatLng initialPosition; | ||||||
|  |   final bool? useCurrentLocation; | ||||||
|  |   final LocationAccuracy desiredLocationAccuracy; | ||||||
|  | 
 | ||||||
|  |   final String? hintText; | ||||||
|  |   final String? searchingText; | ||||||
|  |   final String? selectText; | ||||||
|  |   final String? outsideOfPickAreaText; | ||||||
|  | 
 | ||||||
|  |   final ValueChanged<String>? onAutoCompleteFailed; | ||||||
|  |   final ValueChanged<String>? onGeocodingSearchFailed; | ||||||
|  |   final int autoCompleteDebounceInMilliseconds; | ||||||
|  |   final int cameraMoveDebounceInMilliseconds; | ||||||
|  | 
 | ||||||
|  |   final MapType initialMapType; | ||||||
|  |   final bool enableMapTypeButton; | ||||||
|  |   final bool enableMyLocationButton; | ||||||
|  |   final int myLocationButtonCooldown; | ||||||
|  | 
 | ||||||
|  |   final bool usePinPointingSearch; | ||||||
|  |   final bool usePlaceDetailSearch; | ||||||
|  | 
 | ||||||
|  |   final num? autocompleteOffset; | ||||||
|  |   final num? autocompleteRadius; | ||||||
|  |   final String? autocompleteLanguage; | ||||||
|  |   final List<String>? autocompleteTypes; | ||||||
|  |   final List<Component>? autocompleteComponents; | ||||||
|  |   final bool? strictbounds; | ||||||
|  |   final String? region; | ||||||
|  | 
 | ||||||
|  |   /// If set the picker can only pick addresses in the given circle area. | ||||||
|  |   /// The section will be highlighted. | ||||||
|  |   final CircleArea? pickArea; | ||||||
|  | 
 | ||||||
|  |   /// If true the [body] and the scaffold's floating widgets should size | ||||||
|  |   /// themselves to avoid the onscreen keyboard whose height is defined by the | ||||||
|  |   /// ambient [MediaQuery]'s [MediaQueryData.viewInsets] `bottom` property. | ||||||
|  |   /// | ||||||
|  |   /// For example, if there is an onscreen keyboard displayed above the | ||||||
|  |   /// scaffold, the body can be resized to avoid overlapping the keyboard, which | ||||||
|  |   /// prevents widgets inside the body from being obscured by the keyboard. | ||||||
|  |   /// | ||||||
|  |   /// Defaults to true. | ||||||
|  |   final bool resizeToAvoidBottomInset; | ||||||
|  | 
 | ||||||
|  |   final bool selectInitialPosition; | ||||||
|  | 
 | ||||||
|  |   /// By using default setting of Place Picker, it will result result when user hits the select here button. | ||||||
|  |   /// | ||||||
|  |   /// If you managed to use your own [selectedPlaceWidgetBuilder], then this WILL NOT be invoked, and you need use data which is | ||||||
|  |   /// being sent with [selectedPlaceWidgetBuilder]. | ||||||
|  |   final ValueChanged<PickResult>? onPlacePicked; | ||||||
|  | 
 | ||||||
|  |   /// optional - builds selected place's UI | ||||||
|  |   /// | ||||||
|  |   /// It is provided by default if you leave it as a null. | ||||||
|  |   /// INPORTANT: If this is non-null, [onPlacePicked] will not be invoked, as there will be no default 'Select here' button. | ||||||
|  |   final SelectedPlaceWidgetBuilder? selectedPlaceWidgetBuilder; | ||||||
|  | 
 | ||||||
|  |   /// optional - builds customized pin widget which indicates current pointing position. | ||||||
|  |   /// | ||||||
|  |   /// It is provided by default if you leave it as a null. | ||||||
|  |   final PinBuilder? pinBuilder; | ||||||
|  | 
 | ||||||
|  |   /// optional - builds customized introduction panel. | ||||||
|  |   /// | ||||||
|  |   /// None is provided / the map is instantly accessible if you leave it as a null. | ||||||
|  |   final IntroModalWidgetBuilder? introModalWidgetBuilder; | ||||||
|  | 
 | ||||||
|  |   /// optional - sets 'proxy' value in google_maps_webservice | ||||||
|  |   /// | ||||||
|  |   /// In case of using a proxy the baseUrl can be set. | ||||||
|  |   /// The apiKey is not required in case the proxy sets it. | ||||||
|  |   /// (Not storing the apiKey in the app is good practice) | ||||||
|  |   final String? proxyBaseUrl; | ||||||
|  | 
 | ||||||
|  |   /// optional - set 'client' value in google_maps_webservice | ||||||
|  |   /// | ||||||
|  |   /// In case of using a proxy url that requires authentication | ||||||
|  |   /// or custom configuration | ||||||
|  |   final BaseClient? httpClient; | ||||||
|  | 
 | ||||||
|  |   /// Initial value of autocomplete search | ||||||
|  |   final String? initialSearchString; | ||||||
|  | 
 | ||||||
|  |   /// Whether to search for the initial value or not | ||||||
|  |   final bool searchForInitialValue; | ||||||
|  | 
 | ||||||
|  |   /// On Android devices you can set [forceAndroidLocationManager] | ||||||
|  |   /// to true to force the plugin to use the [LocationManager] to determine the | ||||||
|  |   /// position instead of the [FusedLocationProviderClient]. On iOS this is ignored. | ||||||
|  |   final bool forceAndroidLocationManager; | ||||||
|  | 
 | ||||||
|  |   /// Allow searching place when zoom has changed. By default searching is disabled when zoom has changed in order to prevent unwilling API usage. | ||||||
|  |   final bool forceSearchOnZoomChanged; | ||||||
|  | 
 | ||||||
|  |   /// Whether to display appbar backbutton. Defaults to true. | ||||||
|  |   final bool automaticallyImplyAppBarLeading; | ||||||
|  | 
 | ||||||
|  |   /// Will perform an autocomplete search, if set to true. Note that setting | ||||||
|  |   /// this to true, while providing a smoother UX experience, may cause | ||||||
|  |   /// additional unnecessary queries to the Places API. | ||||||
|  |   /// | ||||||
|  |   /// Defaults to false. | ||||||
|  |   final bool autocompleteOnTrailingWhitespace; | ||||||
|  | 
 | ||||||
|  |   final bool hidePlaceDetailsWhenDraggingPin; | ||||||
|  | 
 | ||||||
|  |   // Raised when clicking on the back arrow. | ||||||
|  |   // This will not listen for the system back button on Android devices. | ||||||
|  |   // If this is not set, but the back button is visible through automaticallyImplyLeading, | ||||||
|  |   // the Navigator will try to pop instead. | ||||||
|  |   final VoidCallback? onTapBack; | ||||||
|  | 
 | ||||||
|  |   /// GoogleMap pass-through events: | ||||||
|  | 
 | ||||||
|  |   /// Callback method for when the map is ready to be used. | ||||||
|  |   /// | ||||||
|  |   /// Used to receive a [GoogleMapController] for this [GoogleMap]. | ||||||
|  |   final MapCreatedCallback? onMapCreated; | ||||||
|  | 
 | ||||||
|  |   /// Called when the camera starts moving. | ||||||
|  |   /// | ||||||
|  |   /// This can be initiated by the following: | ||||||
|  |   /// 1. Non-gesture animation initiated in response to user actions. | ||||||
|  |   ///    For example: zoom buttons, my location button, or marker clicks. | ||||||
|  |   /// 2. Programmatically initiated animation. | ||||||
|  |   /// 3. Camera motion initiated in response to user gestures on the map. | ||||||
|  |   ///    For example: pan, tilt, pinch to zoom, or rotate. | ||||||
|  |   final Function(PlaceProvider)? onCameraMoveStarted; | ||||||
|  | 
 | ||||||
|  |   /// Called repeatedly as the camera continues to move after an | ||||||
|  |   /// onCameraMoveStarted call. | ||||||
|  |   /// | ||||||
|  |   /// This may be called as often as once every frame and should | ||||||
|  |   /// not perform expensive operations. | ||||||
|  |   final CameraPositionCallback? onCameraMove; | ||||||
|  | 
 | ||||||
|  |   /// Called when camera movement has ended, there are no pending | ||||||
|  |   /// animations and the user has stopped interacting with the map. | ||||||
|  |   final Function(PlaceProvider)? onCameraIdle; | ||||||
|  | 
 | ||||||
|  |   /// Called when the map type has been changed. | ||||||
|  |   final Function(MapType)? onMapTypeChanged; | ||||||
|  | 
 | ||||||
|  |   /// Allow user to make visible the zoom button & toggle on & off zoom gestures | ||||||
|  |   final bool zoomGesturesEnabled; | ||||||
|  |   final bool zoomControlsEnabled; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   _PlacePickerState createState() => _PlacePickerState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _PlacePickerState extends State<PlacePicker> { | ||||||
|  |   GlobalKey appBarKey = GlobalKey(); | ||||||
|  |   late final Future<PlaceProvider> _futureProvider; | ||||||
|  |   PlaceProvider? provider; | ||||||
|  |   SearchBarController searchBarController = SearchBarController(); | ||||||
|  |   bool showIntroModal = true; | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  | 
 | ||||||
|  |     _futureProvider = _initPlaceProvider(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     searchBarController.dispose(); | ||||||
|  | 
 | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Future<PlaceProvider> _initPlaceProvider() async { | ||||||
|  |     final headers = await const GoogleApiHeaders().getHeaders(); | ||||||
|  |     final provider = PlaceProvider( | ||||||
|  |       widget.apiKey, | ||||||
|  |       widget.proxyBaseUrl, | ||||||
|  |       widget.httpClient, | ||||||
|  |       headers, | ||||||
|  |     ); | ||||||
|  |     provider.sessionToken = const Uuid().v4(); | ||||||
|  |     provider.desiredAccuracy = widget.desiredLocationAccuracy; | ||||||
|  |     provider.setMapType(widget.initialMapType); | ||||||
|  |     if (widget.useCurrentLocation != null && widget.useCurrentLocation!) { | ||||||
|  |       await provider.updateCurrentLocation(widget.forceAndroidLocationManager); | ||||||
|  |     } | ||||||
|  |     return provider; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return WillPopScope( | ||||||
|  |         onWillPop: () { | ||||||
|  |           searchBarController.clearOverlay(); | ||||||
|  |           return Future.value(true); | ||||||
|  |         }, | ||||||
|  |         child: FutureBuilder<PlaceProvider>( | ||||||
|  |           future: _futureProvider, | ||||||
|  |           builder: (context, snapshot) { | ||||||
|  |             if (snapshot.connectionState == ConnectionState.waiting) { | ||||||
|  |               return const Center(child: CircularProgressIndicator()); | ||||||
|  |             } else if (snapshot.hasData) { | ||||||
|  |               provider = snapshot.data; | ||||||
|  | 
 | ||||||
|  |               return MultiProvider( | ||||||
|  |                 providers: [ | ||||||
|  |                   ChangeNotifierProvider<PlaceProvider>.value(value: provider!), | ||||||
|  |                 ], | ||||||
|  |                 child: Stack(children: [ | ||||||
|  |                   Scaffold( | ||||||
|  |                     key: ValueKey<int>(provider.hashCode), | ||||||
|  |                     resizeToAvoidBottomInset: widget.resizeToAvoidBottomInset, | ||||||
|  |                     extendBodyBehindAppBar: true, | ||||||
|  |                     appBar: AppBar( | ||||||
|  |                       key: appBarKey, | ||||||
|  |                       automaticallyImplyLeading: false, | ||||||
|  |                       iconTheme: Theme.of(context).iconTheme, | ||||||
|  |                       elevation: 0, | ||||||
|  |                       backgroundColor: Colors.transparent, | ||||||
|  |                       titleSpacing: 0.0, | ||||||
|  |                       title: _buildSearchBar(context), | ||||||
|  |                     ), | ||||||
|  |                     body: _buildMapWithLocation(), | ||||||
|  |                   ), | ||||||
|  |                   _buildIntroModal(context), | ||||||
|  |                 ]), | ||||||
|  |               ); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             final children = <Widget>[]; | ||||||
|  |             if (snapshot.hasError) { | ||||||
|  |               children.addAll([ | ||||||
|  |                 Icon( | ||||||
|  |                   Icons.error_outline, | ||||||
|  |                   color: Theme.of(context).errorColor, | ||||||
|  |                 ), | ||||||
|  |                 Padding( | ||||||
|  |                   padding: const EdgeInsets.only(top: 16), | ||||||
|  |                   child: Text('Error: ${snapshot.error}'), | ||||||
|  |                 ) | ||||||
|  |               ]); | ||||||
|  |             } else { | ||||||
|  |               children.add(CircularProgressIndicator()); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return Scaffold( | ||||||
|  |               body: Center( | ||||||
|  |                 child: Column( | ||||||
|  |                   mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |                   crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |                   children: children, | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |           }, | ||||||
|  |         )); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildSearchBar(BuildContext context) { | ||||||
|  |     return Row( | ||||||
|  |       children: <Widget>[ | ||||||
|  |         widget.automaticallyImplyAppBarLeading || widget.onTapBack != null | ||||||
|  |             ? IconButton( | ||||||
|  |                 onPressed: () { | ||||||
|  |                   if (!showIntroModal || | ||||||
|  |                       widget.introModalWidgetBuilder == null) { | ||||||
|  |                     if (widget.onTapBack != null) { | ||||||
|  |                       widget.onTapBack!(); | ||||||
|  |                       return; | ||||||
|  |                     } | ||||||
|  |                     Navigator.maybePop(context); | ||||||
|  |                   } | ||||||
|  |                 }, | ||||||
|  |                 icon: Icon( | ||||||
|  |                   Platform.isIOS ? Icons.arrow_back_ios : Icons.arrow_back, | ||||||
|  |                 ), | ||||||
|  |                 color: Colors.black.withAlpha(128), | ||||||
|  |                 padding: EdgeInsets.zero) | ||||||
|  |             : SizedBox(width: 15), | ||||||
|  |         Expanded( | ||||||
|  |           child: AutoCompleteSearch( | ||||||
|  |               appBarKey: appBarKey, | ||||||
|  |               searchBarController: searchBarController, | ||||||
|  |               sessionToken: provider!.sessionToken, | ||||||
|  |               hintText: widget.hintText, | ||||||
|  |               searchingText: widget.searchingText, | ||||||
|  |               debounceMilliseconds: widget.autoCompleteDebounceInMilliseconds, | ||||||
|  |               onPicked: (prediction) { | ||||||
|  |                 _pickPrediction(prediction); | ||||||
|  |               }, | ||||||
|  |               onSearchFailed: (status) { | ||||||
|  |                 if (widget.onAutoCompleteFailed != null) { | ||||||
|  |                   widget.onAutoCompleteFailed!(status); | ||||||
|  |                 } | ||||||
|  |               }, | ||||||
|  |               autocompleteOffset: widget.autocompleteOffset, | ||||||
|  |               autocompleteRadius: widget.autocompleteRadius, | ||||||
|  |               autocompleteLanguage: widget.autocompleteLanguage, | ||||||
|  |               autocompleteComponents: widget.autocompleteComponents, | ||||||
|  |               autocompleteTypes: widget.autocompleteTypes, | ||||||
|  |               strictbounds: widget.strictbounds, | ||||||
|  |               region: widget.region, | ||||||
|  |               initialSearchString: widget.initialSearchString, | ||||||
|  |               searchForInitialValue: widget.searchForInitialValue, | ||||||
|  |               autocompleteOnTrailingWhitespace: | ||||||
|  |                   widget.autocompleteOnTrailingWhitespace), | ||||||
|  |         ), | ||||||
|  |         SizedBox(width: 5), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _pickPrediction(Prediction prediction) async { | ||||||
|  |     provider!.placeSearchingState = SearchingState.Searching; | ||||||
|  | 
 | ||||||
|  |     final PlacesDetailsResponse response = | ||||||
|  |         await provider!.places.getDetailsByPlaceId( | ||||||
|  |       prediction.placeId!, | ||||||
|  |       sessionToken: provider!.sessionToken, | ||||||
|  |       language: widget.autocompleteLanguage, | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     if (response.errorMessage?.isNotEmpty == true || | ||||||
|  |         response.status == "REQUEST_DENIED") { | ||||||
|  |       if (widget.onAutoCompleteFailed != null) { | ||||||
|  |         widget.onAutoCompleteFailed!(response.status); | ||||||
|  |       } | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     provider!.selectedPlace = PickResult.fromPlaceDetailResult(response.result); | ||||||
|  | 
 | ||||||
|  |     // Prevents searching again by camera movement. | ||||||
|  |     provider!.isAutoCompleteSearching = true; | ||||||
|  | 
 | ||||||
|  |     await _moveTo(provider!.selectedPlace!.geometry!.location.lat, | ||||||
|  |         provider!.selectedPlace!.geometry!.location.lng); | ||||||
|  | 
 | ||||||
|  |     provider!.placeSearchingState = SearchingState.Idle; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _moveTo(double latitude, double longitude) async { | ||||||
|  |     GoogleMapController? controller = provider!.mapController; | ||||||
|  |     if (controller == null) return; | ||||||
|  | 
 | ||||||
|  |     await controller.animateCamera( | ||||||
|  |       CameraUpdate.newCameraPosition( | ||||||
|  |         CameraPosition( | ||||||
|  |           target: LatLng(latitude, longitude), | ||||||
|  |           zoom: 16, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   _moveToCurrentPosition() async { | ||||||
|  |     if (provider!.currentPosition != null) { | ||||||
|  |       await _moveTo(provider!.currentPosition!.latitude, | ||||||
|  |           provider!.currentPosition!.longitude); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildMapWithLocation() { | ||||||
|  |     if (provider!.currentPosition == null) { | ||||||
|  |       return _buildMap(widget.initialPosition); | ||||||
|  |     } | ||||||
|  |     return _buildMap(LatLng(provider!.currentPosition!.latitude, | ||||||
|  |         provider!.currentPosition!.longitude)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildMap(LatLng initialTarget) { | ||||||
|  |     return GoogleMapPlacePicker( | ||||||
|  |       fullMotion: !widget.resizeToAvoidBottomInset, | ||||||
|  |       initialTarget: initialTarget, | ||||||
|  |       appBarKey: appBarKey, | ||||||
|  |       selectedPlaceWidgetBuilder: widget.selectedPlaceWidgetBuilder, | ||||||
|  |       pinBuilder: widget.pinBuilder, | ||||||
|  |       onSearchFailed: widget.onGeocodingSearchFailed, | ||||||
|  |       debounceMilliseconds: widget.cameraMoveDebounceInMilliseconds, | ||||||
|  |       enableMapTypeButton: widget.enableMapTypeButton, | ||||||
|  |       enableMyLocationButton: widget.enableMyLocationButton, | ||||||
|  |       usePinPointingSearch: widget.usePinPointingSearch, | ||||||
|  |       usePlaceDetailSearch: widget.usePlaceDetailSearch, | ||||||
|  |       onMapCreated: widget.onMapCreated, | ||||||
|  |       selectInitialPosition: widget.selectInitialPosition, | ||||||
|  |       language: widget.autocompleteLanguage, | ||||||
|  |       pickArea: widget.pickArea, | ||||||
|  |       forceSearchOnZoomChanged: widget.forceSearchOnZoomChanged, | ||||||
|  |       hidePlaceDetailsWhenDraggingPin: widget.hidePlaceDetailsWhenDraggingPin, | ||||||
|  |       selectText: widget.selectText, | ||||||
|  |       outsideOfPickAreaText: widget.outsideOfPickAreaText, | ||||||
|  |       onToggleMapType: () { | ||||||
|  |         provider!.switchMapType(); | ||||||
|  |         if (widget.onMapTypeChanged != null) { | ||||||
|  |           widget.onMapTypeChanged!(provider!.mapType); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       onMyLocation: () async { | ||||||
|  |         // Prevent to click many times in short period. | ||||||
|  |         if (provider!.isOnUpdateLocationCooldown == false) { | ||||||
|  |           provider!.isOnUpdateLocationCooldown = true; | ||||||
|  |           Timer(Duration(seconds: widget.myLocationButtonCooldown), () { | ||||||
|  |             provider!.isOnUpdateLocationCooldown = false; | ||||||
|  |           }); | ||||||
|  |           await provider! | ||||||
|  |               .updateCurrentLocation(widget.forceAndroidLocationManager); | ||||||
|  |           await _moveToCurrentPosition(); | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       onMoveStart: () { | ||||||
|  |         searchBarController.reset(); | ||||||
|  |       }, | ||||||
|  |       onPlacePicked: widget.onPlacePicked, | ||||||
|  |       onCameraMoveStarted: widget.onCameraMoveStarted, | ||||||
|  |       onCameraMove: widget.onCameraMove, | ||||||
|  |       onCameraIdle: widget.onCameraIdle, | ||||||
|  |       zoomGesturesEnabled: widget.zoomGesturesEnabled, | ||||||
|  |       zoomControlsEnabled: widget.zoomControlsEnabled, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Widget _buildIntroModal(BuildContext context) { | ||||||
|  |     return StatefulBuilder( | ||||||
|  |         builder: (BuildContext context, StateSetter setState) { | ||||||
|  |       return showIntroModal && widget.introModalWidgetBuilder != null | ||||||
|  |           ? Stack(children: [ | ||||||
|  |               Positioned( | ||||||
|  |                 top: 0, | ||||||
|  |                 right: 0, | ||||||
|  |                 bottom: 0, | ||||||
|  |                 left: 0, | ||||||
|  |                 child: Material( | ||||||
|  |                   type: MaterialType.canvas, | ||||||
|  |                   color: Color.fromARGB(128, 0, 0, 0), | ||||||
|  |                   shape: RoundedRectangleBorder( | ||||||
|  |                     borderRadius: BorderRadius.zero, | ||||||
|  |                   ), | ||||||
|  |                   child: ClipRect(), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               widget.introModalWidgetBuilder!(context, () { | ||||||
|  |                 setState(() { | ||||||
|  |                   showIntroModal = false; | ||||||
|  |                 }); | ||||||
|  |               }) | ||||||
|  |             ]) | ||||||
|  |           : Container(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,6 @@ | |||||||
|  | class APIKeys { | ||||||
|  |   APIKeys._(); | ||||||
|  | 
 | ||||||
|  |   static String androidApiKey = "AIzaSyDJpK9RVhlBejtJu9xSGfneuTN6HOfJgSM"; | ||||||
|  |   static String iosApiKey = "YOUR IOS KEY HERE"; | ||||||
|  | } | ||||||
| @ -0,0 +1,302 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:flutter/services.dart'; | ||||||
|  | import 'package:healthcare_user/dashboard.dart'; | ||||||
|  | import 'package:healthcare_user/settings.dart'; | ||||||
|  | import 'package:healthcare_user/signup.dart'; | ||||||
|  | import 'package:path/path.dart' as Path; | ||||||
|  | 
 | ||||||
|  | class Login extends StatefulWidget { | ||||||
|  |   const Login({super.key}); | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   State<Login> createState() => _LoginState(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | class _LoginState extends State<Login> { | ||||||
|  | 
 | ||||||
|  |   bool isObscureText=true; | ||||||
|  |   TextEditingController mobileNumberController = TextEditingController(); | ||||||
|  |   TextEditingController passwordController = TextEditingController(); | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     isObscureText=true; | ||||||
|  |     super.initState(); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   Future<bool> onWillPop() async { | ||||||
|  |     final shouldPop = await showDialog<bool>(context: context, builder: (context) { | ||||||
|  |       return AlertDialog( | ||||||
|  |         title: const Text('Do you want to exit app?', | ||||||
|  |             style: TextStyle( | ||||||
|  |               color: primaryColor, | ||||||
|  |               fontSize: 20, | ||||||
|  |             )), | ||||||
|  |         actionsAlignment: MainAxisAlignment.spaceBetween, | ||||||
|  |         actions: [ | ||||||
|  |           TextButton( | ||||||
|  |             onPressed: () { | ||||||
|  |               SystemNavigator.pop(); | ||||||
|  |             }, | ||||||
|  |             child: const Text('Yes', | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: primaryColor, | ||||||
|  |                   fontSize: 20, | ||||||
|  |                 )), | ||||||
|  |           ), | ||||||
|  |           TextButton( | ||||||
|  |             onPressed: () { | ||||||
|  |               Navigator.of(context).pop(false); | ||||||
|  |             }, | ||||||
|  |             child: const Text('No', | ||||||
|  |                 style: TextStyle( | ||||||
|  |                   color: primaryColor, | ||||||
|  |                   fontSize: 20, | ||||||
|  |                 )), | ||||||
|  |           ), | ||||||
|  |         ], | ||||||
|  |       ); | ||||||
|  |     }, | ||||||
|  |     ); | ||||||
|  |     return shouldPop!; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     String lastInputValue=""; | ||||||
|  | 
 | ||||||
|  |     return WillPopScope( | ||||||
|  |       onWillPop: () async => onWillPop(), | ||||||
|  |       child: Scaffold( | ||||||
|  | 
 | ||||||
|  |           body: Stack( | ||||||
|  |             children: <Widget>[ | ||||||
|  |               Container( | ||||||
|  |                 decoration:  const BoxDecoration( | ||||||
|  |                   image:  DecorationImage(image:  AssetImage("images/background.png"), fit: BoxFit.cover,), | ||||||
|  |                 ), | ||||||
|  |               ), | ||||||
|  |               GestureDetector( | ||||||
|  |                 onTap: () { | ||||||
|  |                   FocusManager.instance.primaryFocus?.unfocus(); | ||||||
|  |                 }, | ||||||
|  |                 child: SafeArea( | ||||||
|  |                     child: SingleChildScrollView( | ||||||
|  |                         child: Padding( | ||||||
|  |                           padding: const EdgeInsets.all(10), | ||||||
|  |                           child: Column( | ||||||
|  |                             children: <Widget>[ | ||||||
|  |                               const SizedBox( | ||||||
|  |                                 height: 15, | ||||||
|  |                               ), | ||||||
|  |                               Container( | ||||||
|  |                                 //width: double.infinity, | ||||||
|  |                                   child: Image( | ||||||
|  |                                     image: const AssetImage('images/logo.png'), | ||||||
|  |                                     height: MediaQuery.of(context).size.height * .25, | ||||||
|  |                                   )), | ||||||
|  |                               const SizedBox( | ||||||
|  |                                 height: 15, | ||||||
|  |                               ), | ||||||
|  |                               Container( | ||||||
|  |                                 padding: const EdgeInsets.all(10), | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   cursorColor: greyColor, | ||||||
|  |                                   controller: mobileNumberController, | ||||||
|  |                                   keyboardType: TextInputType.number, | ||||||
|  |                                   decoration: const InputDecoration( | ||||||
|  |                                     prefixIcon: Icon( | ||||||
|  |                                       Icons.phone, | ||||||
|  |                                       color: greyColor, | ||||||
|  |                                     ), | ||||||
|  |                                     border: OutlineInputBorder( | ||||||
|  |                                         borderSide: BorderSide(color: primaryColor)), | ||||||
|  |                                     focusedBorder: OutlineInputBorder( | ||||||
|  |                                       borderSide: BorderSide(color:primaryColor), | ||||||
|  |                                     ), | ||||||
|  |                                     enabledBorder: OutlineInputBorder( | ||||||
|  |                                       borderSide: BorderSide(color: primaryColor), | ||||||
|  |                                     ), | ||||||
|  |                                     labelText: 'Enter MobileNumber', | ||||||
|  |                                     labelStyle: TextStyle( | ||||||
|  |                                       color: greyColor, //<-- SEE HERE | ||||||
|  |                                     ), | ||||||
|  |                                   ), | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                               const SizedBox( | ||||||
|  |                                 height: 15, | ||||||
|  |                               ), | ||||||
|  | 
 | ||||||
|  |                               Container( | ||||||
|  |                                 padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), | ||||||
|  |                                 child: TextFormField( | ||||||
|  |                                   cursorColor: greyColor, | ||||||
|  |                                   obscureText: isObscureText, | ||||||
|  |                                   controller: passwordController, | ||||||
|  |                                   decoration: InputDecoration( | ||||||
|  |                                     labelText: 'Password', | ||||||
|  |                                     prefixIcon: const Icon(Icons.password, color: greyColor,), | ||||||
|  |                                     labelStyle: const TextStyle( | ||||||
|  |                                       color: greyColor, //<-- SEE HERE | ||||||
|  |                                     ), | ||||||
|  |                                     border: const OutlineInputBorder( | ||||||
|  |                                         borderSide: BorderSide(color: primaryColor)), | ||||||
|  |                                     focusedBorder: const OutlineInputBorder( | ||||||
|  |                                       borderSide: BorderSide(color: primaryColor), | ||||||
|  |                                     ), | ||||||
|  |                                     enabledBorder: const OutlineInputBorder( | ||||||
|  |                                       borderSide: BorderSide(color: primaryColor), | ||||||
|  |                                     ), | ||||||
|  |                                     suffixIcon: IconButton( | ||||||
|  |                                       icon:  Icon( | ||||||
|  |                                         Icons.visibility_off_outlined, | ||||||
|  |                                         color: isObscureText==true?greyColor:primaryColor, | ||||||
|  |                                       ), | ||||||
|  |                                       onPressed: () { | ||||||
|  | 
 | ||||||
|  |                                         print("show password"); | ||||||
|  |                                         setState(() { | ||||||
|  |                                           isObscureText = !isObscureText; | ||||||
|  |                                         }); | ||||||
|  |                                       }, | ||||||
|  |                                     ), | ||||||
|  | 
 | ||||||
|  |                                   ), | ||||||
|  | 
 | ||||||
|  |                                 ), | ||||||
|  |                               ), | ||||||
|  |                               Padding(padding: const EdgeInsets.fromLTRB(220, 10, 0,10), | ||||||
|  |                                 child: TextButton( | ||||||
|  |                                   onPressed: () { | ||||||
|  |                                     /*Navigator.push( | ||||||
|  |                                       context, | ||||||
|  |                                       MaterialPageRoute(builder: (context) => OtpScreen()), | ||||||
|  |                                     );*/ | ||||||
|  |                                   }, | ||||||
|  |                                   child: const Text( | ||||||
|  |                                     'Forgot Password?', | ||||||
|  |                                     style: TextStyle( | ||||||
|  |                                       color: greyColor, | ||||||
|  |                                       fontSize: 15, | ||||||
|  |                                       decoration: TextDecoration.underline, | ||||||
|  | 
 | ||||||
|  |                                     ), | ||||||
|  |                                   ), | ||||||
|  |                                 ),), | ||||||
|  |                               Container( | ||||||
|  |                                   width: 400, | ||||||
|  |                                   height: 50, | ||||||
|  |                                   padding: const EdgeInsets.fromLTRB(10, 0, 10, 0), | ||||||
|  |                                   child: ElevatedButton( | ||||||
|  |                                     style: ElevatedButton.styleFrom( | ||||||
|  |                                       primary: primaryColor, // background | ||||||
|  |                                       onPrimary: Colors.white, // foreground | ||||||
|  |                                     ), | ||||||
|  |                                     onPressed: () async{ | ||||||
|  | 
 | ||||||
|  |                                       if (mobileNumberController.text != '' || | ||||||
|  |                                           passwordController.text != '') { | ||||||
|  |                                         AppSettings.preLoaderDialog(context); | ||||||
|  | 
 | ||||||
|  |                                         bool isOnline = await AppSettings.internetConnectivity(); | ||||||
|  | 
 | ||||||
|  |                                         if(isOnline){ | ||||||
|  |                                           var payload = new Map<String, dynamic>(); | ||||||
|  |                                           payload["phone"] = mobileNumberController.text.toString(); | ||||||
|  |                                           payload["password"] = passwordController.text.toString(); | ||||||
|  | 
 | ||||||
|  |                                           bool signinStatus = await AppSettings.login(payload); | ||||||
|  | 
 | ||||||
|  |                                           try{ | ||||||
|  |                                             if (signinStatus) { | ||||||
|  |                                               Navigator.of(context,rootNavigator: true).pop(); | ||||||
|  | 
 | ||||||
|  |                                               await Navigator.push( | ||||||
|  |                                                 context, | ||||||
|  |                                                 MaterialPageRoute( | ||||||
|  |                                                     builder: (context) => const Dashboard()), | ||||||
|  |                                               ); | ||||||
|  |                                              // AppSettings.longSuccessToast("Logged in Successfully"); | ||||||
|  |                                               mobileNumberController.text=''; | ||||||
|  |                                               passwordController.text=''; | ||||||
|  | 
 | ||||||
|  |                                             } else { | ||||||
|  |                                               Navigator.of(context,rootNavigator: true).pop(); | ||||||
|  |                                               //AppSettings.longFailedToast("Please enter valid details"); | ||||||
|  |                                             } | ||||||
|  |                                           } | ||||||
|  |                                           catch(exception){ | ||||||
|  |                                             Navigator.of(context,rootNavigator: true).pop(); | ||||||
|  |                                             print(exception); | ||||||
|  |                                           } | ||||||
|  |                                         } | ||||||
|  |                                         else{ | ||||||
|  |                                           Navigator.of(context,rootNavigator: true).pop(); | ||||||
|  |                                          // AppSettings.longFailedToast("Please Check internet"); | ||||||
|  |                                         } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |                                       } | ||||||
|  |                                       else{ | ||||||
|  | 
 | ||||||
|  |                                         //AppSettings.longFailedToast("Please enter valid details"); | ||||||
|  |                                       } | ||||||
|  | 
 | ||||||
|  |                                     }, | ||||||
|  |                                     child: const Text('Login'), | ||||||
|  |                                   )), | ||||||
|  |                               Padding(padding: const EdgeInsets.fromLTRB(10, 10,10,10), | ||||||
|  |                                 child: Row( | ||||||
|  |                                   mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |                                   children: <Widget>[ | ||||||
|  |                                     const Text( | ||||||
|  |                                       'Not a Member Yet?', | ||||||
|  |                                       style: TextStyle( | ||||||
|  |                                         color: primaryColor, | ||||||
|  |                                       ), | ||||||
|  |                                     ), | ||||||
|  |                                     TextButton( | ||||||
|  |                                       child: const Text( | ||||||
|  |                                         'Sign Up', | ||||||
|  |                                         style: TextStyle(fontSize: 15, | ||||||
|  |                                             decoration: TextDecoration.underline,color: greyColor), | ||||||
|  |                                       ), | ||||||
|  |                                       onPressed: () { | ||||||
|  |                                         Navigator.push( | ||||||
|  |                                           context, | ||||||
|  |                                           MaterialPageRoute( | ||||||
|  |                                               builder: (context) => const SignUp()), | ||||||
|  |                                         ); | ||||||
|  |                                         //signup screen | ||||||
|  |                                       }, | ||||||
|  |                                     ) | ||||||
|  |                                   ], | ||||||
|  |                                 ),) | ||||||
|  |                             ], | ||||||
|  |                           ), | ||||||
|  |                         ) | ||||||
|  |                     )), | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ) | ||||||
|  |         /*bottomNavigationBar: Container( | ||||||
|  |     padding: EdgeInsets.only(bottom: 13), | ||||||
|  |     height: 38, | ||||||
|  |     child: Column( | ||||||
|  |       mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |       crossAxisAlignment: CrossAxisAlignment.center, | ||||||
|  |       children: [ | ||||||
|  |         Container( | ||||||
|  |             child: Image( | ||||||
|  |               image: AssetImage('images/logo_btm.png'), | ||||||
|  |               width: 90, | ||||||
|  |             )), | ||||||
|  |       ], | ||||||
|  |     ), | ||||||
|  |   ),*/ | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @ -0,0 +1,23 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:healthcare_user/splash_screen.dart'; | ||||||
|  | import 'package:sizer/sizer.dart'; | ||||||
|  | import 'package:flutter/services.dart'; | ||||||
|  | 
 | ||||||
|  | void main () async { | ||||||
|  |   // Set default home. | ||||||
|  |   Widget _defaultHome = Splash(); | ||||||
|  |   WidgetsFlutterBinding.ensureInitialized(); | ||||||
|  |   SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) | ||||||
|  |       .then((_) { | ||||||
|  |     runApp(Sizer( | ||||||
|  |       builder: (context, orientation, deviceType) { | ||||||
|  |         return MaterialApp( | ||||||
|  |           title: 'Health Care', | ||||||
|  |           theme: ThemeData.light(), | ||||||
|  |           home:_defaultHome, | ||||||
|  |           debugShowCheckedModeBanner: false, | ||||||
|  |         ); | ||||||
|  |       }, | ||||||
|  |     )); | ||||||
|  |   }); | ||||||
|  | } | ||||||