diff --git a/android/.gitignore b/android/.gitignore index 0a741cb..ed8ee91 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -4,6 +4,7 @@ gradle-wrapper.jar /gradlew /gradlew.bat /local.properties +/key.properties GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. diff --git a/android/app/build.gradle b/android/app/build.gradle index dc3736b..ba1e306 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -25,8 +25,14 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + android { - compileSdkVersion 30 + compileSdkVersion 31 compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -50,11 +56,17 @@ android { versionName flutterVersionName } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } 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 + signingConfig signingConfigs.release } } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8b2eb43..8b2a12f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,35 +1,40 @@ - + + + + + + + + android:name="io.flutter.embedding.android.NormalTheme" + android:resource="@style/NormalTheme" /> + android:name="io.flutter.embedding.android.SplashScreenDrawable" + android:resource="@drawable/launch_background" /> - - + + @drawable/launch_background + false diff --git a/android/app/src/main/res/values/ic_samagri_icon_background.xml b/android/app/src/main/res/values/ic_samagri_icon_background.xml new file mode 100644 index 0000000..74a956f --- /dev/null +++ b/android/app/src/main/res/values/ic_samagri_icon_background.xml @@ -0,0 +1,4 @@ + + + #3F3D56 + \ No newline at end of file diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml index d74aa35..b696815 100644 --- a/android/app/src/main/res/values/styles.xml +++ b/android/app/src/main/res/values/styles.xml @@ -5,6 +5,7 @@ @drawable/launch_background + false diff --git a/android/build.gradle b/android/build.gradle index ed45c65..09fbd64 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ buildscript { - ext.kotlin_version = '1.3.50' + ext.kotlin_version = '1.6.10' repositories { google() mavenCentral() diff --git a/assets/Illustration.png b/assets/Illustration.png new file mode 100644 index 0000000..d54b845 Binary files /dev/null and b/assets/Illustration.png differ diff --git a/assets/avatar_man.png b/assets/avatar_man.png new file mode 100644 index 0000000..93c7099 Binary files /dev/null and b/assets/avatar_man.png differ diff --git a/assets/avatar_woman.png b/assets/avatar_woman.png new file mode 100644 index 0000000..3264d55 Binary files /dev/null and b/assets/avatar_woman.png differ diff --git a/assets/bg.png b/assets/bg.png deleted file mode 100644 index 292c1d4..0000000 Binary files a/assets/bg.png and /dev/null differ diff --git a/assets/image_01.png b/assets/image_01.png index 4235bba..6b86346 100644 Binary files a/assets/image_01.png and b/assets/image_01.png differ diff --git a/assets/location.png b/assets/location.png new file mode 100644 index 0000000..dcfe4e5 Binary files /dev/null and b/assets/location.png differ diff --git a/assets/profile_background.png b/assets/profile_background.png new file mode 100644 index 0000000..d97fc77 Binary files /dev/null and b/assets/profile_background.png differ diff --git a/assets/svg/background.svg b/assets/svg/background.svg new file mode 100644 index 0000000..52b4921 --- /dev/null +++ b/assets/svg/background.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/svg/profile_bg.svg b/assets/svg/profile_bg.svg new file mode 100644 index 0000000..47c56aa --- /dev/null +++ b/assets/svg/profile_bg.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/svg/user-id-icon.svg b/assets/svg/user-id-icon.svg new file mode 100644 index 0000000..b3269d6 --- /dev/null +++ b/assets/svg/user-id-icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9367d48..8d4492f 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 8.0 + 9.0 diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..313ea4a --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +platform :ios, '11.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..922e9a3 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,63 @@ +PODS: + - connectivity_plus (0.0.1): + - Flutter + - ReachabilitySwift + - Flutter (1.0.0) + - flutter_keyboard_visibility (0.0.1): + - Flutter + - flutter_secure_storage (3.3.1): + - Flutter + - geolocator_apple (1.2.0): + - Flutter + - ObjectBox (1.6.0) + - objectbox_flutter_libs (0.0.1): + - Flutter + - ObjectBox (= 1.6.0) + - path_provider_ios (0.0.1): + - Flutter + - ReachabilitySwift (5.0.0) + +DEPENDENCIES: + - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) + - Flutter (from `Flutter`) + - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) + - geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`) + - objectbox_flutter_libs (from `.symlinks/plugins/objectbox_flutter_libs/ios`) + - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) + +SPEC REPOS: + trunk: + - ObjectBox + - ReachabilitySwift + +EXTERNAL SOURCES: + connectivity_plus: + :path: ".symlinks/plugins/connectivity_plus/ios" + Flutter: + :path: Flutter + flutter_keyboard_visibility: + :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" + geolocator_apple: + :path: ".symlinks/plugins/geolocator_apple/ios" + objectbox_flutter_libs: + :path: ".symlinks/plugins/objectbox_flutter_libs/ios" + path_provider_ios: + :path: ".symlinks/plugins/path_provider_ios/ios" + +SPEC CHECKSUMS: + connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e + Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 + flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec + geolocator_apple: b741765c55dc21950e3e106e8b3584e55cf81ce5 + ObjectBox: a181cc5fb47e0a6ec60754d34dc49f40dc17829e + objectbox_flutter_libs: 511c59b863bc45abc7f6f338499e4a50e9aa5f1d + path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5 + ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 + +PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d + +COCOAPODS: 1.11.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 16e112c..f5b0ec6 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,12 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + 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 */; }; + 4C9879DB498106CD77BAE52B /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5EF6C7081ECB6B5BB4E44D4A /* Pods_Runner.framework */; }; 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 */; }; @@ -32,9 +33,12 @@ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 5EF6C7081ECB6B5BB4E44D4A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 72598152D802005263DC75BC /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 90682DB92518F3BC8CA0280D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -42,6 +46,7 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + FAD90254FE911E159AC2C5E3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -49,12 +54,24 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4C9879DB498106CD77BAE52B /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 343EDA05513D996852D25A5C /* Pods */ = { + isa = PBXGroup; + children = ( + 72598152D802005263DC75BC /* Pods-Runner.debug.xcconfig */, + 90682DB92518F3BC8CA0280D /* Pods-Runner.release.xcconfig */, + FAD90254FE911E159AC2C5E3 /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -72,6 +89,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 343EDA05513D996852D25A5C /* Pods */, + D6A2D8873CBDEFEE806EF21B /* Frameworks */, ); sourceTree = ""; }; @@ -98,6 +117,14 @@ path = Runner; sourceTree = ""; }; + D6A2D8873CBDEFEE806EF21B /* Frameworks */ = { + isa = PBXGroup; + children = ( + 5EF6C7081ECB6B5BB4E44D4A /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -105,12 +132,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 55E1C451B26B8833402FF022 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + EF1296F45A0EDDE3599E6609 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -127,7 +156,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1300; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -183,6 +212,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 55E1C451B26B8833402FF022 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -197,6 +248,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + EF1296F45A0EDDE3599E6609 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -290,7 +358,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.example.geoSpatial; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -414,7 +485,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.example.geoSpatial; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; @@ -433,7 +507,10 @@ CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); PRODUCT_BUNDLE_IDENTIFIER = com.example.geoSpatial; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140c..3db53b6 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png new file mode 100644 index 0000000..5c281a9 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png new file mode 100644 index 0000000..8e30ffe Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png new file mode 100644 index 0000000..70fe67f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png new file mode 100644 index 0000000..36a2815 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png new file mode 100644 index 0000000..7a17e17 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png new file mode 100644 index 0000000..1cdae3f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png new file mode 100644 index 0000000..f053738 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png new file mode 100644 index 0000000..aded42e Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png new file mode 100644 index 0000000..a17250a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png new file mode 100644 index 0000000..a574333 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png new file mode 100644 index 0000000..1aef459 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png new file mode 100644 index 0000000..e2c5229 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png new file mode 100644 index 0000000..b7d7694 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png new file mode 100644 index 0000000..271d47d Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png new file mode 100644 index 0000000..2974b62 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png new file mode 100644 index 0000000..aaa4180 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png new file mode 100644 index 0000000..49fdcbb Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png new file mode 100644 index 0000000..a7bfc3d Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png new file mode 100644 index 0000000..71ed690 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png new file mode 100644 index 0000000..9546867 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png new file mode 100644 index 0000000..39ed20f Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png new file mode 100644 index 0000000..9a121c1 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png new file mode 100644 index 0000000..d9ccd27 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png new file mode 100644 index 0000000..f10f4fd Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png new file mode 100644 index 0000000..ed1c1f2 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png new file mode 100644 index 0000000..e2bc2ea Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png new file mode 100644 index 0000000..9d12c67 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png new file mode 100644 index 0000000..463546c Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png new file mode 100644 index 0000000..fcfac4a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png new file mode 100644 index 0000000..5188f24 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png new file mode 100644 index 0000000..a536d7a Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fa..e138c0b 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1 @@ -{ - "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" - } -} +{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"idiom":"watch","filename":"172.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"86x86","expected-size":"172","role":"quickLook"},{"idiom":"watch","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"40x40","expected-size":"80","role":"appLauncher"},{"idiom":"watch","filename":"88.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"40mm","scale":"2x","size":"44x44","expected-size":"88","role":"appLauncher"},{"idiom":"watch","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"50x50","expected-size":"100","role":"appLauncher"},{"idiom":"watch","filename":"196.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"98x98","expected-size":"196","role":"quickLook"},{"idiom":"watch","filename":"216.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"108x108","expected-size":"216","role":"quickLook"},{"idiom":"watch","filename":"48.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"24x24","expected-size":"48","role":"notificationCenter"},{"idiom":"watch","filename":"55.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"27.5x27.5","expected-size":"55","role":"notificationCenter"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"3x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"2x"},{"size":"1024x1024","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch-marketing","scale":"1x"},{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]} \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 28c6bf0..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 2ccbfd9..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cde121..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index dcdc230..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 2ccbfd9..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b86..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b86..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d16..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 6a84f41..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index d0e1f58..0000000 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 1a3ee2a..b890903 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -11,7 +11,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - geo_spatial + Samagri Spatial CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/Constants/Globals.dart b/lib/Constants/Globals.dart deleted file mode 100644 index 04b4b65..0000000 --- a/lib/Constants/Globals.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:flutter/material.dart'; - -ThemeData theme = ThemeData( - brightness: Brightness.light, - primaryColor: Color(0xff5EAAA8), - canvasColor: Color(0xffF7F3E9), - scaffoldBackgroundColor: Color(0xffF7F3E9), - cardColor: Colors.white, - focusColor: Color(0xff5EAAA8), - hoverColor: Color(0xff5EAAA8), - highlightColor: Color(0xff5EAAA8), - disabledColor: Colors.grey.shade200, - buttonTheme: ButtonThemeData( - minWidth: 200, - height: 50, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20))), - ), - backgroundColor: Color(0xffF7F3E9), - hintColor: Color(0xff5EAAA8), - colorScheme: ColorScheme.fromSwatch().copyWith(secondary: Color(0xffF05945)), -); diff --git a/lib/Constants/NetworkConfig.dart b/lib/Constants/NetworkConfig.dart deleted file mode 100644 index 9705b16..0000000 --- a/lib/Constants/NetworkConfig.dart +++ /dev/null @@ -1,2 +0,0 @@ -//Server ID Address/URL, change here and this constant, avoid hardcoding -String NETWORK_ADDRESS = '192.168.29.156:3000'; diff --git a/lib/Model/CommunityDataModel.dart b/lib/Model/CommunityDataModel.dart new file mode 100644 index 0000000..0a3367c --- /dev/null +++ b/lib/Model/CommunityDataModel.dart @@ -0,0 +1,165 @@ +import 'dart:convert'; + +import 'package:geolocator/geolocator.dart'; +import 'package:objectbox/objectbox.dart'; +import 'package:intl/intl.dart'; + +@Entity() +class CommunityDataModel { + int id = 0; + String? recordCollectingUserId; + String? resourceType; + Position? locationTopLeft; + Position? locationTopRight; + Position? locationBottomLeft; + Position? locationBottomRight; + String? villageCode; + String? savedTime = DateFormat('kk:mm:ss, EEE d MMM').format(DateTime.now()); + + String? get dbLocationTopLeft { + if (locationTopLeft == null) { + return null; + } else { + Map data = locationTopLeft!.toJson(); + var encodedData = json.encode(data); + print(encodedData); + return encodedData; + } + } + + set dbLocationTopLeft(String? value) { + if (value == null) { + locationTopLeft = null; + } else { + final body = json.decode(value.trim()); + ; + locationTopLeft = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + String? get dbLocationTopRight { + if (locationTopRight == null) { + return null; + } else { + Map data = locationTopRight!.toJson(); + var encodedData = json.encode(data); + print(encodedData); + return encodedData; + } + } + + set dbLocationTopRight(String? value) { + if (value == null) { + locationTopRight = null; + } else { + final body = json.decode(value.trim()); + ; + locationTopRight = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + String? get dbLocationBottomLeft { + if (locationBottomLeft == null) { + return null; + } else { + Map data = locationBottomLeft!.toJson(); + var encodedData = json.encode(data); + print(encodedData); + return encodedData; + } + } + + set dbLocationBottomLeft(String? value) { + if (value == null) { + locationBottomLeft = null; + } else { + final body = json.decode(value.trim()); + ; + locationBottomLeft = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + String? get dbLocationBottomRight { + if (locationBottomRight == null) { + return null; + } else { + Map data = locationBottomRight!.toJson(); + var encodedData = json.encode(data); + print(encodedData); + return encodedData; + } + } + + set dbLocationBottomRight(String? value) { + if (value == null) { + locationBottomRight = null; + } else { + final body = json.decode(value.trim()); + ; + print(body); + locationBottomRight = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + CommunityDataModel( + {this.locationBottomLeft, + this.locationBottomRight, + this.locationTopLeft, + this.locationTopRight, + this.resourceType, + this.villageCode}); + + Map toJson() => { + 'volunteerUserId': recordCollectingUserId, + 'resourceType': resourceType, + 'villageCode': villageCode, + 'locationTopLeft': [ + locationTopLeft!.latitude, + locationTopLeft!.longitude + ], + 'locationTopRight': [ + locationTopRight!.latitude, + locationTopRight!.longitude + ], + 'locationBottomLeft': [ + locationBottomLeft!.latitude, + locationBottomLeft!.longitude + ], + 'locationBottomRight': [ + locationBottomRight!.latitude, + locationBottomRight!.longitude + ], + }; +} diff --git a/lib/Model/FamilyDataModels.dart b/lib/Model/FamilyDataModels.dart new file mode 100644 index 0000000..80cfe47 --- /dev/null +++ b/lib/Model/FamilyDataModels.dart @@ -0,0 +1,643 @@ +import 'dart:convert'; +import 'package:geo_spatial/Widgets/NestedOptionsWidget.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:intl/intl.dart'; +import 'package:objectbox/objectbox.dart'; + +String parseStringFields(String? val) { + if (val == null || val == "") + return ""; + else + return val; +} + +parseDependentField( + String? dependentFieldVal, var returnVal, String requiredValue, + {bool sendEmptyList = false}) { + if (dependentFieldVal == null || dependentFieldVal == "") { + return sendEmptyList ? [] : ""; + } else if (dependentFieldVal == requiredValue) { + return returnVal; + } else { + return sendEmptyList ? [] : ""; + } +} + +buildListForOptionWidget(Map mapData) { + var listData = []; + + mapData.forEach((key, value) { + if (value) { + listData.add(key); + } + }); + if (listData.isEmpty) { + return ""; + } + return listData; +} + +@Entity() +class FamilyMemberIndividualDataModel { + parseOccupationJson(List occupationData) { + var list = []; + for (var i in occupationData) { + list.add(i.toJsonString()); + } + + return json.encode(list); + } + + parseOccupationServerResultJSON(List occupationData) { + var list = []; + for (var i in occupationData) { + if (i.isSelected == true) { + var job = []; + i.subOptionDataMap!.forEach((key, value) { + if (value == true) { + job.add(key); + } + }); + list.add({"category": i.boxName, "occupation": job}); + } + } + print("ENC: ${json.encode(list)}"); + return list; + } + + parseOccupationObject(String occupationData) { + List occupationStringList = json.decode(occupationData); + List list = []; + + for (var i in occupationStringList) { + list.add(NestedOptionData.fromJson(i)); + } + + return list; + } + + int id = 0; + String? userName; + @Property(type: PropertyType.date) + DateTime? dateOfBirth; + String? gender; + String? phoneNumber; + String? educationQualification; + String? aadhaarNumber; + Map? vulnerabilities; + String? dailyWageWorker; + String? employed; + List? occupationData; + String? student; + String? studentEducationCategory; + String? income; + String? incomeType; + String? pension; + String? businessStatus; + String? maritalStatus; + String? noOfDaysWorking; + List? specialSkills; + List? workTimings; + String? surgeries; + String? anganwadiServicesAware; + String? anganwadiServicesUsing; + List? anganwadiServicesUsedList; + String? PHCServicesUsed; + String? privateClinicServicesUsed; + Map? privateServiceReason; + Map? communicableDiseases; + Map? frequentAilments; + Map? nonCommunicableDiseases; + String? useOfTobacco; + Map? tobaccoProducts; + String? useOfAlcohol; + String? aarogyaSetuInstalled; + String? vizhithiruInstalled; + bool? dataValid = false; + + Map toJson() { + print(parseDependentField( + employed, + occupationData == null + ? [] + : parseOccupationServerResultJSON(occupationData!), + "yes", + sendEmptyList: true)); + return { + "UIN": "", + "name": parseStringFields(userName), + "dateOfBirth": + "${dateOfBirth!.day}-${dateOfBirth!.month}-${dateOfBirth!.year}", + "gender": parseStringFields(gender), + "phoneNumber": parseStringFields(phoneNumber), + "educationalQualification": parseStringFields(educationQualification), + "aadhaarNumber": parseStringFields(aadhaarNumber), + "Vulnerabilities": vulnerabilities != null + ? buildListForOptionWidget(vulnerabilities!) + : "", + "isADailyWageWorker": parseStringFields(dailyWageWorker), + "occupationData": parseDependentField( + employed, + occupationData == null + ? [] + : parseOccupationServerResultJSON(occupationData!), + "yes", + sendEmptyList: true), + "employed": parseStringFields(employed), + "income": parseDependentField(employed, parseStringFields(income), "yes"), + "incomeType": + parseDependentField(employed, parseStringFields(incomeType), "yes"), + "noOfDaysWorking": parseDependentField( + employed, parseStringFields(noOfDaysWorking), "yes"), + //TODO: Verify if parseDependentField method working for new fields + "student": + parseDependentField(employed, parseStringFields(student), "no"), + "studentEducationCategory": parseDependentField( + employed, + parseDependentField(parseStringFields(student), + parseStringFields(studentEducationCategory), "yes"), + "no"), + "oldAgePension": parseStringFields(pension), + "businessStatus": parseStringFields(businessStatus), + "maritalStatus": parseStringFields(maritalStatus), + + "specialSkills": specialSkills != null + ? (specialSkills!.isNotEmpty ? specialSkills : "") + : "", + "workTimings": parseDependentField(employed, workTimings, "yes"), + "surgeriesUndergone": parseStringFields(surgeries), + "anganwadiServicesAware": parseStringFields(anganwadiServicesAware), + "anganwadiServicesUsed": parseStringFields(anganwadiServicesUsing), + "anganwadiServicesUtilised": parseDependentField( + anganwadiServicesUsing, anganwadiServicesUsedList, "yes"), + "phcServicesUtilised": parseStringFields(PHCServicesUsed), + "privateHealthClinicFacilitiesUsed": + parseStringFields(privateClinicServicesUsed), + "reasonsForVisitingPrivateHealthClinic": parseDependentField( + privateClinicServicesUsed, + privateServiceReason != null + ? buildListForOptionWidget(privateServiceReason!) + : "", + "yes"), + "communicableDiseases": communicableDiseases != null + ? buildListForOptionWidget(communicableDiseases!) + : "", + "frequentHealthAilments": frequentAilments != null + ? buildListForOptionWidget(frequentAilments!) + : "", + "nonCommunicableDiseases": nonCommunicableDiseases != null + ? buildListForOptionWidget(nonCommunicableDiseases!) + : "", + "tobaccoBasedProductsUsage": parseStringFields(useOfTobacco), + "tobaccoProductsUsed": parseDependentField( + useOfTobacco, + tobaccoProducts != null + ? buildListForOptionWidget(tobaccoProducts!) + : "", + "yes"), + "alcoholConsumption": parseStringFields(useOfAlcohol), + "arogyaSethuAppInstallationStatus": + parseStringFields(aarogyaSetuInstalled), + "vizhithiruAppInstallationStatus": parseStringFields(vizhithiruInstalled) + }; + } + + FamilyMemberIndividualDataModel({this.userName}); + + String? get dbVulnerabilities => + vulnerabilities == null ? null : json.encode(vulnerabilities); + + set dbVulnerabilities(String? value) { + if (value == null) { + vulnerabilities = null; + } else { + vulnerabilities = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbOccupationData => + occupationData == null ? null : parseOccupationJson(occupationData!); + + set dbOccupationData(String? value) { + if (value == null) { + occupationData = null; + } else { + var data = parseOccupationObject(value); + if (data.isEmpty) { + occupationData = null; + } else { + occupationData = data; + } + } + } + + String? get dbPrivateServiceReason => + privateServiceReason == null ? null : json.encode(privateServiceReason); + + set dbPrivateServiceReason(String? value) { + if (value == null) { + privateServiceReason = null; + } else { + privateServiceReason = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbCommunicableDiseases => + communicableDiseases == null ? null : json.encode(communicableDiseases); + + set dbCommunicableDiseases(String? value) { + if (value == null) { + communicableDiseases = null; + } else { + communicableDiseases = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbFrequentAilments => + frequentAilments == null ? null : json.encode(frequentAilments); + + set dbFrequentAilments(String? value) { + if (value == null) { + frequentAilments = null; + } else { + frequentAilments = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbNonCommunicableDiseases => nonCommunicableDiseases == null + ? null + : json.encode(nonCommunicableDiseases); + + set dbNonCommunicableDiseases(String? value) { + if (value == null) { + nonCommunicableDiseases = null; + } else { + nonCommunicableDiseases = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbTobaccoProducts => + tobaccoProducts == null ? null : json.encode(tobaccoProducts); + + set dbTobaccoProducts(String? value) { + if (value == null) { + tobaccoProducts = null; + } else { + tobaccoProducts = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } +} + +@Entity() +class FamilyMembersCommonDataModel { + int id = 0; + String? recordCollectingUserId; + + Position? locationTopLeft; + Position? locationTopRight; + Position? locationBottomLeft; + Position? locationBottomRight; + + String? headOfFamily; + String? drinkingWater; + Map? sourceOfDrinkingWater; + String? toiletFacility; + Map? noToiletsWhy; + String? communityToilet; + String? environmentSanitationLevel; + String? runningWaterAvailable; + String? noOfTwoWheelers; + String? noOfThreeWheelers; + String? noOfFourWheelers; + Map? twoThreeWheelManufacturer; + Map? fourWheelManufacturer; + Map? localFoodMap; + String? isCattleOwned; + String? incomeFromCattle; + String? isFarmLandOwned; + String? isSeedsPreserved; + Map? cropsCultivated; + Map? preservedSeedsMap; + Map? treesOwnedMap; + String? isKitchenGardenOwned; + Map? kitchenGardenPlants; + String? addressOne; + String? addressTwo; + String? city; + String? villageCode; + bool? locationPageValid = false; + bool? commonDetailsValid = false; + + @Transient() + final individualDataListTransient = []; + final individualDataList = ToMany(); + + Map toJson() { + return { + 'volunteerUserId': recordCollectingUserId, + 'familyMemberData': + individualDataListTransient.map((item) => item.toJson()).toList(), + 'locationTopLeft': [ + locationTopLeft!.latitude, + locationTopLeft!.longitude + ], + 'locationTopRight': [ + locationTopRight!.latitude, + locationTopRight!.longitude + ], + 'locationBottomLeft': [ + locationBottomLeft!.latitude, + locationBottomLeft!.longitude + ], + 'locationBottomRight': [ + locationBottomRight!.latitude, + locationBottomRight!.longitude + ], + "headOfFamily": parseStringFields(headOfFamily), + "availabilityOfDrinkingWater": parseStringFields(drinkingWater), + "drinkingWaterSource": sourceOfDrinkingWater != null + ? buildListForOptionWidget(sourceOfDrinkingWater!) + : "", + "areToiletsAvailableInHouse": parseStringFields(toiletFacility), + "noToiletsWhy": parseDependentField( + toiletFacility, + noToiletsWhy != null + ? buildListForOptionWidget(noToiletsWhy!) + : "", + "no"), + "alternativeForHouseholdToilet": parseDependentField( + toiletFacility, parseStringFields(communityToilet), "no"), + "statusOfEnvironmentalSanitation": + parseStringFields(environmentSanitationLevel), + "availabilityOfWaterInToilets": parseStringFields(runningWaterAvailable), + "numberOfTwoWheelers": parseStringFields(noOfTwoWheelers), + "numberOfThreeWheelers": parseStringFields(noOfThreeWheelers), + "numberOfFourWheelers": parseStringFields(noOfFourWheelers), + "brandsOfTwoThreeWheelers": twoThreeWheelManufacturer != null + ? buildListForOptionWidget(twoThreeWheelManufacturer!) + : "", + "brandsOfFourWheelers": fourWheelManufacturer != null + ? buildListForOptionWidget(fourWheelManufacturer!) + : "", + "locallyAvailableFoodsConsumed": localFoodMap != null + ? buildListForOptionWidget(localFoodMap!) + : "", + "doYouOwnCattle": isCattleOwned, + "incomeFromCattle": + parseDependentField(isCattleOwned, incomeFromCattle, "yes"), + "doYouOwnFarmLand": parseStringFields(isFarmLandOwned), + "cropsCultivated": parseDependentField( + isFarmLandOwned, + cropsCultivated != null + ? buildListForOptionWidget(cropsCultivated!) + : "", + "yes"), + "doYouPreserveSeeds": parseStringFields(isSeedsPreserved), + "typesOfSeedsPreserved": parseDependentField( + isSeedsPreserved, + preservedSeedsMap != null + ? buildListForOptionWidget(preservedSeedsMap!) + : "", + "yes"), + "treesOwnedIfAny": treesOwnedMap != null + ? buildListForOptionWidget(treesOwnedMap!) + : "", + "isKitchenGardenAvailable": parseStringFields(isKitchenGardenOwned), + "cropsInKitchenGarden": parseDependentField( + isKitchenGardenOwned, + kitchenGardenPlants != null + ? buildListForOptionWidget(kitchenGardenPlants!) + : "", + "yes"), + "address": + "$addressOne${addressTwo != null && addressTwo != "" ? "\n$addressTwo" : ""}\n$city", + "villageCode": parseStringFields(villageCode) + }; + } + + String? savedTime = DateFormat('kk:mm:ss, EEE d MMM').format(DateTime.now()); + + String? get dbLocationTopLeft { + if (locationTopLeft == null) { + return null; + } else { + Map data = locationTopLeft!.toJson(); + var encodedData = json.encode(data); + return encodedData; + } + } + + set dbLocationTopLeft(String? value) { + if (value == null) { + locationTopLeft = null; + } else { + final body = json.decode(value.trim()); + locationTopLeft = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + String? get dbLocationTopRight { + if (locationTopRight == null) { + return null; + } else { + Map data = locationTopRight!.toJson(); + var encodedData = json.encode(data); + return encodedData; + } + } + + set dbLocationTopRight(String? value) { + if (value == null) { + locationTopRight = null; + } else { + final body = json.decode(value.trim()); + locationTopRight = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + String? get dbLocationBottomLeft { + if (locationBottomLeft == null) { + return null; + } else { + Map data = locationBottomLeft!.toJson(); + var encodedData = json.encode(data); + return encodedData; + } + } + + set dbLocationBottomLeft(String? value) { + if (value == null) { + locationBottomLeft = null; + } else { + final body = json.decode(value.trim()); + locationBottomLeft = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + String? get dbLocationBottomRight { + if (locationBottomRight == null) { + return null; + } else { + Map data = locationBottomRight!.toJson(); + var encodedData = json.encode(data); + return encodedData; + } + } + + set dbLocationBottomRight(String? value) { + if (value == null) { + locationBottomRight = null; + } else { + final body = json.decode(value.trim()); + + locationBottomRight = new Position( + longitude: body['longitude'] ?? 0, + latitude: body['latitude'] ?? 0, + timestamp: DateTime.fromMicrosecondsSinceEpoch(body['timestamp']), + accuracy: body['accuracy'] ?? 0, + altitude: body['altitude'] ?? 0, + heading: body['heading'] ?? 0, + speed: body['speed'] ?? 0, + speedAccuracy: body['speedAccuracy'] ?? 0); + } + } + + String? get dbTwoThreeWheelManufacturer => twoThreeWheelManufacturer == null + ? null + : json.encode(twoThreeWheelManufacturer); + + set dbTwoThreeWheelManufacturer(String? value) { + if (value == null) { + twoThreeWheelManufacturer = null; + } else { + twoThreeWheelManufacturer = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbSourceOfDrinkingWater => + sourceOfDrinkingWater == null ? null : json.encode(sourceOfDrinkingWater); + + set dbSourceOfDrinkingWater(String? value) { + if (value == null) { + sourceOfDrinkingWater = null; + } else { + sourceOfDrinkingWater = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbTwoFourManufacturer => + fourWheelManufacturer == null ? null : json.encode(fourWheelManufacturer); + + set dbTwoFourManufacturer(String? value) { + if (value == null) { + fourWheelManufacturer = null; + } else { + fourWheelManufacturer = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbLocalFoodMap => + localFoodMap == null ? null : json.encode(localFoodMap); + + set dbLocalFoodMap(String? value) { + if (value == null) { + localFoodMap = null; + } else { + localFoodMap = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbPreservedSeedsMap => + preservedSeedsMap == null ? null : json.encode(preservedSeedsMap); + + set dbPreservedSeedsMap(String? value) { + if (value == null) { + preservedSeedsMap = null; + } else { + preservedSeedsMap = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbNoToiletsWhy => + noToiletsWhy == null ? null : json.encode(noToiletsWhy); + + set dbNoToiletsWhy(String? value) { + if (value == null) { + noToiletsWhy = null; + } else { + noToiletsWhy = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbCropsCultivated => + cropsCultivated == null ? null : json.encode(cropsCultivated); + + set dbCropsCultivated(String? value) { + if (value == null) { + cropsCultivated = null; + } else { + cropsCultivated = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbTreesOwnedMap => + treesOwnedMap == null ? null : json.encode(treesOwnedMap); + + set dbTreesOwnedMap(String? value) { + if (value == null) { + treesOwnedMap = null; + } else { + treesOwnedMap = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } + + String? get dbKitchenGardenPlants => + kitchenGardenPlants == null ? null : json.encode(kitchenGardenPlants); + + set dbKitchenGardenPlants(String? value) { + if (value == null) { + kitchenGardenPlants = null; + } else { + kitchenGardenPlants = Map.from( + json.decode(value).map((k, v) => MapEntry(k as String, v as bool))); + } + } +} diff --git a/lib/Screens/Background.dart b/lib/Screens/Background.dart deleted file mode 100644 index d474e7a..0000000 --- a/lib/Screens/Background.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:flutter/material.dart'; - -class Background extends StatelessWidget { - final Widget child; - - const Background({ - Key? key, - required this.child, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - Size size = MediaQuery.of(context).size; - return Container( - width: double.infinity, - height: size.height, - child: Stack( - alignment: Alignment.center, - children: [ - Positioned( - top: 0, - left: 0, - child: Image.asset( - "assets/images/main_top.png", - width: size.width * 0.35, - ), - ), - Positioned( - bottom: 0, - right: 0, - child: Image.asset( - "assets/images/login_bottom.png", - width: size.width * 0.4, - ), - ), - child, - ], - ), - ); - } -} diff --git a/lib/Screens/ChangePassword.dart b/lib/Screens/ChangePassword.dart new file mode 100644 index 0000000..7f275eb --- /dev/null +++ b/lib/Screens/ChangePassword.dart @@ -0,0 +1,343 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:geo_spatial/main.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:oktoast/oktoast.dart'; + +class ChangePassword extends StatefulWidget { + ChangePassword({Key? key, required this.userName}) : super(key: key); + final String userName; + + @override + _ChangePasswordState createState() => _ChangePasswordState(); +} + +class _ChangePasswordState extends State { + final _oldPasswordKey = GlobalKey(); + final _newPasswordKey = GlobalKey(); + final _newPasswordKeyRepeat = GlobalKey(); + + var _showPasswordOld = false; + var _showPasswordNew = false; + var _showPasswordNewRepeat = false; + + var _showProgressBar = false; + + final TextEditingController _oldPasswordController = TextEditingController(); + final TextEditingController _newPasswordController = TextEditingController(); + final TextEditingController _newPasswordControllerRepeat = + TextEditingController(); + + Future _makeLoginRequest( + String username, String currentPassword, String newPassword) async { + String url = NETWORK_ADDRESS; + var body = json + .encode({"password": newPassword, "currentPassword": currentPassword}); + + String jwt = await jwtToken; + + var res = await http + .put(Uri.http(url, '/api/changeUserPassword'), + headers: { + "Content-Type": "application/json", + 'user-auth-token': jwt + }, + body: body) + .timeout( + const Duration(seconds: 30), + onTimeout: () { + showToast("Server Timed out!"); + // Time has run out, do what you wanted to do. + return http.Response( + 'Error', 408); // Request Timeout response status code + }, + ); + + return res; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Color.fromRGBO(36, 37, 56, 1), + resizeToAvoidBottomInset: true, + appBar: AppBarBackButton('Change Password'), + body: Stack( + children: [ + SvgPicture.asset('assets/svg/profile_bg.svg', fit: BoxFit.fill), + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(20))), + child: CustomScrollView( + slivers: [ + SliverFillRemaining( + hasScrollBody: false, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + child: SvgPicture.asset( + 'assets/svg/storage_image.svg', + ), + height: 200, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 40.0, vertical: 20), + child: TextFormField( + obscureText: !_showPasswordOld, + key: _oldPasswordKey, + controller: _oldPasswordController, + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + keyboardType: TextInputType.visiblePassword, + decoration: InputDecoration( + suffixIcon: IconButton( + onPressed: () { + setState(() { + _showPasswordOld = !_showPasswordOld; + }); + }, + icon: Icon( + _showPasswordOld + ? Icons.visibility_off + : Icons.visibility, + color: colors.darkAccentColor, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.darkSecondaryTextColor, + width: 1.0)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.successColor, width: 1.0)), + label: Text( + "Enter current password", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Enter password here", + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value!.isNotEmpty) { + if (value.length <= 7) { + return "Password too small"; + } else { + return null; + } + } else + return "Please enter password"; + }, + autovalidateMode: AutovalidateMode.disabled, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 40.0, vertical: 20), + child: TextFormField( + obscureText: !_showPasswordNew, + controller: _newPasswordController, + key: _newPasswordKey, + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + keyboardType: TextInputType.visiblePassword, + decoration: InputDecoration( + suffixIcon: IconButton( + onPressed: () { + setState(() { + _showPasswordNew = !_showPasswordNew; + }); + }, + icon: Icon( + _showPasswordNew + ? Icons.visibility_off + : Icons.visibility, + color: colors.darkAccentColor, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.darkSecondaryTextColor, + width: 1.0)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.successColor, width: 1.0)), + label: Text( + "Enter new password", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Enter password here", + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value!.isNotEmpty) { + if (value.length <= 7) { + return "Password too small"; + } else if (value != + _newPasswordControllerRepeat.text) { + return "Password does not match"; + } else { + return null; + } + } else + return "Please enter password"; + }, + autovalidateMode: AutovalidateMode.disabled, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 40.0, vertical: 20), + child: TextFormField( + obscureText: !_showPasswordNewRepeat, + controller: _newPasswordControllerRepeat, + key: _newPasswordKeyRepeat, + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + keyboardType: TextInputType.visiblePassword, + decoration: InputDecoration( + suffixIcon: IconButton( + onPressed: () { + setState(() { + _showPasswordNewRepeat = + !_showPasswordNewRepeat; + }); + }, + icon: Icon( + _showPasswordNewRepeat + ? Icons.visibility_off + : Icons.visibility, + color: colors.darkAccentColor, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.darkSecondaryTextColor, + width: 1.0)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.successColor, width: 1.0)), + label: Text( + "Re-Enter new password", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Enter password here", + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value!.isNotEmpty) { + if (value.length <= 7) { + return "Password too small"; + } else if (value != _newPasswordController.text) { + return "Password does not match"; + } else { + return null; + } + } else + return "Please enter password"; + }, + autovalidateMode: AutovalidateMode.disabled, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 40.0, vertical: 20), + child: _showProgressBar + ? CircularProgressIndicator() + : SizedBox( + width: double.infinity, + height: 55, + child: ElevatedButton( + child: Text("Change Password", + style: TextStyle(fontSize: 16)), + style: ButtonStyle( + foregroundColor: + MaterialStateProperty.all( + colors.lightPrimaryTextColor), + backgroundColor: + MaterialStateProperty.all( + colors.darkPrimaryTextColor), + shape: MaterialStateProperty.all< + RoundedRectangleBorder>( + RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(20), + side: BorderSide( + color: + colors.darkSecondBackgroundColor)))), + onPressed: () async { + bool oldPassword = _oldPasswordKey + .currentState! + .validate(); + bool newPassword = _newPasswordKey + .currentState! + .validate(); + bool newPasswordRepeat = + _newPasswordKeyRepeat.currentState! + .validate(); + if (oldPassword && + newPassword && + newPasswordRepeat) { + try { + setState(() { + _showProgressBar = true; + }); + http.Response res = + await _makeLoginRequest( + widget.userName, + _oldPasswordController.text, + _newPasswordController.text); + + if (res.statusCode != 200) { + if(res.statusCode == 401){ + logout(context); + } + showToast(res.body); + } else { + storage.write( + key: JWT_STORAGE_KEY, + value: res.body); + showToast( + "Password changed successfully!"); + Navigator.pop(context); + } + + setState(() { + _showProgressBar = false; + }); + } catch (e) { + setState(() { + _showProgressBar = false; + }); + showToast( + "Something went wrong, please check your network connection or try again later", + ); + } + } + }, + ), + ), + ) + ], + ), + ) + ], + ), + ) + ], + ), + ); + } +} diff --git a/lib/Screens/CollectLocationWidget.dart b/lib/Screens/CollectLocationWidget.dart new file mode 100644 index 0000000..a586bed --- /dev/null +++ b/lib/Screens/CollectLocationWidget.dart @@ -0,0 +1,122 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Model/FamilyDataModels.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:geo_spatial/Widgets/FormPageView.dart'; +import 'package:geo_spatial/Widgets/LocationWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class CollectLocationWidget extends StatefulWidget { + const CollectLocationWidget({Key? key, this.modelData}) : super(key: key); + final FamilyMembersCommonDataModel? modelData; + + @override + _CollectLocationWidgetState createState() => _CollectLocationWidgetState(); +} + +class _CollectLocationWidgetState extends State { + @override + Widget build(BuildContext context) { + _onSubmit(bool isValid) async { + if (isValid) { + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: AutoSizeText( + "Please fill all fields!", + style: GoogleFonts.poppins(color: colors.errorColor), + ), + )); + } + } + + return WillPopScope( + onWillPop: () async { + final result = await showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: colors.darkScaffoldColor, + title: Text( + "Are you sure?", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + content: Text( + "All unsaved changes will be lost.", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + actions: [ + TextButton( + child: Text( + 'No', + style: + GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onPressed: () { + Navigator.pop(context, false); + }, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: colors.darkAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)))), + child: Text('Yes', + style: TextStyle(color: colors.darkPrimaryTextColor)), + onPressed: () async { + Navigator.pop(context, true); + }, + ), + ], + ), + ); + return result; + }, + child: Scaffold( + backgroundColor: colors.darkScaffoldColor, + appBar: AppBarBackButton('Get Location'), + body: SingleChildScrollView( + child: FormPageView([ + LocationWidgetField( + title: "Record location at top left part of the facility", + context: context, + defaultValue: widget.modelData?.locationTopLeft, + onSaved: (data) { + widget.modelData?.locationTopLeft = data; + }, + ), + LocationWidgetField( + title: "Record location at top right part of the facility", + context: context, + defaultValue: widget.modelData?.locationTopRight, + onSaved: (data) { + widget.modelData?.locationTopRight = data; + }, + ), + LocationWidgetField( + title: "Record location at bottom left part of the facility", + context: context, + defaultValue: widget.modelData?.locationBottomLeft, + onSaved: (data) { + widget.modelData?.locationBottomLeft = data; + }, + ), + LocationWidgetField( + title: "Record location at bottom right part of the facility", + context: context, + defaultValue: widget.modelData?.locationBottomRight, + onSaved: (data) { + widget.modelData?.locationBottomRight = data; + }, + ), + ], _onSubmit, onChange: (isValid) { + widget.modelData?.locationPageValid = isValid; + }, + submitMessage: + "Submit to Continue or go back to re-record location data", + note: + "The entered fields are automatically saved when changed and doesn't require submit to be clicked to save locally"), + )), + ); + } +} diff --git a/lib/Screens/CommunityDataCollection.dart b/lib/Screens/CommunityDataCollection.dart new file mode 100644 index 0000000..6b00726 --- /dev/null +++ b/lib/Screens/CommunityDataCollection.dart @@ -0,0 +1,266 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Model/CommunityDataModel.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Utils/StoreInstance.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:geo_spatial/Widgets/DropDownFormField.dart'; +import 'package:geo_spatial/Widgets/FormPageView.dart'; +import 'package:geo_spatial/Widgets/LocationWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:oktoast/oktoast.dart'; + +class CommunityDataCollection extends StatefulWidget { + CommunityDataCollection({Key? key, CommunityDataModel? this.modelData}) + : super(key: key); + + final modelData; + final List _publicResourceList = [ + 'Temple', + 'Church', + 'Mosque', + 'Community hall', + 'Community toilet', + 'Anganwadi centre', + 'Schools', + 'Colleges', + 'Market', + 'Wine shops', + 'PHC', + 'PDS', + 'Petty shops', + 'Whole sale shops', + 'Retail shops', + 'Vegetable shops', + 'Bakeries', + 'Hotels', + 'Food processing units' + ]; + + final List _villageCodeName = [ + 'THC', + 'PGP', + 'AMC', + 'KUP', + 'KAP', + 'NEP', + 'CGP', + 'JJN', + 'ETT' + ]; + + @override + _CommunityDataCollectionState createState() => + _CommunityDataCollectionState(); +} + +class _CommunityDataCollectionState extends State { + int count = 0; + late CommunityDataModel modelData; + var store; + + Future _makeRequest(var data, String node) async { + String url = NETWORK_ADDRESS; + var body = json.encode(data); + + var jwt = await jwtToken; + + var res = await http + .post(Uri.http(url, node), + headers: { + "Content-Type": "application/json", + "user-auth-token": jwt + }, + body: body) + .timeout( + const Duration(seconds: 30), + onTimeout: () { + // Time has run out, do what you wanted to do. + return http.Response( + 'Server Timed out!', 408); // Request Timeout response status code + }, + ); + return res; + } + + @override + Widget build(BuildContext context) { + modelData = widget.modelData ?? new CommunityDataModel(); + + _onSubmit(bool isValid) async { + if (isValid) { + var userId = await getUserID; + modelData.recordCollectingUserId = userId; + var progressContext; + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + progressContext = context; + return WillPopScope( + child: Dialog( + child: Padding( + padding: EdgeInsets.all(20), + child: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only(right: 20), + child: CircularProgressIndicator(), + ), + new Text( + "Uploading data", + style: TextStyle(color: Colors.black), + ), + ], + ), + ), + ), + onWillPop: () async => false); + }, + ); + try { + http.Response res = await _makeRequest( + modelData.toJson(), "/api/addCommunityBuilding"); + if (res.statusCode != 201) { + if (res.statusCode == 401) { + logout(context); + } + showToast(res.body); + } else { + Navigator.pop(context); + showToast("Data entered successfully!"); + } + } catch (e) { + debugPrint(e.toString()); + showToast( + "Something went wrong, please check your network connection or save your records to upload later", + position: ToastPosition.center, + backgroundColor: colors.darkAccentColor); + } + Navigator.of(progressContext!, rootNavigator: true).pop(); + } else { + showToast("Please fill all fields!"); + } + } + + _onSave() async { + var userId = await getUserID; + modelData.recordCollectingUserId = userId; + + store = await StoreInstance.getInstance(); + final box = store.box(); + int id = await box.putAsync(modelData); + + AlertDialog alertDialog = AlertDialog( + backgroundColor: colors.darkScaffoldColor, + title: Text( + 'Record Saved', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + content: Text('The record has been saved with record ID ${id}', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor)), + actions: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: colors.darkAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)))), + onPressed: () { + Navigator.of(context, rootNavigator: true).pop('dialog'); + }, + child: Text( + 'OK', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + ) + ], + ); + + showDialog( + context: context, builder: (BuildContext context) => alertDialog); + } + + return WillPopScope( + onWillPop: () async { + return await closePage(context); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + backgroundColor: colors.darkScaffoldColor, + appBar: AppBarBackButton('Community Data'), + body: SingleChildScrollView( + child: FormPageView( + [ + DropDownFormField( + defaultValue: modelData.resourceType, + list: widget._publicResourceList, + onSaved: (data) { + modelData.resourceType = data; + }, + title: "Choose type of resource to tag", + hint: "Select resource type", + errorField: "Please choose a resource to tag"), + LocationWidgetField( + title: "Record location at top left part of the facility", + defaultValue: modelData.locationTopLeft, + context: context, + onSaved: (data) { + modelData.locationTopLeft = data; + }, + ), + LocationWidgetField( + title: "Record location at top right part of the facility", + defaultValue: modelData.locationTopRight, + context: context, + onSaved: (data) { + modelData.locationTopRight = data; + }, + ), + LocationWidgetField( + title: "Record location at bottom left part of the facility", + defaultValue: modelData.locationBottomLeft, + context: context, + onSaved: (data) { + modelData.locationBottomLeft = data; + }, + ), + LocationWidgetField( + title: "Record location at bottom right part of the facility", + defaultValue: modelData.locationBottomRight, + context: context, + onSaved: (data) { + modelData.locationBottomRight = data; + }, + ), + DropDownFormField( + defaultValue: modelData.villageCode, + list: widget._villageCodeName, + onSaved: (data) { + modelData.villageCode = data; + }, + title: "Choose Village Code", + hint: "Select Village Code", + errorField: "Please choose a village code"), + ], + _onSubmit, + submitMessage: + "Submit record to server or Save record locally for later editing", + saveData: _onSave, + note: + "Note: Saving existing records will over-write the record and not create new one", + ), + ), + ), + ); + } + + @override + void dispose() { + super.dispose(); + } +} diff --git a/lib/Screens/DisplayUploadedCommunityData.dart b/lib/Screens/DisplayUploadedCommunityData.dart new file mode 100644 index 0000000..76164de --- /dev/null +++ b/lib/Screens/DisplayUploadedCommunityData.dart @@ -0,0 +1,275 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:geo_spatial/Screens/RenderJSONData.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:oktoast/oktoast.dart'; + +//TODO: Parse Data into Family Data Object +class DisplayVillageData extends StatefulWidget { + const DisplayVillageData({Key? key}) : super(key: key); + + @override + State createState() => _DisplayVillageDataState(); +} + +class _DisplayVillageDataState extends State { + bool isSearchOpen = false; + TextEditingController _textEditingController = new TextEditingController(); + + List _dataList = []; + List _mapData = []; + late List _searchList; + + initState() { + super.initState(); + _searchList = _dataList; + } + + Future _getCommonRecords() async { + String url = NETWORK_ADDRESS; + String jwt = await jwtToken; + + try { + var res = await http + .get(Uri.http(url, '/api/getCommonRecords/individualData'), headers: { + "Content-Type": "application/json", + 'user-auth-token': jwt + }).timeout( + const Duration(seconds: 30), + onTimeout: () { + showToast("Server Timed out!"); + return http.Response('Error', 408); + }, + ); + print(json.decode(res.body)); + + return res; + } catch (e) { + return http.Response(e.toString(), 408); + } + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _getCommonRecords(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + if (snapshot.requireData.statusCode != 200) { + return Scaffold( + appBar: AppBarBackButton("View Community Data"), + body: Center( + child: Text("Could not fetch data from server at this time"), + ), + ); + } + + try { + var dataJson = json.decode(snapshot.requireData.body); + _dataList.clear(); + _mapData.clear(); + for (var i in dataJson) { + _dataList.add(i["resourceType"]); + _mapData.add(i); + print(i); + } + } catch (e) { + print(e); + return Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBarBackButton("View Community Data"), + body: Center( + child: Text("Could not fetch data from server at this time"), + ), + ); + } + + return Scaffold( + backgroundColor: colors.darkScaffoldColor, + appBar: AppBarBackButton( + 'View Community Data', + actions: [ + IconButton( + splashRadius: 20, + icon: Icon( + Icons.search, + color: colors.darkAccentColor, + ), + onPressed: () { + setState(() { + isSearchOpen = !isSearchOpen; + _searchList = _dataList; + }); + }) + ], + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Visibility( + visible: isSearchOpen, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 20), + child: TextField( + onChanged: (text) { + setState(() { + _searchList = _dataList + .where((i) => i + .toLowerCase() + .contains(text.toLowerCase())) + .toList(); + }); + }, + controller: _textEditingController, + style: TextStyle(color: Colors.white), + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.darkSecondaryTextColor, + width: 1.0)), + contentPadding: + EdgeInsets.symmetric(horizontal: 10.0), + fillColor: colors.darkScaffoldColor, + prefixIcon: Icon( + Icons.search, + color: colors.darkAccentColor, + ), + label: Text( + "Search", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Search for records...", + ), + ), + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.all(20), + child: Container( + decoration: BoxDecoration( + color: colors.darkSecondBackgroundColor, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Color(0xBC252426), + blurRadius: 8.0, + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(12), + child: _searchList.isNotEmpty + ? ListView.builder( + itemCount: _searchList.length, + itemBuilder: + (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 3.0), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(5))), + elevation: 10, + color: colors.darkScaffoldColor, + child: ListTile( + contentPadding: EdgeInsets.symmetric( + vertical: 10, horizontal: 20.0), + minLeadingWidth: 30, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + RenderJSONData( + data: _mapData[ + index]))); + }, + //Pass a function which is called onSaved in the next page and add data to the class object + title: Text( + _searchList[index], + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20), + ), + subtitle: Text( + 'Click to view data', + style: GoogleFonts.poppins( + color: colors + .darkSecondaryTextColor), + ), + leading: SvgPicture.asset( + "assets/svg/user-id-icon.svg", + fit: BoxFit.fill, + ), + isThreeLine: true, + trailing: IconButton( + icon: Icon( + Icons.delete_forever, + color: colors.darkAccentColor, + ), + onPressed: () { + displayDialog( + context, + positiveFunction: () async { + var record = _mapData[index]; + Navigator.of(context).pop(); + + bool success = + await deleteRecord({ + "id": record["_id"] + }, "/api/getCommonRecords/deleteCommunityData", + context); + + if (success) { + _mapData.removeAt(index); + setState(() {}); + } + }, + negativeFunction: () { + Navigator.of(context).pop(); + }, + title: 'Delete record', + subTitle: + 'Are you sure you want to delete this record?', + ); + }, + ), + ), + ), + ); + }) + : Container( + width: double.infinity, + child: Center( + child: Text( + "No Results Found", + textAlign: TextAlign.center, + ), + )), + ), + ), + ), + ), + ], + ), + ); + } else { + return Scaffold( + appBar: AppBarBackButton("View Community Data"), + body: Center( + child: CircularProgressIndicator(), + )); + } + }); + } +} diff --git a/lib/Screens/DisplayUploadedData.dart b/lib/Screens/DisplayUploadedData.dart new file mode 100644 index 0000000..1e3690f --- /dev/null +++ b/lib/Screens/DisplayUploadedData.dart @@ -0,0 +1,41 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Screens/DisplayUploadedFamilyData.dart'; +import 'package:geo_spatial/Screens/DisplayUploadedCommunityData.dart'; + +import '../Widgets/AppBarBackButtonWidget.dart'; +import '../Widgets/DataCard.dart'; + +class DisplayUploadedData extends StatelessWidget { + const DisplayUploadedData({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBarBackButton("View Uploaded Records"), + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + DataCard( + 'Individual data', + 'Individual data entry for everyone in home', + 'assets/svg/female.svg', + //FamilyHomeScreen(), + DisplayFamilyData(), + Color(0xfff54b64), + Color(0xfff78361)), + DataCard( + 'Community Details', + 'Data entry for communities', + 'assets/svg/house.svg', + DisplayVillageData(), + Color(0xfff54b64), + Color(0xfff78361)), + + ], + ), + ), + ); + } +} diff --git a/lib/Screens/DisplayUploadedFamilyData.dart b/lib/Screens/DisplayUploadedFamilyData.dart new file mode 100644 index 0000000..8d8d5af --- /dev/null +++ b/lib/Screens/DisplayUploadedFamilyData.dart @@ -0,0 +1,275 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:geo_spatial/Screens/RenderJSONData.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:oktoast/oktoast.dart'; + +//TODO: Parse Data into Family Data Object +class DisplayFamilyData extends StatefulWidget { + const DisplayFamilyData({Key? key}) : super(key: key); + + @override + State createState() => _DisplayFamilyDataState(); +} + +class _DisplayFamilyDataState extends State { + bool isSearchOpen = false; + TextEditingController _textEditingController = new TextEditingController(); + + List _dataList = []; + List _mapData = []; + late List _searchList; + + initState() { + super.initState(); + _searchList = _dataList; + } + + Future _getCommonRecords() async { + String url = NETWORK_ADDRESS; + String jwt = await jwtToken; + + try { + var res = await http + .get(Uri.http(url, '/api/getCommonRecords/familyData'), headers: { + "Content-Type": "application/json", + 'user-auth-token': jwt + }).timeout( + const Duration(seconds: 30), + onTimeout: () { + showToast("Server Timed out!"); + return http.Response('Error', 408); + }, + ); + print(json.decode(res.body)); + + return res; + } catch (e) { + return http.Response(e.toString(), 408); + } + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _getCommonRecords(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + if (snapshot.requireData.statusCode != 200) { + return Scaffold( + appBar: AppBarBackButton("View Family Data"), + body: Center( + child: Text("Could not fetch data from server at this time"), + ), + ); + } + + try { + var dataJson = json.decode(snapshot.requireData.body); + _dataList.clear(); + _mapData.clear(); + for (var i in dataJson) { + _dataList.add(i["FamilyUIN"]); + _mapData.add(i); + print(i); + } + } catch (e) { + print(e); + return Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBarBackButton("View Family Data"), + body: Center( + child: Text("Could not fetch data from server at this time"), + ), + ); + } + + return Scaffold( + backgroundColor: colors.darkScaffoldColor, + appBar: AppBarBackButton( + 'View Family Data', + actions: [ + IconButton( + splashRadius: 20, + icon: Icon( + Icons.search, + color: colors.darkAccentColor, + ), + onPressed: () { + setState(() { + isSearchOpen = !isSearchOpen; + _searchList = _dataList; + }); + }) + ], + ), + body: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Visibility( + visible: isSearchOpen, + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 20), + child: TextField( + onChanged: (text) { + setState(() { + _searchList = _dataList + .where((i) => i + .toLowerCase() + .contains(text.toLowerCase())) + .toList(); + }); + }, + controller: _textEditingController, + style: TextStyle(color: Colors.white), + decoration: InputDecoration( + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.darkSecondaryTextColor, + width: 1.0)), + contentPadding: + EdgeInsets.symmetric(horizontal: 10.0), + fillColor: colors.darkScaffoldColor, + prefixIcon: Icon( + Icons.search, + color: colors.darkAccentColor, + ), + label: Text( + "Search", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Search for records...", + ), + ), + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.all(20), + child: Container( + decoration: BoxDecoration( + color: colors.darkSecondBackgroundColor, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Color(0xBC252426), + blurRadius: 8.0, + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(12), + child: _searchList.isNotEmpty + ? ListView.builder( + itemCount: _searchList.length, + itemBuilder: + (BuildContext context, int index) { + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 3.0), + child: Card( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(5))), + elevation: 10, + color: colors.darkScaffoldColor, + child: ListTile( + contentPadding: EdgeInsets.symmetric( + vertical: 10, horizontal: 20.0), + minLeadingWidth: 30, + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + RenderJSONData( + data: _mapData[ + index]))); + }, + //Pass a function which is called onSaved in the next page and add data to the class object + title: Text( + _searchList[index], + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20), + ), + subtitle: Text( + 'Click to view data', + style: GoogleFonts.poppins( + color: colors + .darkSecondaryTextColor), + ), + leading: SvgPicture.asset( + "assets/svg/user-id-icon.svg", + fit: BoxFit.fill, + ), + isThreeLine: true, + trailing: IconButton( + icon: Icon( + Icons.delete_forever, + color: colors.darkAccentColor, + ), + onPressed: () { + displayDialog( + context, + positiveFunction: () async { + var record = _mapData[index]; + Navigator.of(context).pop(); + + bool success = + await deleteRecord({ + "id": record["_id"] + }, "/api/getCommonRecords/deleteFamilyData", + context); + + if (success) { + _mapData.removeAt(index); + setState(() {}); + } + }, + negativeFunction: () { + Navigator.of(context).pop(); + }, + title: 'Delete record', + subTitle: + 'Are you sure you want to delete this record?', + ); + }, + ), + ), + ), + ); + }) + : Container( + width: double.infinity, + child: Center( + child: Text( + "No Results Found", + textAlign: TextAlign.center, + ), + )), + ), + ), + ), + ), + ], + ), + ); + } else { + return Scaffold( + appBar: AppBarBackButton("View Family Data"), + body: Center( + child: CircularProgressIndicator(), + )); + } + }); + } +} diff --git a/lib/Screens/FamilyDetails.dart b/lib/Screens/FamilyDetails.dart new file mode 100644 index 0000000..b22b393 --- /dev/null +++ b/lib/Screens/FamilyDetails.dart @@ -0,0 +1,606 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Model/FamilyDataModels.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:geo_spatial/Widgets/CheckBoxAddExtraDialog.dart'; +import 'package:geo_spatial/Widgets/ConditionalRenderWidget.dart'; +import 'package:geo_spatial/Widgets/DropDownFormField.dart'; +import 'package:geo_spatial/Widgets/FormPageView.dart'; +import 'package:geo_spatial/Widgets/OptionsFormWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class FamilyDetails extends StatefulWidget { + const FamilyDetails({Key? key, this.modelData}) : super(key: key); + final FamilyMembersCommonDataModel? modelData; + + @override + State createState() => _FamilyDetailsState(); +} + +class _FamilyDetailsState extends State { + _onSubmit(bool isValid) { + if (isValid) { + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: AutoSizeText( + "Please fill all fields!", + style: TextStyle(color: colors.errorColor), + ), + )); + } + } + + final PageController controller = PageController(initialPage: 0); + + final List> formKeyList = + List.generate(3, (index) => GlobalObjectKey(index)); + final error = [false, false, false]; + + var two_three_mfg = { + 'TVS': false, + 'Hero': false, + 'Honda': false, + 'Piaggio (scooters)': false, + 'Suzuki': false, + 'Yamaha': false, + 'Royal Enfield': false, + 'Bajaj': false, + 'Mahindra & Mahindra': false, + 'Force': false, + 'Tempo': false, + }; + + final List _villageCodeName = [ + 'THC', + 'PGP', + 'AMC', + 'KUP', + 'KAP', + 'NEP', + 'CGP', + 'JJN', + 'ETT' + ]; + + var four_mfg = { + 'Maruti Suzuki': false, + 'Hyundai': false, + 'Tata': false, + 'Ashok Leyland': false, + 'Eicher': false, + 'Ford': false, + 'Toyota': false, + 'Tafe': false, + 'Volkswagen': false, + 'Force': false, + 'Tempo': false, + 'Renault': false, + 'Skoda': false, + 'Mitsubishi': false, + }; + + var noToiletsWhy = { + 'Lack of space': false, + 'Lack of money': false, + 'Habit of open defecation': false, + 'Using community toilets': false + }; + + var seeds_preserved = { + 'Country Seeds': false, + 'Indigenous Seeds': false, + 'Hybrid Seeds': false + }; + + var local_food = { + 'brinjal': false, + 'tomato': false, + 'drumstick': false, + 'ladies finger': false, + 'banana': false, + 'potato': false, + 'drumstick leaves': false, + 'beans': false, + 'long beans': false, + }; + + var trees_owned = { + 'Moringa Tree': false, + 'Guava Tree': false, + 'Papaya Tree': false, + 'Pomegranate Tree': false, + 'Custard Apple Tree': false, + 'Banana': false, + 'Indian Gooseberry': false + }; + + var garden_plants = { + 'Tapioca': false, + 'Tomato': false, + 'Brinjal': false, + 'Ladies finger': false, + 'Chili': false, + 'Mint': false, + 'Spinach': false, + 'Ridge Guard': false, + 'Bitter Guard': false, + 'Cluster Beans': false, + 'Long Beans': false, + 'Snake Guard': false + }; + + var water_sources = { + 'Lake': false, + 'Pond': false, + 'Groundwater': false, + 'Borewell': false, + 'Well': false, + 'Tap': false, + 'Water supply': false, + 'Lorry/Van': false + }; + + _getUserNameList() { + var list = []; + widget.modelData!.individualDataListTransient.forEach((element) { + if (element.userName != null) if (element.userName != "") + list.add(element.userName); + }); + if (!list.contains(widget.modelData!.headOfFamily)) + widget.modelData!.headOfFamily = null; + return list; + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + return await closePage(context); + }, + child: Scaffold( + resizeToAvoidBottomInset: true, + backgroundColor: colors.darkScaffoldColor, + appBar: AppBarBackButton('Family Details'), + body: SingleChildScrollView( + child: FormPageView( + [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: DropDownFormField( + list: _getUserNameList(), + defaultValue: widget.modelData!.headOfFamily, + onSaved: (value) { + widget.modelData!.headOfFamily = value; + }, + title: 'Head of family', + hint: 'Choose the head of family', + errorField: 'Please choose a head of family', + autoValidateMode: AutovalidateMode.onUserInteraction, + )), + DropDownFormField( + defaultValue: widget.modelData!.villageCode, + list: _villageCodeName, + onSaved: (data) { + widget.modelData!.villageCode = data; + }, + title: "Choose Village Code", + hint: "Select Village Code", + errorField: "Please choose a village code"), + OptionsWidget( + options: [ + ['Yes', 'yes'], + ['No', 'no'] + ], + defaultValue: widget.modelData!.drinkingWater, + onSaved: (val) { + widget.modelData!.drinkingWater = val; + }, + title: "Do you have drinking water available?"), + CheckBoxAddExtraAlertDialog( + singleOption: false, + dataMap: widget.modelData!.sourceOfDrinkingWater ?? + water_sources, + onSaved: (val) { + widget.modelData!.sourceOfDrinkingWater = val; + }, + validator: (data) {}, + hint: "Select source / empty if none", + title: "Source of Water", + context: context, + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: ConditionalRenderWidget( + title: "Do you have toilet facilities?", + defaultValue: widget.modelData!.toiletFacility, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.modelData!.toiletFacility = val; + }, + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: Container(), + conditionalNegativeWidget: Column( + children: [ + Padding( + padding: + const EdgeInsets.symmetric(vertical: 25.0), + child: CheckBoxAddExtraAlertDialog( + title: 'Why do you not have a toilet?', + hint: 'Please choose reason', + singleOption: false, + context: context, + dataMap: widget.modelData!.noToiletsWhy ?? + noToiletsWhy, + onSaved: (val) { + widget.modelData?.noToiletsWhy = val; + }, + errorField: "Please choose a reason", + autoValidateMode: + AutovalidateMode.onUserInteraction, + ), + ), + OptionsWidget( + options: [ + ['Yes', 'yes'], + ['No', 'no'] + ], + defaultValue: widget.modelData!.communityToilet, + onSaved: (val) { + widget.modelData!.communityToilet = val; + }, + title: "Community toilet?"), + ], + ), + ), + ), + OptionsWidget( + options: [ + ['Clean', 'clean'], + ['Unclean', 'unclean'] + ], + defaultValue: + widget.modelData!.environmentSanitationLevel, + onSaved: (val) { + widget.modelData!.environmentSanitationLevel = val; + }, + title: "Environmental sanitation level: "), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + DropDownFormField( + list: ['0', '1', '2', '3', '4', '5', 'More'], + hint: "Select the highest", + title: "No. of two wheelers", + defaultValue: widget.modelData!.noOfTwoWheelers, + onSaved: (val) { + widget.modelData!.noOfTwoWheelers = val; + }, + errorField: "Please choose a valid number", + ), + DropDownFormField( + list: ['0', '1', '2', '3', '4', '5', 'More'], + hint: "Select the highest", + title: "No. of three wheelers", + defaultValue: widget.modelData!.noOfThreeWheelers, + onSaved: (val) { + widget.modelData!.noOfThreeWheelers = val; + }, + errorField: "Please choose a valid number", + ), + CheckBoxAddExtraAlertDialog( + title: 'Two/Three wheeler brand', + hint: 'Please choose brands', + singleOption: false, + context: context, + dataMap: widget.modelData!.twoThreeWheelManufacturer ?? + two_three_mfg, + onSaved: (val) { + widget.modelData?.twoThreeWheelManufacturer = val; + }, + errorField: "Please choose a brand", + validator: (val) {}, + autoValidateMode: AutovalidateMode.onUserInteraction, + ), + DropDownFormField( + list: ['0', '1', '2', '3', '4', '5', 'More'], + hint: "Select the highest", + title: "No. of four wheelers", + errorField: "Please choose a valid number", + defaultValue: widget.modelData!.noOfFourWheelers, + onSaved: (val) { + widget.modelData!.noOfFourWheelers = val; + }, + ), + CheckBoxAddExtraAlertDialog( + title: 'Four wheeler brand', + hint: 'Please choose brand', + singleOption: false, + context: context, + dataMap: + widget.modelData!.fourWheelManufacturer ?? four_mfg, + onSaved: (val) { + widget.modelData?.fourWheelManufacturer = val; + }, + validator: (val) {}, + errorField: "Please choose a brand", + autoValidateMode: AutovalidateMode.onUserInteraction, + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + OptionsWidget( + options: [ + ['Yes', 'yes'], + ['No', 'no'] + ], + defaultValue: widget.modelData!.runningWaterAvailable, + onSaved: (val) { + widget.modelData!.runningWaterAvailable = val; + }, + title: "Is running water available?"), + ConditionalRenderWidget( + title: "Do you own cattle?", + defaultValue: widget.modelData!.isCattleOwned, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.modelData!.isCattleOwned = val; + }, + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: Padding( + padding: const EdgeInsets.only( + left: 10.0, right: 10.0, top: 20.0), + child: TextFormField( + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + initialValue: widget.modelData!.incomeFromCattle, + onSaved: (val) { + widget.modelData!.incomeFromCattle = val; + }, + decoration: InputDecoration( + contentPadding: EdgeInsets.all(7.0), + hintText: "Enter income in Rupees", + label: AutoSizeText( + 'Income from cattle/month', + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + )), + validator: (value) { + if (value == null || value == "") { + return "Please enter cattle income"; + } + if (int.tryParse(value) == null) { + return "Income can only have numbers"; + } + }, + autovalidateMode: AutovalidateMode.always, + keyboardType: TextInputType.number, + ), + ), + conditionalNegativeWidget: Container()), + ConditionalRenderWidget( + title: "Do you own farmland?", + defaultValue: widget.modelData!.isFarmLandOwned, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.modelData!.isFarmLandOwned = val; + }, + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: CheckBoxAddExtraAlertDialog( + title: 'Crops Cultivated', + hint: 'Choose cultivated crops', + singleOption: false, + context: context, + dataMap: widget.modelData!.cropsCultivated ?? + seeds_preserved, + onSaved: (val) { + widget.modelData!.cropsCultivated = val; + }, + ), + conditionalNegativeWidget: Container()), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ConditionalRenderWidget( + title: "Do you preserve seeds?", + defaultValue: widget.modelData!.isSeedsPreserved, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.modelData!.isSeedsPreserved = val; + }, + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: CheckBoxAddExtraAlertDialog( + title: 'Seeds Preserved', + hint: 'Choose preserved seeds', + singleOption: false, + context: context, + dataMap: widget.modelData!.preservedSeedsMap ?? + seeds_preserved, + onSaved: (val) { + widget.modelData!.preservedSeedsMap = val; + }, + ), + conditionalNegativeWidget: Container()), + CheckBoxAddExtraAlertDialog( + title: 'Trees owned', + hint: 'Choose trees owned', + singleOption: false, + context: context, + validator: (val) {}, + dataMap: widget.modelData!.treesOwnedMap ?? trees_owned, + onSaved: (val) { + widget.modelData!.treesOwnedMap = val; + }, + ), + CheckBoxAddExtraAlertDialog( + title: 'Local foods consumed', + hint: 'Choose your resource', + //TODO: Change variable to local food + validator: (val) {}, + dataMap: widget.modelData!.localFoodMap ?? local_food, + onSaved: (val) { + widget.modelData!.localFoodMap = val; + }, + singleOption: false, + context: context, + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + ConditionalRenderWidget( + title: "Do you have a kitchen garden?", + defaultValue: + widget.modelData!.isKitchenGardenOwned, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.modelData!.isKitchenGardenOwned = val; + }, + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: Padding( + padding: EdgeInsets.only(bottom: 30), + child: CheckBoxAddExtraAlertDialog( + title: 'Kitchen Garden plants', + hint: 'Choose garden plants', + singleOption: false, + context: context, + dataMap: + widget.modelData!.kitchenGardenPlants ?? + garden_plants, + onSaved: (val) { + widget.modelData!.kitchenGardenPlants = val; + }, + ), + ), + conditionalNegativeWidget: Container()), + Align( + alignment: Alignment.topLeft, + child: Padding( + padding: const EdgeInsets.only( + left: 10.0, right: 10.0, bottom: 15.0), + child: Text( + "Address", + style: GoogleFonts.montserrat( + fontSize: 15.0, + color: colors.darkPrimaryTextColor), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 10.0, right: 10.0, bottom: 70.0), + child: TextFormField( + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + initialValue: widget.modelData!.addressOne, + onSaved: (val) { + widget.modelData!.addressOne = val; + }, + decoration: InputDecoration( + label: Text( + "First Line", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Please enter first line", + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value == "") { + return "Enter First Line"; + } + }, + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 10.0, right: 10.0, bottom: 70.0), + child: TextFormField( + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + initialValue: widget.modelData!.addressTwo, + onSaved: (val) { + widget.modelData!.addressTwo = val; + }, + decoration: InputDecoration( + label: Text( + "Second Line", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Please enter second line", + contentPadding: EdgeInsets.all(7.0), + ), + ), + ), + Padding( + padding: const EdgeInsets.only( + left: 10.0, right: 10.0, bottom: 70.0), + child: TextFormField( + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + initialValue: widget.modelData!.city, + onSaved: (val) { + widget.modelData!.city = val; + }, + decoration: InputDecoration( + label: Text( + "City", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Please enter city", + contentPadding: EdgeInsets.all(7.0), + ), + ), + ), + ], + ), + ], + ) + ], + _onSubmit, + onChange: (isValid) { + widget.modelData?.commonDetailsValid = isValid; + }, + submitMessage: "Submit to Continue or go back to re-record data", + note: + "The entered fields are automatically saved when changed and doesn't require submit to be clicked to save locally", + )))); + } +} diff --git a/lib/Screens/FamilyHomeScreen.dart b/lib/Screens/FamilyHomeScreen.dart new file mode 100644 index 0000000..32273ff --- /dev/null +++ b/lib/Screens/FamilyHomeScreen.dart @@ -0,0 +1,290 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Model/FamilyDataModels.dart'; +import 'package:geo_spatial/Screens/FamilyDetails.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Utils/StoreInstance.dart'; +import 'package:geo_spatial/Widgets/AddRemoveBoxWidget.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:geo_spatial/Widgets/DataCard.dart'; +import 'package:geo_spatial/objectbox.g.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:oktoast/oktoast.dart'; +import 'CollectLocationWidget.dart'; +import 'package:http/http.dart' as http; + +class FamilyHomeScreen extends StatefulWidget { + FamilyHomeScreen({Key? key, this.modelData}) : super(key: key); + + @override + State createState() => _FamilyHomeScreenState(); + final modelData; +} + +FamilyMembersCommonDataModel? modelData; + +class _FamilyHomeScreenState extends State { + void initState() { + super.initState(); + setState(() { + if (modelData == null) + modelData = widget.modelData ?? new FamilyMembersCommonDataModel(); + for (var i in modelData!.individualDataList) { + modelData!.individualDataListTransient.add(i); + } + }); + } + + Future _makeRequest(var data, String node) async { + String url = NETWORK_ADDRESS; + var body = json.encode(data); + + var jwt = await jwtToken; + + var res = await http + .post(Uri.http(url, node), + headers: { + "Content-Type": "application/json", + "user-auth-token": jwt + }, + body: body) + .timeout( + const Duration(seconds: 30), + onTimeout: () { + showToast("Server Timed out!"); + // Time has run out, do what you wanted to do. + return http.Response( + 'Error', 408); // Request Timeout response status code + }, + ); + return res; + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: () async { + return await closePage(context); + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBarBackButton('Individual Data'), + backgroundColor: colors.darkScaffoldColor, + body: SafeArea( + child: Column( + children: [ + AddRemoveBoxWidget( + modelData: modelData, + ), + DataCard( + "\nCollect Common Details", + "", + "assets/svg/house.svg", + FamilyDetails( + modelData: modelData, + ), + Color(0xfff54b64), + Color(0xfff78361)), + DataCard( + "Record GPS Data", + "Make sure GPS is enabled", + "assets/svg/map.svg", + CollectLocationWidget(modelData: modelData), + Color(0xfff54b64), + Color(0xfff78361)), + Padding( + padding: EdgeInsets.only( + bottom: 10.0, left: 10.0, right: 10.0, top: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + child: Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: ElevatedButton( + child: + Text("Submit", style: TextStyle(fontSize: 14)), + style: ButtonStyle( + foregroundColor: + MaterialStateProperty.all( + Colors.white), + backgroundColor: + MaterialStateProperty.all( + colors.darkSecondBackgroundColor), + shape: MaterialStateProperty.all< + RoundedRectangleBorder>( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + side: BorderSide( + color: colors + .darkSecondBackgroundColor)))), + onPressed: () async { + bool isValid = true; + isValid &= modelData!.commonDetailsValid! && + modelData!.locationPageValid!; + + for (var i + in modelData!.individualDataListTransient) { + isValid &= i.dataValid!; + } + + if (isValid) { + var userId = await getUserID; + modelData!.recordCollectingUserId = userId; + var progressContext; + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + progressContext = context; + return WillPopScope( + child: Dialog( + child: Padding( + padding: EdgeInsets.all(20), + child: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only( + right: 20), + child: + CircularProgressIndicator(), + ), + new Text( + "Uploading data", + style: TextStyle( + color: Colors.black), + ), + ], + ), + ), + ), + onWillPop: () async => false); + }, + ); + try { + http.Response res = await _makeRequest( + modelData!.toJson(), + "/api/IndividualData"); + if (res.statusCode != 201) { + if(res.statusCode == 401){ + logout(context); + } + showToast(res.body); + } else { + Navigator.pop(context); + showToast("Data entered successfully!"); + } + } catch (e) { + showToast( + "Something went wrong, please check your network connection or save your records to upload later", + position: ToastPosition.center, + backgroundColor: colors.darkAccentColor); + } + Navigator.of(progressContext!, + rootNavigator: true) + .pop(); + } else { + showToast("Please fill all fields!"); + } + }), + ), + ), + Expanded( + child: Padding( + padding: EdgeInsets.only( + left: 10, right: 10, top: 5, bottom: 10), + child: ElevatedButton( + child: Text("Save", + style: TextStyle( + fontSize: 14, color: Colors.black)), + style: ButtonStyle( + foregroundColor: + MaterialStateProperty.all( + Colors.white), + backgroundColor: + MaterialStateProperty.all( + Colors.white), + shape: MaterialStateProperty.all< + RoundedRectangleBorder>( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + side: + BorderSide(color: Colors.white)))), + onPressed: () async { + var userId = await getUserID; + modelData!.recordCollectingUserId = userId; + var store = await StoreInstance.getInstance(); + Box individualDataBox = + store.box(); + + await individualDataBox.putMany( + modelData!.individualDataListTransient); + + modelData!.individualDataList.clear(); + modelData!.individualDataList.addAll( + modelData!.individualDataListTransient); + + Box box = + store.box(); + int id = await box.put(modelData); + + AlertDialog alertDialog = AlertDialog( + backgroundColor: colors.darkScaffoldColor, + title: Text( + 'Record Saved', + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + ), + content: Text( + 'The Record has been saved with record ID ${id}', + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor)), + actions: [ + ElevatedButton( + onPressed: () { + Navigator.of(context, rootNavigator: true) + .pop('dialog'); + }, + child: Text( + 'OK', + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + ), + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(20)), + ), + primary: colors.darkAccentColor), + ) + ], + ); + + showDialog( + context: context, + builder: (BuildContext context) => + alertDialog); + }), + ), + ) + ], + ), + ), + ], + ), + ), + ), + ); + } + + @override + void dispose() { + super.dispose(); + modelData!.individualDataListTransient.clear(); + modelData = null; + } +} diff --git a/lib/Screens/FamilyMemberAdd.dart b/lib/Screens/FamilyMemberAdd.dart index 6a10c9e..672087f 100644 --- a/lib/Screens/FamilyMemberAdd.dart +++ b/lib/Screens/FamilyMemberAdd.dart @@ -1,48 +1,939 @@ import 'package:flutter/material.dart'; -import 'package:geo_spatial/Widgets/Datepicker.dart'; +import 'package:geo_spatial/Model/FamilyDataModels.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/DarkTheme.dart'; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:geo_spatial/Widgets/CheckBoxAddExtraDialog.dart'; +import 'package:geo_spatial/Widgets/ConditionalRenderWidget.dart'; +import 'package:geo_spatial/Widgets/DatePickerWidget.dart'; +import 'package:geo_spatial/Widgets/DropDownFormField.dart'; +import 'package:geo_spatial/Widgets/FormPageView.dart'; +import 'package:geo_spatial/Widgets/GenderWidget.dart'; +import 'package:geo_spatial/Widgets/IncomeWithTypeTextField.dart'; +import 'package:geo_spatial/Widgets/NestedOptionWidgetFormField.dart'; +import 'package:geo_spatial/Widgets/NestedOptionsWidget.dart'; +import 'package:geo_spatial/Widgets/OptionsFormWidget.dart'; +import 'package:geo_spatial/Widgets/StartingEndingTimeWidget.dart'; +import 'package:geo_spatial/Widgets/TagTextWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; class FamilyMemberAdd extends StatefulWidget { - const FamilyMemberAdd({Key? key}) : super(key: key); + const FamilyMemberAdd( + {Key? key, + this.familyMemberIndividualDataModel, + this.dataModel, + this.index}) + : super(key: key); + final FamilyMemberIndividualDataModel? familyMemberIndividualDataModel; + final FamilyMembersCommonDataModel? dataModel; + final int? index; @override _FamilyMemberAddState createState() => _FamilyMemberAddState(); } class _FamilyMemberAddState extends State { - final _formKey = GlobalKey(); + bool dailyWageWorker = false; + + _onSubmit(bool isValid) { + setState(() { + isPageValid = isValid; + }); + + if (isValid) { + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + "Please fill all fields!", + style: GoogleFonts.poppins(color: colors.errorColor), + ), + )); + } + } + + bool isPageValid = false; + int count = 0; + + var vulnerabilities = { + 'Widower (M)': false, + 'Widow (F)': false, + 'Divorcee': false, + 'Differently Abled': false, + 'Pregnant Woman': false, + 'Lactating Mother': false, + 'Elderly (>60 years)': false, + 'Children below 2 years': false, + }; + + var occupations = { + 'Clerical support worker': false, + 'Services and sales worker': false, + 'Agricultural, forestry, fishery worker': false, + 'Professional': false, + 'Technician and associate professionals': false, + 'Craft and related trades workers': false, + 'Plant/Machine Operators and Assemblers': false, + 'Elementary occupations': false, + 'Armed Forces occupations': false, + 'Unemployed': false, + 'Studying': false, + }; + + var privateClinicReasons = { + 'Better treatment and personalised care': false, + 'Easy to access': false, + 'Less waiting time': false + }; + + var frequentAilments = { + 'Cold and Flu': false, + 'Diarrhoea': false, + 'Headaches': false, + 'Fever': false + }; + + var communicableDiseases = { + 'COVID': false, + 'Typhoid': false, + 'Dengue': false, + 'Malaria': false, + 'HIV/AIDS': false + }; + + var nonCommunicableDiseases = { + 'Cardiovascular disease': false, + 'Diabetes': false, + 'Treatable cancers': false, + 'Hypertension': false + }; + + var tobaccoProducts = { + 'Normal tobacco': false, + 'Hans': false, + 'Betel nuts': false, + 'Beedi': false + }; @override Widget build(BuildContext context) { - return Scaffold( + return WillPopScope( + onWillPop: () async { + return await closePage(context); + }, + child: Scaffold( + resizeToAvoidBottomInset: true, + backgroundColor: colors.darkScaffoldColor, + appBar: AppBarBackButton('Add Family Member'), body: SingleChildScrollView( - child: Column( - children: [ - Form( - key: _formKey, - child: Column( + child: FormPageView( + [ + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - TextFormField( - validator: (value) { - if (value == null || value.isEmpty) { - return 'Please enter the name'; + Padding( + padding: const EdgeInsets.only(left: 10.0, right: 10.0), + child: TextFormField( + initialValue: + widget.familyMemberIndividualDataModel?.userName, + onSaved: (String? data) async { + /** + * If condition to check if user name is equal to the HeadofFamily + * HeadOfFamily value updated as well + */ + if (widget.dataModel!.headOfFamily != null) { + if (widget.dataModel!.headOfFamily == + widget + .familyMemberIndividualDataModel!.userName) { + widget.dataModel!.headOfFamily = data; + } + } + widget.familyMemberIndividualDataModel!.userName = data; + }, + style: darkTheme.DarkTheme.textTheme.bodyText2, + decoration: InputDecoration( + //isDense: true, + label: Text( + "Name", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Please enter name", + + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value == "") { + return "Please enter a name"; + } else + return null; + }, + autovalidateMode: AutovalidateMode.onUserInteraction, + ), + ), + DatePickerWidget( + defaultDate: + widget.familyMemberIndividualDataModel?.dateOfBirth, + context: context, + title: "Date of Birth", + hint: "Choose a date", + autoValidateMode: AutovalidateMode.onUserInteraction, + onSaved: (data) { + widget.familyMemberIndividualDataModel!.dateOfBirth = + data; + }, + validator: (val) { + if (val != null) if (val.isAfter(DateTime.now())) { + return 'Please choose a valid date'; } - return null; }, ), - OutlinedButton( - onPressed: () { - if (_formKey.currentState!.validate() == true) { - print('Form submitted successfully'); - //TODO: Add logic to store locally and to lazy upload to database - } + GenderPickerWidget( + initialGender: + widget.familyMemberIndividualDataModel?.gender, + onChanged: (val) { + widget.familyMemberIndividualDataModel?.gender = val; + }, + onSaved: (val) { + }, + ), + Padding( + padding: const EdgeInsets.only(left: 10.0, right: 10.0), + child: TextFormField( + initialValue: + widget.familyMemberIndividualDataModel?.phoneNumber, + style: darkTheme.DarkTheme.textTheme.bodyText2, + keyboardType: TextInputType.number, + decoration: InputDecoration( + label: Text( + "Phone Number", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + helperText: + "Leave empty if person is not willing to share", + + hintText: "Please enter 10 digit phone", + + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value == "" || value == null) + return null; + else if (int.tryParse(value) == null) { + return "Phone number can only have numbers"; + } else if (value.length != 10) { + return "Enter a valid Phone Number"; + } else + return null; + }, + onSaved: (data) { + widget.familyMemberIndividualDataModel!.phoneNumber = + data; + }, + autovalidateMode: AutovalidateMode.onUserInteraction, + ), + ), + DropDownFormField( + defaultValue: widget.familyMemberIndividualDataModel! + .educationQualification, + list: [ + 'None', + 'Elementary', + 'Secondary', + 'Higher Secondary', + 'Bachelor\'s', + 'Master\'s' + ], + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .educationQualification = data; + }, + hint: "Select the highest", + title: "Educational qualification", + errorField: "Please choose a qualification", + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + CheckBoxAddExtraAlertDialog( + title: 'Vulnerabilities', + hint: 'Please choose a vulnerability', + dataMap: widget + .familyMemberIndividualDataModel!.vulnerabilities ?? + vulnerabilities, + singleOption: false, + context: context, + onSaved: (map) { + widget.familyMemberIndividualDataModel!.vulnerabilities = + map; + }, + validator: (val) {}, + errorField: "Please choose a vulnerability / None", + autoValidateMode: AutovalidateMode.onUserInteraction, + ), + OptionsWidget( + defaultValue: + widget.familyMemberIndividualDataModel!.dailyWageWorker, + autoValidateMode: AutovalidateMode.onUserInteraction, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onChanged: (val) { + setState(() { + dailyWageWorker = val == "yes"; + }); + }, + title: "Daily wage worker?", + onSaved: (val) { + widget.familyMemberIndividualDataModel!.dailyWageWorker = + val; + }, + ), + ConditionalRenderWidget( + title: "Employed?", + onSaved: (val) { + widget.familyMemberIndividualDataModel!.employed = val; + }, + defaultValue: + widget.familyMemberIndividualDataModel!.employed, + conditionalNegativeWidget: ConditionalRenderWidget( + title: 'Student?', + onSaved: (val) { + widget.familyMemberIndividualDataModel!.student = val; + }, + defaultValue: + widget.familyMemberIndividualDataModel!.student, + options: [ + ["Yes", "yes"], + ["No", "no"], + ], + conditionalPositiveValue: "yes", + conditionalNegativeValue: "no", + conditionalPositiveWidget: DropDownFormField( + defaultValue: widget.familyMemberIndividualDataModel! + .studentEducationCategory, + list: [ + 'School', + 'College', + 'Vocational', + ], + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .studentEducationCategory = data; + }, + hint: "Choose education category", + title: "Education", + errorField: "Please choose a category", + ), + conditionalNegativeWidget: Container(), + ), + conditionalPositiveWidget: Column( + children: [ + NestedOptionWidgetFormField( + onSaved: (val) { + widget.familyMemberIndividualDataModel! + .occupationData = val; + }, + nestedOptionData: widget + .familyMemberIndividualDataModel! + .occupationData ?? + [ + new NestedOptionData(subOptionDataMap: { + "Administrative and Commercial Managers": + false, + "Chief Executives, Senior Officials and Legislators": + false, + "Production and Specialized Services Managers": + false, + "Hospitality, Retail and Other Services Managers": + false + }, boxName: 'Managers'), + new NestedOptionData(subOptionDataMap: { + "Science and Engineering Professionals": + false, + "Health Professionals": false, + "Teaching Professionals": false, + "Business and Administration Professionals": + false, + "Information and Communications Technology Professionals": + false, + "Legal, Social and Cultural Professionals": + false + }, boxName: 'Professionals'), + new NestedOptionData( + subOptionDataMap: { + "Science and Engineering Associate Professionals": + false, + "Health Associate Professionals": false, + "Business and Administration Associate Professionals": + false, + "Legal, Social, Cultural and Related Associate Professionals": + false, + "Information and Communications Technicians": + false + }, + boxName: + 'Technicians and Associate Professionals'), + new NestedOptionData(subOptionDataMap: { + "General and Keyboard Clerks": false, + "Customer Services Clerks": false, + "Numerical and Material Recording Clerks": + false, + "Other Clerical Support Workers": false + }, boxName: 'Clerical Support Workers'), + new NestedOptionData(subOptionDataMap: { + "Personal Services Workers": false, + "Sales Workers": false, + "Personal Care Workers": false, + "Protective Services Workers": false + }, boxName: 'Services and Sales Workers'), + new NestedOptionData( + subOptionDataMap: { + "Market-oriented Skilled Agricultural Workers": + false, + "Market-oriented Skilled Forestry, Fishery and Hunting Workers": + false, + "Subsistence Farmers, Fishers, Hunters and Gatherers": + false + }, + boxName: + 'Skilled Agricultural, Forestry and Fishery Workers'), + new NestedOptionData(subOptionDataMap: { + "Building and Related Trades Workers (excluding Electricians)": + false, + "Metal, Machinery and Related Trades Workers": + false, + "Handicraft and Printing Workers": false, + "Electrical and Electronic Trades Workers": + false, + "Food Processing, Woodworking, Garment and Other Craft and Related Trades Workers": + false + }, boxName: 'Craft and Related Trades Workers'), + new NestedOptionData( + subOptionDataMap: { + "Stationary Plant and Machine Operators": + false, + "Assemblers": false, + "Drivers and Mobile Plant Operators": + false + }, + boxName: + 'Plant and Machine Operators and Assemblers'), + new NestedOptionData(subOptionDataMap: { + "Cleaners and Helpers": false, + "Agricultural, Forestry and Fishery Labourers": + false, + "Labourers in Mining, Construction, Manufacturing and Transport": + false, + "Food Preparation Assistants": false, + "Street and Related Sales and Services Workers": + false, + "Refuse Workers and Other Elementary Workers": + false + }, boxName: 'Elementary Occupations'), + new NestedOptionData(subOptionDataMap: { + "Commissioned Armed Forces Officers": false, + "Non-commissioned Armed Forces Officers": + false, + "Armed Forces Occupations, Other Ranks": false + }, boxName: 'Armed Forces Occupations'), + ], + title: 'Occupation', + context: context, + ), + Padding( + padding: EdgeInsets.all(15), + child: StartingEndingTimeWidget( + initialValue: widget + .familyMemberIndividualDataModel! + .workTimings != + null + ? [ + TimeOfDay( + hour: int.parse(widget + .familyMemberIndividualDataModel! + .workTimings![0] + .split(":")[0]), + minute: int.parse(widget + .familyMemberIndividualDataModel! + .workTimings![0] + .split(":")[1] + .replaceAll( + new RegExp(r"\D"), ""))), + TimeOfDay( + hour: int.parse(widget + .familyMemberIndividualDataModel! + .workTimings![1] + .split(":")[0]), + minute: int.parse(widget + .familyMemberIndividualDataModel! + .workTimings![1] + .split(":")[1] + .replaceAll(new RegExp(r"\D"), ""))) + ] + : null, + onSaved: (List? timeList) { + var timeFinalString = [ + "${timeList![0].hour}:${timeList[0].minute} ${timeList[0].period == DayPeriod.am ? "AM" : "PM"}", + "${timeList[1].hour}:${timeList[1].minute} ${timeList[1].period == DayPeriod.am ? "AM" : "PM"}" + ]; + widget.familyMemberIndividualDataModel! + .workTimings = timeFinalString; + }, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 20.0), + child: TextFormField( + initialValue: widget + .familyMemberIndividualDataModel! + .noOfDaysWorking, + keyboardType: TextInputType.number, + autovalidateMode: + AutovalidateMode.onUserInteraction, + style: darkTheme.DarkTheme.textTheme.bodyText2, + decoration: InputDecoration( + label: Text( + "Number of work days", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Please enter number of work days", + + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value == null || value == "") + return "Please enter number of work days"; + else if (int.tryParse(value) == null) { + return "Field can only have numbers"; + } else if (int.parse(value) < 1) { + return "Enter number of work days"; + } else if (int.parse(value) > 31) { + return "Enter a valid number of work days"; + } + }, + onSaved: (val) { + widget.familyMemberIndividualDataModel! + .noOfDaysWorking = val; + }, + ), + ), + IncomeWithTypeTextField( + initialDropdownValue: widget + .familyMemberIndividualDataModel!.incomeType, + initialValue: + widget.familyMemberIndividualDataModel!.income, + onSaved: (income, option) { + widget.familyMemberIndividualDataModel!.income = + income; + widget.familyMemberIndividualDataModel!.incomeType = + option; + }, + text: 'Income', + hintText: 'Enter income', + listOfOptions: ["Day", "Week", "Month"], + ), + ], + ), + options: [ + ["Yes", "yes"], + ["No", "no"], + ], + conditionalPositiveValue: "yes", + conditionalNegativeValue: "no", + ) + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 10.0, right: 10.0, bottom: 20.0, top: 20.0), + child: TextFormField( + initialValue: widget + .familyMemberIndividualDataModel?.aadhaarNumber, + keyboardType: TextInputType.number, + style: darkTheme.DarkTheme.textTheme.bodyText2, + decoration: InputDecoration( + label: Text( + "Aadhaar Number", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: "Please enter 12 digit Aadhaar.", + helperText: + "Leave empty if person is not willing to share", + + contentPadding: EdgeInsets.all(7.0), + ), + validator: (value) { + if (value == "" || value == null) + return null; + else if (int.tryParse(value) == null) { + return "Aadhaar number can only have numbers"; + } else if (value.length != 12) { + return "Enter a valid Aadhaar"; + } else + return null; + }, + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .aadhaarNumber = data; + }, + autovalidateMode: AutovalidateMode.onUserInteraction, + ), + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 20.0), + child: OptionsWidget( + defaultValue: + widget.familyMemberIndividualDataModel!.pension, + autoValidateMode: AutovalidateMode.onUserInteraction, + options: [ + ["Eligible, not receiving", "eligible"], + ["Eligible, receiving", "eligible_receiving"], + ["Not eligible", "not_eligible"] + ], + title: 'Old age pension', + onSaved: (val) { + widget.familyMemberIndividualDataModel!.pension = val; + }, + ), + ), + OptionsWidget( + defaultValue: widget + .familyMemberIndividualDataModel!.businessStatus, + autoValidateMode: AutovalidateMode.onUserInteraction, + options: [ + ["Yes", "yes"], + ["No", "no"], + ], + title: 'Doing/Did business', + onSaved: (val) { + widget.familyMemberIndividualDataModel!.businessStatus = + val; + }, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 20.0), + child: OptionsWidget( + defaultValue: widget + .familyMemberIndividualDataModel!.maritalStatus, + autoValidateMode: AutovalidateMode.onUserInteraction, + options: [ + ["Married", "married"], + ["Unmarried", "unmarried"], + ], + title: 'Marital Status', + onSaved: (val) { + widget.familyMemberIndividualDataModel! + .maritalStatus = val; + }, + ), + ), + ]), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Padding( + padding: + EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0), + child: TagTextWidget( + autoValidateMode: AutovalidateMode.onUserInteraction, + label: "Special Skills", + hint: "Enter skills here", + initialValue: + widget.familyMemberIndividualDataModel!.specialSkills, + onSaved: (data) { + widget.familyMemberIndividualDataModel!.specialSkills = + data; + }, + validator: (value) {}, + ), + ), + CheckBoxAddExtraAlertDialog( + title: 'Frequent ailments', + hint: 'Please choose the applicable', + dataMap: widget.familyMemberIndividualDataModel! + .frequentAilments ?? + frequentAilments, + singleOption: false, + context: context, + onSaved: (map) { + widget.familyMemberIndividualDataModel!.frequentAilments = + map; + }, + validator: (val) {}, + errorField: "Please choose ailments / None", + autoValidateMode: AutovalidateMode.onUserInteraction, + ), + SizedBox( + height: 20, + ), + CheckBoxAddExtraAlertDialog( + title: 'Communicable diseases', + hint: 'Please choose the applicable', + dataMap: widget.familyMemberIndividualDataModel! + .communicableDiseases ?? + communicableDiseases, + singleOption: false, + context: context, + onSaved: (map) { + widget.familyMemberIndividualDataModel! + .communicableDiseases = map; + }, + validator: (val) {}, + errorField: "Please choose diseases / None", + autoValidateMode: AutovalidateMode.onUserInteraction, + ), + SizedBox( + height: 20, + ), + CheckBoxAddExtraAlertDialog( + title: 'Non Communicable diseases', + hint: 'Please choose the applicable', + dataMap: widget.familyMemberIndividualDataModel! + .nonCommunicableDiseases ?? + nonCommunicableDiseases, + singleOption: false, + context: context, + onSaved: (map) { + widget.familyMemberIndividualDataModel! + .nonCommunicableDiseases = map; + }, + validator: (val) {}, + errorField: "Please choose diseases / None", + autoValidateMode: AutovalidateMode.onUserInteraction, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 20.0), + child: OptionsWidget( + defaultValue: + widget.familyMemberIndividualDataModel!.surgeries, + options: [ + ["Yes", "yes"], + ["No", "no"], + ], + onSaved: (data) { + widget.familyMemberIndividualDataModel!.surgeries = + data; + }, + title: 'Any Surgeries?', + ), + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + OptionsWidget( + defaultValue: widget.familyMemberIndividualDataModel! + .anganwadiServicesAware, + options: [ + ["Yes", "yes"], + ["No", "no"], + ], + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .anganwadiServicesAware = data; + }, + title: 'Aware about Anganwadi services?', + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 10.0, vertical: 20.0), + child: ConditionalRenderWidget( + title: 'Using any Anganwadi services?', + defaultValue: widget.familyMemberIndividualDataModel! + .anganwadiServicesUsing, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.familyMemberIndividualDataModel! + .anganwadiServicesUsing = val; + }, + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: TagTextWidget( + autoValidateMode: + AutovalidateMode.onUserInteraction, + label: "Anganwadi services utilised", + hint: "Enter services here", + initialValue: widget + .familyMemberIndividualDataModel! + .anganwadiServicesUsedList, + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .anganwadiServicesUsedList = data; + }, + validator: (value) { + if (value == null || value.isEmpty) { + return "Enter a value / NA"; + } else + return null; + }), + ), + conditionalNegativeWidget: Container(), + ), + ), + Padding( + padding: const EdgeInsets.all(10), + child: OptionsWidget( + defaultValue: widget + .familyMemberIndividualDataModel!.PHCServicesUsed, + options: [ + ["Yes", "yes"], + ["No", "no"], + ], + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .PHCServicesUsed = data; + }, + title: 'Using any PHC services?', + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 20.0), + child: ConditionalRenderWidget( + title: 'Do you visit a private hospital?', + defaultValue: widget.familyMemberIndividualDataModel! + .privateClinicServicesUsed, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.familyMemberIndividualDataModel! + .privateClinicServicesUsed = val; }, - child: Text('Submit')) + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: CheckBoxAddExtraAlertDialog( + title: 'Reasons for using a private clinic', + hint: 'Please choose a reason', + dataMap: widget.familyMemberIndividualDataModel! + .privateServiceReason ?? + privateClinicReasons, + singleOption: false, + context: context, + onSaved: (map) { + widget.familyMemberIndividualDataModel! + .privateServiceReason = map; + }, + errorField: "Please choose a reason", + autoValidateMode: AutovalidateMode.onUserInteraction, + ), + conditionalNegativeWidget: Container(), + ), + ) ], ), + Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Padding( + padding: const EdgeInsets.all(10), + child: ConditionalRenderWidget( + title: 'Do you use any tobacco based products?', + defaultValue: + widget.familyMemberIndividualDataModel!.useOfTobacco, + options: [ + ["Yes", "yes"], + ["No", "no"] + ], + onSaved: (val) { + widget.familyMemberIndividualDataModel!.useOfTobacco = + val; + }, + conditionalPositiveValue: 'yes', + conditionalNegativeValue: 'no', + conditionalPositiveWidget: CheckBoxAddExtraAlertDialog( + title: 'Tobacco products', + hint: 'Choose applicable products', + dataMap: widget.familyMemberIndividualDataModel! + .tobaccoProducts ?? + tobaccoProducts, + context: context, + errorField: 'Please choose at least one', + onSaved: (map) { + widget.familyMemberIndividualDataModel! + .tobaccoProducts = map; + }, + ), + conditionalNegativeWidget: Container(), + ), + ), + OptionsWidget( + defaultValue: + widget.familyMemberIndividualDataModel!.useOfAlcohol, + options: [ + ['Yes', 'yes'], + ['No', 'no'] + ], + title: "Do you consume alcohol?", + onSaved: (data) { + widget.familyMemberIndividualDataModel!.useOfAlcohol = + data; + }, + ), + OptionsWidget( + defaultValue: widget + .familyMemberIndividualDataModel!.aarogyaSetuInstalled, + options: [ + ['Yes', 'yes'], + ['No', 'no'] + ], + title: "Do you have Aarogya Setu installed?", + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .aarogyaSetuInstalled = data; + }, + ), + OptionsWidget( + defaultValue: widget + .familyMemberIndividualDataModel!.vizhithiruInstalled, + options: [ + ['Yes', 'yes'], + ['No', 'no'] + ], + title: "Do you have the Vizhithiru app installed?", + onSaved: (data) { + widget.familyMemberIndividualDataModel! + .vizhithiruInstalled = data; + }, + ), + ], + ) + ], + _onSubmit, + onChange: (isValid) { + + widget.familyMemberIndividualDataModel?.dataValid = isValid; + }, + submitMessage: "Submit to continue or go back to re-record data", + note: + "The entered fields are automatically saved when changed and doesn't require submit to be clicked to save locally", ), - Datepicker(), - ], + ), ), - )); + ); } } diff --git a/lib/Screens/FamilyMemberEdit.dart b/lib/Screens/FamilyMemberEdit.dart deleted file mode 100644 index a192958..0000000 --- a/lib/Screens/FamilyMemberEdit.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; - -class FamilyMemberEdit extends StatefulWidget { - const FamilyMemberEdit({Key? key}) : super(key: key); - - @override - _FamilyMemberEditState createState() => _FamilyMemberEditState(); -} - -class _FamilyMemberEditState extends State { - @override - Widget build(BuildContext context) { - return Container(); - } -} diff --git a/lib/Screens/Home.dart b/lib/Screens/Home.dart index 52c51b2..a9582f5 100644 --- a/lib/Screens/Home.dart +++ b/lib/Screens/Home.dart @@ -1,9 +1,23 @@ +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; -import 'package:geo_spatial/Screens/IndividualDataCollection.dart'; -import 'package:geo_spatial/Widgets/DataCard.dart'; -import 'package:google_fonts/google_fonts.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:geo_spatial/Screens/DisplayUploadedData.dart'; import 'package:geo_spatial/Screens/Login.dart'; +import 'package:geo_spatial/Utils/CheckNetworkConnectivity.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Screens/CommunityDataCollection.dart'; +import 'package:geo_spatial/Screens/FamilyHomeScreen.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Widgets/DataCard.dart'; +import 'package:geo_spatial/Widgets/NavigationDrawer.dart'; +import 'package:geo_spatial/main.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:http/http.dart' as http; +import 'DisplayUploadedFamilyData.dart'; +import 'SavedData.dart'; class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); @@ -12,72 +26,144 @@ class Home extends StatefulWidget { _HomeWidgetState createState() => _HomeWidgetState(); } -final storage = FlutterSecureStorage(); - class _HomeWidgetState extends State { - String userName = ''; + final NetworkConnectivity _connectivity = NetworkConnectivity.instance; + + @override + void initState() { + super.initState(); + _connectivity.initialise(); + _connectivity.myStream.listen((source) async { + if (source == ConnectivityResult.none) { + showToast( + "Offline mode, data cannot be uploaded until device is connected to the internet"); + } else { + String jwt = await jwtToken; + print(jwt); + var res = await http + .get(Uri.http(NETWORK_ADDRESS, '/api/validateToken'), headers: { + "Content-Type": "application/json", + 'user-auth-token': jwt + }).timeout(Duration(seconds: 30)); + print(res.statusCode); + if (res.statusCode == 401) { + await storage.delete(key: JWT_STORAGE_KEY); + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (context) => Login()), + (Route route) => false); + showToast("Invalid token or token not found, logging out"); + } + } + }); + } @override Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color(0xffEAE7FA), - appBar: AppBar( - elevation: 0, - title: Text( - 'Hello, ' + userName + '!', - style: GoogleFonts.montserrat(fontSize: 20, color: Colors.black), + return WillPopScope( + onWillPop: () async { + final result = await showDialog( + context: context, + builder: (_) => AlertDialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20))), + backgroundColor: colors.darkScaffoldColor, + title: Text( + "Are you sure you want to quit?", + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor, fontSize: 15), + ), + actions: [ + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: colors.darkAccentColor, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.all(Radius.circular(20)))), + onPressed: () { + SystemChannels.platform + .invokeMethod('SystemNavigator.pop'); + }, + child: Text( + 'Yes', + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + )), + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text( + 'No', + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + )) + ], + )); + return result; + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + drawer: NavigationDrawer(), + backgroundColor: colors.darkScaffoldColor, + appBar: AppBar( + iconTheme: IconThemeData(color: colors.darkAccentColor), + elevation: 40, + title: FutureBuilder( + future: getUserID, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Text( + 'Hello, ' + snapshot.requireData + '!', + style: GoogleFonts.montserrat( + fontSize: 18, color: colors.darkPrimaryTextColor), + ); + } else { + return Text( + 'Geo Spatial Api!', + style: GoogleFonts.montserrat( + fontSize: 18, color: colors.darkPrimaryTextColor), + ); + } + }, ), backgroundColor: Colors.transparent, - actions: [ - IconButton( - splashRadius: 20, - icon: Icon( - Icons.person, - color: Colors.black, - ), - onPressed: () async { - await storage.delete(key: 'jwt'); - Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute(builder: (context) => Login()), - (Route route) => false); - }, - ) - ], - leading: IconButton( - splashRadius: 20, - icon: Icon( - Icons.settings, - color: Colors.black, - ), - onPressed: () {}, - )), - body: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - DataCard( - 'Individual data', - 'Individual data entry for everyone in home', - 'assets/svg/female.svg', - IndividualDataCollection(), - Color(0xFFF700FF), - Color(0xff3D2C8D)), - DataCard( - 'Community Details', - 'Data entry for communities', - 'assets/svg/house.svg', - IndividualDataCollection(), - Color(0xFF2E2FFF), - Color(0xFF4FD586)), - DataCard( - 'View saved data', - 'View all data saved in local storage', - 'assets/svg/storage_image.svg', - IndividualDataCollection(), - Color(0xFFFFA200), - Color(0xFFBA0000)), - ], + ), + body: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + DataCard( + 'Individual data', + 'Individual data entry for everyone in home', + 'assets/svg/female.svg', + //FamilyHomeScreen(), + FamilyHomeScreen(), + Color(0xfff54b64), + Color(0xfff78361)), + DataCard( + 'Community Details', + 'Data entry for communities', + 'assets/svg/house.svg', + CommunityDataCollection(), + Color(0xfff54b64), + Color(0xfff78361)), + DataCard( + 'View Uploaded Records', + 'View all records uploaded by you', + 'assets/svg/male.svg', + DisplayUploadedData(), + Color(0xfff54b64), + Color(0xfff78361)), + DataCard( + 'View saved data', + 'View all data saved in local storage', + 'assets/svg/storage_image.svg', + SavedDataPage(), + Color(0xfff54b64), + Color(0xfff78361)), + ], + ), ), ), ); diff --git a/lib/Screens/IndividualDataCollection.dart b/lib/Screens/IndividualDataCollection.dart deleted file mode 100644 index 647e73f..0000000 --- a/lib/Screens/IndividualDataCollection.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:geo_spatial/Screens/FamilyMemberAdd.dart'; -import 'package:geo_spatial/Screens/FamilyMemberEdit.dart'; -import 'package:geo_spatial/Widgets/DataCard.dart'; - -class IndividualDataCollection extends StatefulWidget { - const IndividualDataCollection({Key? key}) : super(key: key); - - @override - _IndividualDataCollectionState createState() => - _IndividualDataCollectionState(); -} - -class _IndividualDataCollectionState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.white, - elevation: 0, - centerTitle: true, - title: Text( - 'Personal Data', - style: TextStyle(color: Colors.black), - ), - actions: [ - Icon( - Icons.arrow_back_ios_sharp, - ) - ], - ), - body: Stack(fit: StackFit.expand, children: [ - Column( - children: [ - Padding( - padding: EdgeInsets.only(top: 0.0), - child: Image.asset("assets/image_03.png"), - ), - Expanded( - child: Container(), - ), - Expanded( - child: Image.asset("assets/image_02.png"), - ), - ], - ), - SingleChildScrollView( - child: Padding( - padding: EdgeInsets.only(left: 28.0, right: 28.0), - child: Column( - children: [ - DataCard( - 'Add new person', - 'Enter details of a new family member', - 'assets/svg/female.svg', - FamilyMemberAdd(), - Color(0xFFF700FF), - Color(0xff3D2C8D)), - DataCard( - 'Edit existing person', - 'Edit details of an existing family member', - 'assets/svg/female.svg', - FamilyMemberEdit(), - Color(0xFF2E2FFF), - Color(0xFF4FD586)), - ], - ), - ), - ) - ])); - } -} diff --git a/lib/Screens/Login.dart b/lib/Screens/Login.dart index 1e4e9de..ec1fe7c 100644 --- a/lib/Screens/Login.dart +++ b/lib/Screens/Login.dart @@ -1,12 +1,16 @@ import 'dart:convert'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; -import 'package:geo_spatial/Constants/NetworkConfig.dart'; -import 'package:geo_spatial/Widgets/FormCard.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; import 'package:geo_spatial/Screens/Home.dart'; +import 'package:geo_spatial/Utils/colors.dart' as colors; +import 'package:geo_spatial/Widgets/LoginFormCard.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; +import 'package:oktoast/oktoast.dart'; -final storage = FlutterSecureStorage(); +import '../main.dart'; class Login extends StatefulWidget { @override @@ -19,19 +23,33 @@ class _MyAppState extends State { var _nameError = null; var _passwordError = null; - bool _isSelected = false; + bool _isSelected = true; + bool _isLoading = false; + + @override + void initState() { + super.initState(); + data() async { + var data = await storage.read(key: REMEMBER_ME_KEY); + if (data != null) { + _isSelected = data == "true"; + } + setState(() {}); + } + + data(); + } void _radio() { setState(() { _isSelected = !_isSelected; }); + storage.write(key: REMEMBER_ME_KEY, value: _isSelected.toString()); } String _validateUserName(String username) { if (username.isEmpty) return 'Please enter username'; - else if (username.length != 16) - return 'Username has to be 16 characters long'; else return ''; } @@ -48,8 +66,37 @@ class _MyAppState extends State { String url = NETWORK_ADDRESS; var body = json.encode({"username": username, "password": password}); - var res = await http.post(Uri.http(url, '/api/login'), - headers: {"Content-Type": "application/json"}, body: body); + var res = await http + .post(Uri.http(url, '/api/login'), + headers: {"Content-Type": "application/json"}, body: body) + .timeout( + const Duration(seconds: 30), + onTimeout: () { + // Time has run out, do what you wanted to do. + return http.Response( + 'Server Timed out!', 408); // Request Timeout response status code + }, + ); + + return res; + } + + Future _getUserDetails(String JWT) async { + String url = NETWORK_ADDRESS; + + var res = await http.get(Uri.http(url, '/api/getUserData'), headers: { + "Content-Type": "application/json", + 'user-auth-token': JWT + }).timeout( + const Duration(seconds: 30), + onTimeout: () { + showToast("Server Timed out!"); + // Time has run out, do what you wanted to do. + return http.Response( + 'Error', 408); // Request Timeout response status code + }, + ); + return res; } @@ -76,19 +123,47 @@ class _MyAppState extends State { }); if (_nameError == null && _passwordError == null) { - http.Response loginResponse = await _makeLoginRequest(username, password); - if (loginResponse.statusCode != 200) { - setState(() { - _nameError = loginResponse.body; - _passwordError = loginResponse.body; - }); - } else { - storage.write(key: "jwt", value: loginResponse.body); - Navigator.of(context).pushAndRemoveUntil( - MaterialPageRoute(builder: (context) => Home()), - (Route route) => false); + try { + http.Response loginResponse = + await _makeLoginRequest(username, password); + if (loginResponse.statusCode != 200) { + setState(() { + _nameError = loginResponse.body; + _passwordError = loginResponse.body; + }); + } else { + try { + http.Response userData = await _getUserDetails(loginResponse.body); + if (userData.statusCode != 200) { + showToast( + "Something went wrong, please check your network connection or try again later", + position: ToastPosition.center, + backgroundColor: colors.darkAccentColor); + } else { + storage.write(key: USER_DATA_KEY, value: userData.body); + storage.write(key: JWT_STORAGE_KEY, value: loginResponse.body); + storage.write(key: USER_ID_KEY, value: username); + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (context) => Home()), + (Route route) => false); + } + } catch (e) { + debugPrint(e.toString()); + showToast( + "Something went wrong, please check your network connection or try again later", + position: ToastPosition.center, + backgroundColor: colors.darkAccentColor); + } + } + } catch (e) { + debugPrint(e.toString()); + showToast( + "Something went wrong, please check your network connection or try again later"); } } + setState(() { + _isLoading = false; + }); } Widget radioButton(bool isSelected) => Container( @@ -97,57 +172,42 @@ class _MyAppState extends State { padding: EdgeInsets.all(2.0), decoration: BoxDecoration( shape: BoxShape.circle, - border: Border.all(width: 2.0, color: Colors.black)), + border: Border.all(width: 2.0, color: colors.darkAccentColor)), child: isSelected ? Container( width: double.infinity, height: double.infinity, - decoration: - BoxDecoration(shape: BoxShape.circle, color: Colors.black), + decoration: BoxDecoration( + shape: BoxShape.circle, color: colors.darkAccentColor), ) : Container(), ); - Widget horizontalLine() => Padding( - padding: EdgeInsets.symmetric(horizontal: 16.0), - child: Container( - width: 120, - height: 1.0, - color: Colors.black26.withOpacity(.2), - ), - ); - @override Widget build(BuildContext context) { - return new Scaffold( - backgroundColor: Color(0xffEAE7FA), + return Scaffold( + resizeToAvoidBottomInset: true, + backgroundColor: colors.darkScaffoldColor, body: Stack( fit: StackFit.expand, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Padding( - padding: EdgeInsets.only(top: 0.0), - child: Image.asset("assets/image_01.png"), - ), - Expanded( - child: Container(), - ), - Expanded(child: Image.asset("assets/image_02.png")) - ], + SvgPicture.asset( + "assets/svg/background.svg", + fit: BoxFit.cover, ), SingleChildScrollView( child: Padding( - padding: EdgeInsets.only(left: 28.0, right: 28.0, top: 60.0), + padding: EdgeInsets.only(left: 20.0, right: 20.0), child: Column( children: [ SizedBox( - height: 230, + height: MediaQuery.of(context).size.height * 0.48, ), FormCard(_usernameController, _passwordController, _nameError, _passwordError), - SizedBox(height: 25), + SizedBox( + height: 10, + ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -164,42 +224,46 @@ class _MyAppState extends State { width: 8.0, ), Text("Remember me", - style: TextStyle( - fontSize: 15, - )) + style: GoogleFonts.poppins( + color: colors.darkAccentColor, + fontSize: 14.0)) ], ), - InkWell( - child: Container( - width: 100, - height: 50, - decoration: BoxDecoration( - gradient: LinearGradient(colors: [ - Color.fromARGB(500, 59, 5, 120), - Color.fromARGB(250, 157, 133, 244), - ]), - borderRadius: BorderRadius.circular(6.0), - boxShadow: [ - BoxShadow( - color: Color(0xFF6078ea).withOpacity(.3), - offset: Offset(0.0, 8.0), - blurRadius: 8.0) - ]), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: _login, - child: Center( - child: Text("SIGN IN", - style: TextStyle( - color: Colors.white, - fontSize: 18, - letterSpacing: 1.0)), + _isLoading + ? Padding( + padding: EdgeInsets.only(right: 10), + child: CircularProgressIndicator()) + : InkWell( + child: Container( + width: 100, + height: 45, + decoration: BoxDecoration( + gradient: LinearGradient(colors: [ + Color(0xfff54b64), + Color(0xfff78361), + ]), + borderRadius: BorderRadius.circular(30.0), + ), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () { + setState(() { + _isLoading = true; + }); + _login(); + }, + child: Center( + child: Text("SIGN IN", + style: GoogleFonts.poppins( + color: Colors.white, + fontSize: 18, + letterSpacing: 1.0)), + ), + ), + ), ), ), - ), - ), - ) ], ), ], diff --git a/lib/Screens/ProfilePage.dart b/lib/Screens/ProfilePage.dart new file mode 100644 index 0000000..eb04f2e --- /dev/null +++ b/lib/Screens/ProfilePage.dart @@ -0,0 +1,198 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Screens/ChangePassword.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:http/http.dart' as http; +import 'package:oktoast/oktoast.dart'; + +import '../main.dart'; + +class ProfilePage extends StatefulWidget { + @override + State createState() => _ProfilePageState(); +} + +Future _getUserDetails() async { + var jwt = await jwtToken; + String url = NETWORK_ADDRESS; + + var res = await http.get(Uri.http(url, '/api/getUserData'), headers: { + "Content-Type": "application/json", + 'user-auth-token': jwt + }).timeout( + const Duration(seconds: 30), + onTimeout: () { + showToast("Server Timed out! Showing last updated data"); + // Time has run out, do what you wanted to do. + return http.Response( + 'Error', 408); // Request Timeout response status code + }, + ); + + return res; +} + +Future get _getUserData async { + var userData = await storage.read(key: USER_DATA_KEY); + try { + var res = await _getUserDetails(); + if (res.statusCode == 200) { + userData = res.body; + await storage.write(key: USER_DATA_KEY, value: userData); + } + } catch (e) {} + + if (userData == null) return ""; + return userData; +} + +class _ProfilePageState extends State { + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _getUserData, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + var dataJson = json.decode(snapshot.requireData); + var gender = dataJson[0]["gender"]; + return Scaffold( + backgroundColor: Color.fromRGBO(36, 37, 56, 1), + appBar: AppBarBackButton( + 'Profile', + actions: [ + IconButton( + splashRadius: 20, + onPressed: () async { + logoutDialog(context); + }, + icon: Icon( + Icons.login_outlined, + color: colors.darkAccentColor, + )) + ], + ), + resizeToAvoidBottomInset: false, + body: Stack(children: [ + SvgPicture.asset('assets/svg/profile_bg.svg', + alignment: Alignment.center, fit: BoxFit.fill), + CustomScrollView( + slivers: [ + SliverFillRemaining( + hasScrollBody: false, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Center( + child: Column( + children: [ + Image( + image: gender == "Male" + ? AssetImage("assets/avatar_man.png") + : AssetImage("assets/avatar_woman.png"), + ), + Padding( + padding: const EdgeInsets.only(top: 15.0), + child: Text( + dataJson[0]["Name"], + style: GoogleFonts.poppins(fontSize: 20), + ), + ), + Text( + '@' + dataJson[0]["username"], + style: GoogleFonts.poppins( + fontSize: 15, + color: colors.darkSecondaryTextColor), + textAlign: TextAlign.start, + ), + ], + ), + ), + Padding( + padding: EdgeInsets.symmetric(horizontal: 40), + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 20, top: 50), + child: Container( + padding: + EdgeInsets.only(top: 15, left: 20.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.all( + Radius.circular(20)), + color: Color(0xff34344B)), + height: 50, + width: double.infinity, + child: Text( + 'Joined on: ${dataJson[0]["DateJoined"]}'), + ), + ), + Container( + padding: EdgeInsets.only(top: 15, left: 20.0), + width: double.infinity, + decoration: BoxDecoration( + borderRadius: + BorderRadius.all(Radius.circular(20)), + color: Color(0xff34344B)), + height: 50, + child: Text( + 'Records collected: ${dataJson[0]["NumberOfRecordsCollected"]}'), + ) + ], + ), + ), + Center( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 40.0, vertical: 20.0), + child: SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + style: ElevatedButton.styleFrom( + primary: colors.darkSecondaryTextColor + .withOpacity(0.2), + ), + onPressed: () { + Route route = MaterialPageRoute( + builder: (context) => ChangePassword( + userName: dataJson[0]["username"])); + Navigator.push(context, route); + }, + icon: Icon( + Icons.lock, + color: colors.darkAccentColor, + ), + label: Text( + 'Change Password', + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + textAlign: TextAlign.center, + ), + ), + ), + ), + ), + ], + ), + ) + ], + ), + ]), + ); + } else { + return Scaffold( + body: Center( + child: CircularProgressIndicator(), + )); + } + }); + } +} diff --git a/lib/Screens/RenderJSONData.dart b/lib/Screens/RenderJSONData.dart new file mode 100644 index 0000000..7755247 --- /dev/null +++ b/lib/Screens/RenderJSONData.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class RenderJSONData extends StatefulWidget { + const RenderJSONData({Key? key, required this.data}) : super(key: key); + final Map data; + + @override + State createState() => _RenderJSONDataState(); +} + +class _RenderJSONDataState extends State { + List listData = []; + + buildWidgetList(List jsonData) { + List listData = []; + int mapCount = 0; + jsonData.forEach((element) { + print(element.runtimeType); + if (element.runtimeType == String || + element.runtimeType == double || + element.runtimeType == int) { + listData.add(new Card( + color: colors.darkSecondBackgroundColor, + child: ListTile( + title: Text( + element.toString(), + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 15), + ), + ), + elevation: 3, + )); + setState(() {}); + } else if (element.runtimeType == List) { + listData.add(buildWidgetList(element)); + } else { + listData.add(Card( + color: colors.darkSecondBackgroundColor, + child: ListTile( + title: Text( + "Data entry ${mapCount + 1}", + style: GoogleFonts.poppins( + color: Colors.white, fontWeight: FontWeight.w400, fontSize: 15), + ), + subtitle: buildWidgetMap(element), + ), + )); + } + mapCount++; + }); + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: listData, + ), + ); + } + + buildWidgetMap(data) { + List mapListData = []; + data.forEach((key, value) { + print(value.runtimeType); + if (value.runtimeType == String) { + mapListData.add(new Card( + color: colors.darkScaffoldColor, + child: ListTile( + title: Text( + key.toString(), + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 15), + ), + subtitle: Text(value.toString(), style: GoogleFonts.poppins( + color: colors + .darkSecondaryTextColor)), + ), + )); + setState(() {}); + } else if (value.runtimeType == List) { + mapListData.add(Card( + color: colors.darkScaffoldColor, + child: ListTile( + title: Padding( + padding: const EdgeInsets.only(top: 20), + child: Text( + key.toString().toUpperCase(), + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 15), + ), + ), + subtitle: buildWidgetList(value), + ), + )); + setState(() {}); + } else if (value.runtimeType == Map) { + mapListData.add(new Card( + color: colors.darkSecondBackgroundColor, + child: ListTile( + title: Text( + key.toString().toUpperCase(), + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w200, + fontSize: 15), + ), + subtitle: buildWidgetMap(value), + ), + )); + } + }); + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + children: mapListData, + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: colors.darkScaffoldColor, + appBar: AppBarBackButton("Family Data"), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: Container( + decoration: BoxDecoration( + color: colors.darkSecondBackgroundColor, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Color(0xBC252426), + blurRadius: 8.0, + ), + ], + ), + child: SingleChildScrollView( + child: buildWidgetMap(widget.data), + ), + ), + ), + ); + } +} diff --git a/lib/Screens/SavedData.dart b/lib/Screens/SavedData.dart new file mode 100644 index 0000000..bd8c6fa --- /dev/null +++ b/lib/Screens/SavedData.dart @@ -0,0 +1,246 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Model/CommunityDataModel.dart'; +import 'package:geo_spatial/Model/FamilyDataModels.dart'; +import 'package:geo_spatial/Screens/CommunityDataCollection.dart'; +import 'package:geo_spatial/Screens/FamilyHomeScreen.dart'; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:geo_spatial/Utils/StoreInstance.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/objectbox.g.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class SavedDataPage extends StatelessWidget { + const SavedDataPage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 2, + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: AppBar( + bottom: TabBar( + tabs: [ + Tab( + icon: Icon( + Icons.apartment, + color: colors.darkPrimaryTextColor, + )), + Tab( + icon: Icon( + Icons.people, + color: colors.darkPrimaryTextColor, + )), + ], + ), + backgroundColor: Colors.transparent, + leading: IconButton( + splashRadius: 20, + icon: Icon( + Icons.arrow_back, + color: colors.darkAccentColor, + ), + onPressed: () { + Navigator.pop(context); + }), + elevation: 0, + centerTitle: true, + title: Text( + "Saved Data", + style: GoogleFonts.montserrat( + fontSize: 20, color: colors.darkPrimaryTextColor), + ), + ), + backgroundColor: colors.darkScaffoldColor, + body: SafeArea( + child: TabBarView( + children: [CommunitySavedListWidget(), FamilySavedListWidget()], + ), + ), + ), + ); + } +} + +class CommunitySavedListWidget extends StatefulWidget { + const CommunitySavedListWidget({Key? key}) : super(key: key); + + @override + State createState() => + _CommunitySavedListWidgetState(); +} + +class _CommunitySavedListWidgetState extends State { + Future getList() async { + String userId = await getUserID; + var store = await StoreInstance.getInstance(); + final box = store.box(); + List? list = box + .query(CommunityDataModel_.recordCollectingUserId.equals(userId)) + .build() + .find(); + return await list; + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: getList(), + builder: (context, AsyncSnapshot data) { + if (data.data != null) { + List? list = data.data; + if (list != null) { + if (list.isEmpty) { + return Center(child: Text('No Saved Items')); + } else { + list = list.reversed.toList(); + return ListView.builder( + itemCount: list.length, + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.all(3), + child: Card( + color: colors.darkSecondBackgroundColor, + child: ListTile( + title: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "ID: ${list![index].id}, Resource: ${list[index].resourceType ?? "Not Specified"}", + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 18), + ), + Text( + list[index].savedTime ?? "", + style: GoogleFonts.poppins( + color: Colors.white38, + fontWeight: FontWeight.w400, + fontSize: 12), + ) + ], + ), + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => CommunityDataCollection( + modelData: list![index], + ))); + }, + trailing: IconButton( + color: colors.darkSecondAccentColor, + icon: Icon(Icons.close), + onPressed: () async { + var store = await StoreInstance.getInstance(); + final box = store.box(); + await box.remove(list![index].id); + setState(() {}); + }, + ), + ), + ), + ); + }, + ); + } + } else { + return Center(child: Text('No Saved Items')); + } + } else + return Center(child: Text('No Saved Items')); + }); + } +} + +class FamilySavedListWidget extends StatefulWidget { + const FamilySavedListWidget({Key? key}) : super(key: key); + + @override + State createState() => _FamilySavedListWidgetState(); +} + +class _FamilySavedListWidgetState extends State { + Future getList() async { + String userId = await getUserID; + var store = await StoreInstance.getInstance(); + final box = store.box(); + List? list = box + .query( + FamilyMembersCommonDataModel_.recordCollectingUserId.equals(userId)) + .build() + .find(); + return await list; + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: getList(), + builder: (context, AsyncSnapshot data) { + if (data.data != null) { + List? list = data.data; + if (list != null) { + if (list.isEmpty) { + return Center(child: Text('No Saved Items')); + } else { + list = list.reversed.toList(); + return ListView.builder( + itemCount: list.length, + itemBuilder: (context, index) { + return Padding( + padding: EdgeInsets.all(3), + child: Card( + color: colors.darkSecondBackgroundColor, + child: ListTile( + title: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "ID: ${list![index].id}, Individual Data", + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 18), + ), + Text( + list[index].savedTime ?? "", + style: GoogleFonts.poppins( + color: Colors.white38, + fontWeight: FontWeight.w400, + fontSize: 12), + ) + ], + ), + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => FamilyHomeScreen( + modelData: list![index], + ))); + }, + trailing: IconButton( + color: colors.darkSecondAccentColor, + icon: Icon(Icons.close), + onPressed: () async { + var store = await StoreInstance.getInstance(); + final box = + store.box(); + await box.remove(list![index].id); + setState(() {}); + }, + ), + ), + ), + ); + }, + ); + } + } else { + return Center(child: Text('No Saved Items')); + } + } else + return Center(child: Text('No Saved Items')); + }); + } +} diff --git a/lib/Utils/CheckNetworkConnectivity.dart b/lib/Utils/CheckNetworkConnectivity.dart new file mode 100644 index 0000000..a83bada --- /dev/null +++ b/lib/Utils/CheckNetworkConnectivity.dart @@ -0,0 +1,23 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; + +class NetworkConnectivity { + NetworkConnectivity._(); + + static final _instance = NetworkConnectivity._(); + + static NetworkConnectivity get instance => _instance; + final _connectivity = Connectivity(); + final _controller = StreamController.broadcast(); + + Stream get myStream => _controller.stream; + + void initialise() async { + _connectivity.onConnectivityChanged.listen((result) { + _controller.sink.add(result); + }); + } + + void disposeStream() => _controller.close(); +} diff --git a/lib/Utils/Colors.dart b/lib/Utils/Colors.dart new file mode 100644 index 0000000..bb1ec45 --- /dev/null +++ b/lib/Utils/Colors.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; + +var darkScaffoldColor = Color(0xff202330); +var darkAccentColor = Color(0xffFF7D7E); +var darkPrimaryTextColor = Colors.white; +var darkSecondaryTextColor = Colors.white60; +var darkSecondAccentColor = Color(0xff4E596F); +var lightPrimaryTextColor = Colors.black; +var darkHintColor = Colors.black87; +var darkSecondBackgroundColor = Color(0xff34384c); +var errorColor = Color.fromARGB(255, 255, 167, 167); +var successColor = Color(0xff72de6f);//modify later diff --git a/lib/Utils/Constants.dart b/lib/Utils/Constants.dart new file mode 100644 index 0000000..e189459 --- /dev/null +++ b/lib/Utils/Constants.dart @@ -0,0 +1,15 @@ +//Server ID Address/URL, change here and this constant, avoid hardcoding + +//String NETWORK_ADDRESS = 'geo-spatial-amrita.herokuapp.com'; + +//TESTING SERVER: +// String NETWORK_ADDRESS = 'geo-spatial-avv.herokuapp.com'; +String NETWORK_ADDRESS = '172.17.18.87:2000'; + +String JWT_STORAGE_KEY = 'jwt'; +String USER_ID_KEY = "userId"; +String USER_DATA_KEY = "userData"; +String REMEMBER_ME_KEY = "RememberMe"; +final String MALE = "Male"; +final String FEMALE = "Female"; +final String OTHER = "Other"; diff --git a/lib/Utils/DarkTheme.dart b/lib/Utils/DarkTheme.dart new file mode 100644 index 0000000..c512d12 --- /dev/null +++ b/lib/Utils/DarkTheme.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +class darkTheme { + static ThemeData get DarkTheme { + return ThemeData( + timePickerTheme: TimePickerThemeData( + backgroundColor: colors.darkScaffoldColor, + dialHandColor: colors.darkAccentColor, + dialTextColor: Colors.white, + entryModeIconColor: Colors.white, + hourMinuteTextColor: Colors.white, + dayPeriodTextColor: colors.darkAccentColor), + fontFamily: 'Poppins', + primaryColor: Colors.white, + scaffoldBackgroundColor: colors.darkScaffoldColor, + progressIndicatorTheme: + ProgressIndicatorThemeData(color: colors.darkAccentColor), + textTheme: TextTheme( + headline1: GoogleFonts.poppins( + color: Colors.white, fontSize: 40, fontWeight: FontWeight.w200), + bodyText1: GoogleFonts.poppins( + color: Colors.white, fontSize: 15, fontWeight: FontWeight.w100), + bodyText2: GoogleFonts.poppins( + color: Colors.white, fontSize: 15, fontWeight: FontWeight.w300), + button: GoogleFonts.poppins(color: Color(0xff43282C))), + elevatedButtonTheme: ElevatedButtonThemeData( + style: ElevatedButton.styleFrom( + primary: Color(0xffc1c1c1), + elevation: 10.0, + onPrimary: Color(0xff43282C), + padding: EdgeInsets.all(10), + )), + inputDecorationTheme: InputDecorationTheme( + filled: true, + hintStyle: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + helperStyle: + GoogleFonts.poppins(color: colors.darkSecondaryTextColor), + enabledBorder: OutlineInputBorder( + borderSide: + BorderSide(color: colors.darkScaffoldColor, width: 1.0)), + focusedBorder: OutlineInputBorder( + borderSide: + BorderSide(color: colors.darkPrimaryTextColor, width: 1.0)), + border: OutlineInputBorder( + borderSide: BorderSide(color: colors.darkAccentColor, width: 1.0), + ), + errorBorder: OutlineInputBorder( + borderSide: BorderSide(color: colors.errorColor, width: 1.0)), + contentPadding: EdgeInsets.all(7.0), + fillColor: colors.darkScaffoldColor, + labelStyle: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + floatingLabelStyle: + GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + errorStyle: GoogleFonts.poppins(color: colors.errorColor)), + ); + } +} diff --git a/lib/Utils/StoreInstance.dart b/lib/Utils/StoreInstance.dart new file mode 100644 index 0000000..10cde41 --- /dev/null +++ b/lib/Utils/StoreInstance.dart @@ -0,0 +1,20 @@ +import 'package:geo_spatial/objectbox.g.dart'; + +class StoreInstance { + static var store = null; + static var box = null; + + static Future getInstance() async { + if (store == null) { + try { + store = await openStore(); + } catch (error) { + print(error); + store.close(); + store = await openStore(); + } + } + return store; + } + +} diff --git a/lib/Utils/Utils.dart b/lib/Utils/Utils.dart new file mode 100644 index 0000000..f0a1b05 --- /dev/null +++ b/lib/Utils/Utils.dart @@ -0,0 +1,216 @@ +import 'dart:convert'; +import 'dart:ffi'; +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Screens/Login.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:oktoast/oktoast.dart'; +import '../main.dart'; +import 'Constants.dart'; +import 'package:http/http.dart' as http; + +Future get jwtToken async { + var jwt = await storage.read(key: JWT_STORAGE_KEY); + if (jwt == null) return ""; + return jwt; +} + +Future get getUserData async { + var userData = await storage.read(key: USER_DATA_KEY); + if (userData == null) return ""; + return userData; +} + +Future get getUserID async { + var userData = await getUserData; + var dataJson = json.decode(userData); + return dataJson[0]["username"]; +} + +Future get getUserName async { + var storedUserId = await storage.read(key: USER_ID_KEY); + + if (storedUserId == null) return ""; + return storedUserId; +} + +logout(context) async { + await storage.delete(key: JWT_STORAGE_KEY); + Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (context) => Login()), + (Route route) => false); +} + +logoutDialog(context) { + return showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: colors.darkScaffoldColor, + title: Text( + "Are you sure?", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + content: Text( + "You will be logged out", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + actions: [ + TextButton( + child: Text( + 'No', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: colors.darkAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)))), + child: + Text('Yes', style: TextStyle(color: colors.darkPrimaryTextColor)), + onPressed: () async { + logout(context); + }, + ), + ], + ), + ); +} + +closePage(context) { + return showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: colors.darkScaffoldColor, + title: Text( + "Are you sure?", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + content: Text( + "All unsaved changes will be lost.", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + actions: [ + TextButton( + child: Text( + 'No', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onPressed: () { + Navigator.pop(context, false); + }, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: colors.darkAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)))), + child: Text( + 'Yes', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onPressed: () { + Navigator.pop(context, true); + }, + ), + ], + ), + ); +} + +displayDialog(context, + {required String title, + required String subTitle, + required VoidCallback positiveFunction, + required VoidCallback negativeFunction}) { + return showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: colors.darkScaffoldColor, + title: Text( + title, + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + content: Text( + subTitle, + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + actions: [ + TextButton( + child: Text( + 'No', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onPressed: negativeFunction, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: colors.darkAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)))), + child: + Text('Yes', style: TextStyle(color: colors.darkPrimaryTextColor)), + onPressed: positiveFunction, + ), + ], + ), + ); +} + +Future deleteRecord(var data, String node, context) async { + String url = NETWORK_ADDRESS; + var body = json.encode(data); + + var progressContext; + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + progressContext = context; + return WillPopScope( + child: Dialog( + child: Padding( + padding: EdgeInsets.all(20), + child: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only(right: 20), + child: CircularProgressIndicator(), + ), + new Text( + "Deleting Record", + style: TextStyle(color: Colors.black), + ), + ], + ), + ), + ), + onWillPop: () async => false); + }, + ); + + var jwt = await jwtToken; + + var res = await http + .post(Uri.http(url, node), + headers: {"Content-Type": "application/json", "user-auth-token": jwt}, + body: body) + .timeout( + const Duration(seconds: 30), + onTimeout: () { + // Time has run out, do what you wanted to do. + return http.Response( + 'Server Timed out!', 408); // Request Timeout response status code + }, + ); + Navigator.of(progressContext!, rootNavigator: true).pop(); + if (res.statusCode != 200) { + showToast(res.body); + return false; + } + return true; +} diff --git a/lib/Widgets/AddRemoveBoxWidget.dart b/lib/Widgets/AddRemoveBoxWidget.dart new file mode 100644 index 0000000..9f0bcde --- /dev/null +++ b/lib/Widgets/AddRemoveBoxWidget.dart @@ -0,0 +1,177 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Model/FamilyDataModels.dart'; +import 'package:geo_spatial/Screens/FamilyMemberAdd.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:google_fonts/google_fonts.dart'; +import 'package:visibility_detector/visibility_detector.dart'; + +/** + * Added a dataclass + * To be modified later + * Add required data fields to this class + */ + +class AddRemoveBoxWidget extends StatefulWidget { + const AddRemoveBoxWidget({Key? key, this.modelData}) : super(key: key); + final FamilyMembersCommonDataModel? modelData; + + @override + _AddRemoveBoxWidgetState createState() => _AddRemoveBoxWidgetState(); +} + +class _AddRemoveBoxWidgetState extends State { + @override + Widget build(BuildContext context) { + return Expanded( + flex: 2, + child: Padding( + padding: EdgeInsets.all(5), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextButton( + onPressed: () { + setState(() { + widget.modelData?.individualDataListTransient + .add(FamilyMemberIndividualDataModel()); + }); + }, + child: Text("Add New User Information", + style: GoogleFonts.poppins( + fontSize: 18, color: colors.darkAccentColor)), + ), + IconButton( + splashRadius: 20, + onPressed: () { + setState(() { + widget.modelData?.individualDataListTransient + .add(FamilyMemberIndividualDataModel()); + }); + }, + icon: Icon( + Icons.add, + color: colors.darkAccentColor, + )) + ], + ), + Flexible( + child: Container( + child: widget.modelData!.individualDataListTransient.isEmpty + ? Center(child: Text('No Members Added')) + : ListView.builder( + itemCount: widget + .modelData!.individualDataListTransient.length, + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return Card( + color: colors.darkSecondBackgroundColor, + /** + * Re-renders tiles whenever visibility changed + * i.e, when user comes back from user page, + * page re rendered and user name is reflected + */ + child: VisibilityDetector( + onVisibilityChanged: (VisibilityInfo info) { + try { + setState(() {}); //Re-renders page + } catch (e) {} + }, + key: Key('add-remove-widget-key'), + child: ListTile( + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => FamilyMemberAdd( + dataModel: widget.modelData, + familyMemberIndividualDataModel: + widget.modelData! + .individualDataListTransient + .elementAt(index)))); + }, + leading: Icon(Icons.person), + title: Text( + widget.modelData! + .individualDataListTransient + .elementAt(index) + .userName != + null && + widget.modelData! + .individualDataListTransient + .elementAt(index) + .userName != + '' + ? widget.modelData! + .individualDataListTransient + .elementAt(index) + .userName! + : "User ${index + 1}", + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 20), + ), + trailing: IconButton( + splashRadius: 20, + color: colors.darkSecondAccentColor, + icon: Icon(Icons.close), + onPressed: () async { + Dialog(index); + })), + ), + ); + }), + ), + ), + ], + ), + ), + ); + } + + void Dialog(index) async { + final result = await showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: colors.darkScaffoldColor, + title: Text( + "Are you sure?", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + content: Text( + "All unsaved changes will be lost", + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + actions: [ + TextButton( + child: Text( + 'No', + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onPressed: () { + Navigator.pop(context, false); + }, + ), + ElevatedButton( + style: ElevatedButton.styleFrom( + primary: colors.darkAccentColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)))), + child: Text( + 'Yes', + style: + GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onPressed: () { + setState(() { + widget.modelData!.individualDataListTransient + .removeAt(index); + }); + Navigator.pop(context); + }) + ]), + ); + return result; + } +} diff --git a/lib/Widgets/AppBarBackButtonWidget.dart b/lib/Widgets/AppBarBackButtonWidget.dart new file mode 100644 index 0000000..4880c74 --- /dev/null +++ b/lib/Widgets/AppBarBackButtonWidget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart'as colors; + +class AppBarBackButton extends StatelessWidget implements PreferredSizeWidget { + const AppBarBackButton(this.title, {this.actions}); + + final String title; + final List? actions; + + @override + Size get preferredSize => const Size.fromHeight(kToolbarHeight); + + /** + * Widget for app bars with a back button + * + * @param: + * String title: title to be displayed in app bar + * + * @returns: + * Widget: Returns an AppBar + */ + + @override + Widget build(BuildContext context) { + return AppBar( + backgroundColor: Colors.transparent, + leading: IconButton( + splashRadius: 20, + icon: Icon( + Icons.arrow_back, + color: colors.darkAccentColor, + ), + onPressed: () { + Navigator.pop(context); + }), + elevation: 0, + actions: actions ?? [], + centerTitle: true, + title: Text( + title, + style: GoogleFonts.montserrat(fontSize: 20, color: colors.darkPrimaryTextColor), + ), + ); + } +} diff --git a/lib/Widgets/CheckBoxAddExtraDialog.dart b/lib/Widgets/CheckBoxAddExtraDialog.dart new file mode 100644 index 0000000..a92de00 --- /dev/null +++ b/lib/Widgets/CheckBoxAddExtraDialog.dart @@ -0,0 +1,296 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +/** + * Implementation: + * + * Map values = { + 'yes': false, + 'no': false, + }; + + * CheckBoxAddExtraAlertDialog( + title: 'Choose resource', + hint: 'Choose your resource', + dataMap: values, + singleOption: true, + context: context, + onSaved: (map) { + print(map); + print('called'); + }, + ), + */ + +class CheckBoxAddExtraAlertDialog extends FormField> { + CheckBoxAddExtraAlertDialog( + {FormFieldSetter>? onSaved, + FormFieldValidator>? validator, + autoSave = false, + title, + required hint, + required Map dataMap, + errorField, + singleOption = false, + showAddNewBox = true, + required context, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null || data.isEmpty) + return errorField ?? "Please select a value"; + else { + bool isValid = false; + data.forEach((k, v) => {isValid |= v}); + + if (!isValid) return "Please select a value"; + } + return null; + }, + initialValue: dataMap, + autovalidateMode: autoValidateMode, + builder: (FormFieldState> state) { + getDisplayOptions() { + if (state.hasError) { + return Text( + hint, + style: GoogleFonts.poppins(color: colors.errorColor), + textAlign: TextAlign.end, + ); + } else { + var displayValue = ''; + state.value!.forEach((k, v) { + if (v) displayValue += k + ', '; + }); + + if (displayValue != '') { + if (displayValue.length >= 2) { + displayValue = + displayValue.substring(0, displayValue.length - 2); + } + return Text( + displayValue, + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + textAlign: TextAlign.end, + ); + } else { + return Text( + hint, + style: GoogleFonts.poppins(color: Colors.grey), + textAlign: TextAlign.end, + ); + } + } + } + + return Padding( + padding: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + title != null + ? Padding( + padding: EdgeInsets.only(bottom: 20), + child: Text(title, + style: GoogleFonts.montserrat( + fontSize: 15, + color: colors.darkPrimaryTextColor)), + ) + : Container(), + Card( + color: colors.darkScaffoldColor, + elevation: 5, + margin: EdgeInsets.only(top: 3, bottom: 3), + child: InkWell( + onTap: () { + _showMyDialog(context, title, state, singleOption, + showAddNewBox, autoSave); + }, + child: Padding( + padding: EdgeInsets.only( + left: 20, right: 10, top: 12, bottom: 12), + child: Row( + children: [ + Expanded( + flex: 1, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: getDisplayOptions(), + ), + ), + Padding( + padding: EdgeInsets.only(left: 5), + child: Icon( + Icons.arrow_right, + color: colors.darkSecondaryTextColor, + ), + ) + ], + ), + ), + ), + ), + state.hasError + ? Container( + padding: EdgeInsets.all(10), + child: Text( + state.errorText ?? "error", + style: TextStyle( + color: colors.errorColor, fontSize: 10), + ), + ) + : Container() + ], + ), + ); + }); +} + +Future _showMyDialog( + context, dialogTitle, state, singleOption, showAddNewBox, autoSave) async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialogWidget( + autoSave: autoSave, + dialogTitle: dialogTitle ?? "Choose an option", + state: state, + showAddNew: showAddNewBox, + singleOption: singleOption, + ); + }, + ); +} + +class AlertDialogWidget extends StatefulWidget { + final dialogTitle; + final state; + final singleOption; + final showAddNew; + final bool autoSave; + + const AlertDialogWidget( + {Key? key, + required this.dialogTitle, + required this.state, + required this.singleOption, + this.showAddNew, + required this.autoSave}) + : super(key: key); + + @override + _AlertDialogWidgetState createState() => _AlertDialogWidgetState(); +} + +class _AlertDialogWidgetState extends State { + TextEditingController _controller = TextEditingController(); + + _addNewData(String value) { + Map dataList = widget.state.value; + value = value.trim(); + if (value.isNotEmpty) { + if (!dataList.containsKey(value)) { + dataList[value] = false; + } + widget.state.didChange(dataList); + _controller.clear(); + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + List dialogList = [ + widget.showAddNew + ? TextFormField( + style: TextStyle(color: Colors.white60), + onFieldSubmitted: (submit) { + _addNewData(submit); + }, + controller: _controller, + decoration: InputDecoration( + // fillColor: Colors.blue, + hintText: "Add a new field", + label: Text("Add New Field"), + suffixIcon: Material( + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(4.0), + topRight: Radius.circular(4.0)), + child: IconButton( + splashRadius: 17, + onPressed: () { + var text = _controller.text; + _addNewData(text); + }, + icon: Icon( + Icons.add, + color: colors.darkAccentColor, + )), + )), + ) + : Container() + ]; + var dataList = widget.state.value; + + dataList!.forEach((k, v) => { + dialogList.add(CheckboxListTile( + checkColor: colors.darkPrimaryTextColor, + activeColor: colors.darkAccentColor, + title: Text(k, + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor)), + value: widget.state.value[k], + onChanged: (value) { + Map newPair = widget.state.value; + + if (widget.singleOption) { + widget.state.value!.forEach((k, v) { + newPair.update( + k, + (existingValue) => false, + ifAbsent: () => false, + ); + }); + } + + newPair[k] = value; + setState(() { + dataList = newPair; + }); + widget.state.didChange(newPair); + if (widget.autoSave) { + widget.state.save(); + } + }, + )) + }); + + return AlertDialog( + backgroundColor: colors.darkSecondBackgroundColor, + title: Text( + widget.dialogTitle, + style: GoogleFonts.poppins(color: colors.darkAccentColor), + ), + content: SingleChildScrollView( + child: Column( + children: dialogList, + ), + ), + actions: [ + TextButton( + child: Text( + 'Choose', + style: GoogleFonts.poppins(color: colors.darkAccentColor), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + } +} diff --git a/lib/Widgets/CheckBoxAlertDialog.dart b/lib/Widgets/CheckBoxAlertDialog.dart new file mode 100644 index 0000000..1993bbf --- /dev/null +++ b/lib/Widgets/CheckBoxAlertDialog.dart @@ -0,0 +1,250 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +/** + * Implementation: + * + * Map values = { + 'yes': false, + 'no': false, + }; + + * CheckBoxAlertDialog( + title: 'Choose resource', + hint: 'Choose your resource', + dataMap: values, + singleOption: true, + context: context, + onSaved: (map) { + print(map); + print('called'); + }, + ), + */ + +class CheckBoxAlertDialog extends FormField> { + CheckBoxAlertDialog( + {FormFieldSetter>? onSaved, + FormFieldValidator>? validator, + Key? key, + required title, + required hint, + required Map dataMap, + errorField, + singleOption = false, + autoSave = false, + required context, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + key: key, + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null || data.isEmpty) + return errorField ?? "Please select a value"; + else { + bool isValid = false; + data.forEach((k, v) => {isValid |= v}); + + if (!isValid) return "Please select a value"; + } + return null; + }, + initialValue: dataMap, + autovalidateMode: autoValidateMode, + builder: (FormFieldState> state) { + getDisplayOptions() { + if (state.hasError) { + return Text( + hint, + style: GoogleFonts.poppins(color: colors.errorColor), + textAlign: TextAlign.end, + ); + } else { + var displayValue = ''; + state.value!.forEach((k, v) { + if (v) displayValue += k + ', '; + }); + + if (displayValue != '') { + if (displayValue.length >= 2) { + displayValue = + displayValue.substring(0, displayValue.length - 2); + } + return Text( + displayValue, + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor), + textAlign: TextAlign.end, + ); + } else { + return Text( + hint, + style: GoogleFonts.poppins(color: Colors.grey), + textAlign: TextAlign.end, + ); + } + } + } + + return Padding( + padding: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 20), + child: Text(title, + style: GoogleFonts.montserrat( + fontSize: 15, + color: colors.darkPrimaryTextColor)), + ), + Card( + color: colors.darkScaffoldColor, + elevation: 5, + margin: EdgeInsets.only(top: 3, bottom: 3), + child: InkWell( + onTap: () { + _showMyDialog( + context, title, state, singleOption, autoSave); + }, + child: Padding( + padding: EdgeInsets.only( + left: 20, right: 10, top: 12, bottom: 12), + child: Row( + children: [ + Expanded( + flex: 1, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: getDisplayOptions(), + ), + ), + Padding( + padding: EdgeInsets.only(left: 5), + child: Icon( + Icons.arrow_right, + color: colors.darkSecondaryTextColor, + ), + ) + ], + ), + ), + ), + ), + state.hasError + ? Container( + padding: EdgeInsets.all(10), + child: Text( + state.errorText ?? "error", + style: TextStyle( + color: colors.errorColor, fontSize: 10), + ), + ) + : Container() + ], + ), + ); + }); +} + +Future _showMyDialog( + context, dialogTitle, state, singleOption, autoSave) async { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialogWidget( + autoSave: autoSave, + dialogTitle: dialogTitle, + state: state, + singleOption: singleOption, + ); + }, + ); +} + +class AlertDialogWidget extends StatefulWidget { + final dialogTitle; + final state; + final singleOption; + final autoSave; + + const AlertDialogWidget( + {Key? key, + required this.autoSave, + required this.dialogTitle, + required this.state, + required this.singleOption}) + : super(key: key); + + @override + _AlertDialogWidgetState createState() => _AlertDialogWidgetState(); +} + +class _AlertDialogWidgetState extends State { + @override + Widget build(BuildContext context) { + List dialogList = []; + var dataList = widget.state.value; + + dataList!.forEach((k, v) => { + dialogList.add(CheckboxListTile( + checkColor: colors.darkPrimaryTextColor, + activeColor: colors.darkAccentColor, + title: Text( + k, + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + value: widget.state.value[k], + onChanged: (value) { + Map newPair = widget.state.value; + + if (widget.singleOption) { + widget.state.value!.forEach((k, v) { + newPair.update( + k, + (existingValue) => false, + ifAbsent: () => false, + ); + }); + } + + newPair[k] = value; + setState(() { + dataList = newPair; + }); + widget.state.didChange(newPair); + if (widget.autoSave) { + widget.state.save(); + } + }, + )) + }); + + return AlertDialog( + backgroundColor: colors.darkSecondBackgroundColor, + title: Text( + widget.dialogTitle, + style: GoogleFonts.poppins(color: colors.darkAccentColor), + ), + content: SingleChildScrollView( + child: Column( + children: dialogList, + ), + ), + actions: [ + TextButton( + child: Text( + 'Choose', + style: GoogleFonts.poppins(color: colors.darkAccentColor), + ), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + } +} diff --git a/lib/Widgets/ConditionalRenderWidget.dart b/lib/Widgets/ConditionalRenderWidget.dart new file mode 100644 index 0000000..2c36938 --- /dev/null +++ b/lib/Widgets/ConditionalRenderWidget.dart @@ -0,0 +1,78 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Widgets/OptionsFormWidget.dart'; + +class ConditionalRenderWidget extends StatefulWidget { + const ConditionalRenderWidget( + {Key? key, + this.defaultValue, + this.onSaved, + required this.title, + required this.conditionalPositiveWidget, + required this.options, + required this.conditionalPositiveValue, + required this.conditionalNegativeValue, + required this.conditionalNegativeWidget}) + : super(key: key); + + final defaultValue; + final String conditionalPositiveValue; + final String conditionalNegativeValue; + final String title; + final List options; + final Function(dynamic)? onSaved; + final Widget conditionalPositiveWidget; + final Widget conditionalNegativeWidget; + + @override + _ConditionalRenderWidgetState createState() => + _ConditionalRenderWidgetState(); +} + +class _ConditionalRenderWidgetState extends State { + bool isPositiveVisible = false; + bool isNegativeVisible = false; + + @override + void initState() { + super.initState(); + initData(); + } + + initData() { + if (widget.defaultValue != null) { + isPositiveVisible = + (widget.defaultValue == widget.conditionalPositiveValue); + isNegativeVisible = + (widget.defaultValue == widget.conditionalNegativeValue); + } + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + OptionsWidget( + defaultValue: widget.defaultValue, + autoValidateMode: AutovalidateMode.onUserInteraction, + options: widget.options, + onChanged: (val) { + setState(() { + isPositiveVisible = (val == widget.conditionalPositiveValue); + isNegativeVisible = (val == widget.conditionalNegativeValue); + }); + }, + title: widget.title, + onSaved: widget.onSaved, + ), + Visibility( + child: widget.conditionalPositiveWidget, + visible: isPositiveVisible, + ), + Visibility( + child: widget.conditionalNegativeWidget, + visible: isNegativeVisible, + ) + ], + ); + } +} diff --git a/lib/Widgets/DataCard.dart b/lib/Widgets/DataCard.dart index bc7d6f7..6332700 100644 --- a/lib/Widgets/DataCard.dart +++ b/lib/Widgets/DataCard.dart @@ -1,6 +1,8 @@ +import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; class DataCard extends StatelessWidget { DataCard(this.heading, this.subHeading, this.imageUrl, this.route, @@ -23,8 +25,8 @@ class DataCard extends StatelessWidget { borderRadius: BorderRadius.circular(20), gradient: LinearGradient( colors: [startingColor, endingColor], - begin: Alignment.centerLeft, - end: Alignment.centerRight, + begin: Alignment.bottomLeft, + end: Alignment.topRight, ), boxShadow: [ BoxShadow( @@ -61,12 +63,14 @@ class DataCard extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Text(heading, + AutoSizeText(heading, + maxLines: 3, style: GoogleFonts.montserrat( - fontSize: 25, color: Colors.white)), - Text(subHeading, + fontSize: 25, color: colors.darkPrimaryTextColor)), + AutoSizeText(subHeading, + maxLines: 1, style: GoogleFonts.montserrat( - fontSize: 15, color: Color(0xFFDCDCDC))) + fontSize: 15, color: colors.darkPrimaryTextColor)) ], ), ), @@ -77,7 +81,7 @@ class DataCard extends StatelessWidget { padding: EdgeInsets.only(top: 8.0, bottom: 8.0, right: 8.0), child: SvgPicture.asset('assets/svg/right-icon-arrow.svg', - color: Colors.white), + color: colors.darkPrimaryTextColor), ), flex: 1, ), diff --git a/lib/Widgets/DatePickerWidget.dart b/lib/Widgets/DatePickerWidget.dart new file mode 100644 index 0000000..d155e37 --- /dev/null +++ b/lib/Widgets/DatePickerWidget.dart @@ -0,0 +1,103 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:google_fonts/google_fonts.dart'; + +class DatePickerWidget extends FormField { + DatePickerWidget( + {FormFieldSetter? onSaved, + FormFieldValidator? validator, + DateTime? defaultDate, + required context, + hint = 'Please choose a date', + title, + AutovalidateMode autoValidateMode = AutovalidateMode.disabled}) + : super( + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null) return "Please choose date"; + return null; + }, + initialValue: defaultDate ?? null, + autovalidateMode: autoValidateMode, + builder: (FormFieldState state) { + Future pickDate(BuildContext context) async { + await CupertinoRoundedDatePicker.show(context, + background: colors.darkSecondBackgroundColor, + textColor: colors.darkAccentColor, + initialDate: state.value ?? DateTime.now(), + minimumYear: 1900, + maximumDate: DateTime.now(), + maximumYear: DateTime.now().year, + initialDatePickerMode: CupertinoDatePickerMode.date, + borderRadius: 16, onDateTimeChanged: (date) { + state.didChange(date); + }); + } + + return Padding( + padding: const EdgeInsets.all(10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 8), + child: Text(title ?? 'Choose date', + style: GoogleFonts.montserrat( + fontSize: 15, color: Colors.white)), + ), + Card( + color: colors.darkScaffoldColor, + elevation: 6, + margin: EdgeInsets.only(bottom: 4), + child: InkWell( + onTap: () { + pickDate(context); + }, + child: Padding( + padding: EdgeInsets.only( + left: 8, right: 8, top: 15, bottom: 15), + child: Row( + children: [ + Padding( + padding: EdgeInsets.only(right: 20, left: 10), + child: Icon( + Icons.calendar_today, + color: colors.darkPrimaryTextColor, + ), + ), + Expanded( + flex: 1, + child: Text( + state.value == null + ? hint + : '${state.value!.day} / ${state.value!.month} / ${state.value!.year}', + style: GoogleFonts.montserrat( + fontSize: 15, + color: state.hasError + ? colors.errorColor + : Colors.grey)), + ) + ], + ), + ), + ), + ), + state.hasError + ? Container( + padding: EdgeInsets.all(7), + child: Text( + state.errorText ?? "error", + style: TextStyle( + color: colors.errorColor, fontSize: 10), + ), + ) + : Container() + ], + ), + ); + }); +} diff --git a/lib/Widgets/Datepicker.dart b/lib/Widgets/Datepicker.dart deleted file mode 100644 index a426bcf..0000000 --- a/lib/Widgets/Datepicker.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:table_calendar/table_calendar.dart'; - -class Datepicker extends StatefulWidget { - const Datepicker({Key? key}) : super(key: key); - - @override - _Datepickerstate createState() => _Datepickerstate(); -} - -class _Datepickerstate extends State { - - late DateTime date; - - String getText(){ - - if(date==null){ - return 'Pick date'; - } - - else{ - return '${date.month}/${date.day}/${date.year}'; - } - } - - @override - Widget build(BuildContext context){ - return Container( - child: OutlinedButton( - child: Text(getText()), - onPressed: (){ pickDate(context);}, - ), - ); - } - - Future pickDate(BuildContext context) async { - final initialDate = DateTime.now(); - final newDate = await showDatePicker(context: context, initialDate: initialDate, - firstDate: DateTime(DateTime.now().year-100), - lastDate: DateTime(DateTime.now().year), - ); - - if(newDate == null) return; - - setState(() => date = newDate); - } -} diff --git a/lib/Widgets/DropDownFormField.dart b/lib/Widgets/DropDownFormField.dart new file mode 100644 index 0000000..047f638 --- /dev/null +++ b/lib/Widgets/DropDownFormField.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +class DropDownFormField extends FormField { + DropDownFormField( + {FormFieldSetter? onSaved, + FormFieldValidator? validator, + required list, + required title, + required hint, + String? defaultValue, + errorField, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null) + return errorField ?? "Please select a value"; + return null; + }, + initialValue: defaultValue, + autovalidateMode: autoValidateMode, + builder: (FormFieldState state) { + return Padding( + padding: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 8), + child: Text(title, + style: GoogleFonts.montserrat( + fontSize: 15, + color: colors.darkPrimaryTextColor)), + ), + Card( + color: colors.darkScaffoldColor, + elevation: 10, + margin: EdgeInsets.only(bottom: 4), + child: DropdownButtonHideUnderline( + child: ButtonTheme( + alignedDropdown: true, + child: DropdownButton( + dropdownColor: colors.darkScaffoldColor, + value: state.value, + isExpanded: true, + items: list.map((value) { + return DropdownMenuItem( + value: value, + child: Text( + value, + overflow: TextOverflow.ellipsis, + ), + ); + }).toList(), + onChanged: (newValue) { + state.didChange(newValue); + }, + hint: Container( + color: colors.darkScaffoldColor, + padding: EdgeInsets.all(8), + child: Text( + hint, + overflow: TextOverflow.ellipsis, + style: GoogleFonts.poppins( + color: state.hasError + ? colors.errorColor + : Colors.grey), + textAlign: TextAlign.end, + ), + ), + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor, + decorationColor: colors.errorColor), + ), + ), + ), + ), + state.hasError + ? Container( + padding: EdgeInsets.all(10), + child: Text( + state.errorText ?? "error", + style: GoogleFonts.poppins( + color: colors.errorColor, fontSize: 10), + ), + ) + : Container() + ], + ), + ); + }); +} \ No newline at end of file diff --git a/lib/Widgets/FormCard.dart b/lib/Widgets/FormCard.dart deleted file mode 100644 index ebb812d..0000000 --- a/lib/Widgets/FormCard.dart +++ /dev/null @@ -1,79 +0,0 @@ -import 'package:flutter/material.dart'; - -class FormCard extends StatelessWidget { - FormCard(this._usernameController, this._passwordController, this._nameError, - this._passwordError); - - final TextEditingController _usernameController; - final TextEditingController _passwordController; - final _nameError; - final _passwordError; - - @override - Widget build(BuildContext context) { - return new Container( - width: double.infinity, - padding: EdgeInsets.only(bottom: 1), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(15.0), - boxShadow: [ - BoxShadow( - color: Colors.black12, - offset: Offset(0.0, 15.0), - blurRadius: 15.0), - BoxShadow( - color: Colors.black12, - offset: Offset(0.0, -10.0), - blurRadius: 10.0), - ]), - child: Padding( - padding: EdgeInsets.only(left: 16.0, right: 16.0, top: 20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text("Login", - style: TextStyle( - fontSize: 35, - letterSpacing: 0.8, - color: Colors.deepPurpleAccent)), - SizedBox( - height: 20, - ), - TextField( - controller: _usernameController, - decoration: InputDecoration( - labelText: "Username", - errorText: _nameError, - labelStyle: - TextStyle(color: Colors.deepPurpleAccent, fontSize: 14.0), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0)), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0))), - ), - SizedBox( - height: 20, - ), - TextField( - controller: _passwordController, - obscureText: true, - decoration: InputDecoration( - labelText: "Password", - errorText: _passwordError, - labelStyle: - TextStyle(color: Colors.deepPurpleAccent, fontSize: 14.0), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0)), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(10.0))), - ), - SizedBox( - height: 70, - ), - ], - ), - ), - ); - } -} diff --git a/lib/Widgets/FormPageView.dart b/lib/Widgets/FormPageView.dart new file mode 100644 index 0000000..5d5857c --- /dev/null +++ b/lib/Widgets/FormPageView.dart @@ -0,0 +1,206 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Widgets/StepCounterWidget.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:preload_page_view/preload_page_view.dart'; + +import 'PageViewContentBox.dart'; + +class FormPageView extends StatefulWidget { + const FormPageView(this.pageWidgetList, this.onSubmit, + {Key? key, this.saveData, this.submitMessage, this.note, this.onChange}) + : super(key: key); + + final List pageWidgetList; + final Function(bool) onSubmit; + final Function(bool)? onChange; + final saveData; + final submitMessage; + final note; + + @override + _FormPageViewState createState() => _FormPageViewState(); +} + +class _FormPageViewState extends State { + //Page position + int count = 0; + late int widgetLength; + late final List> formKeyList; + late final List formErrorTile; + final PreloadPageController controller = + PreloadPageController(initialPage: 0); + late final List widgetList; + + @override + void initState() { + super.initState(); + + widgetLength = widget.pageWidgetList.length + 1; + formErrorTile = List.generate(widgetLength - 1, (index) => false); + + formKeyList = List.generate( + widgetLength - 1, (index) => GlobalObjectKey(index)); + widgetList = List.generate( + widgetLength - 1, + (index) => PageViewContentBox(FormKeepAlive( + widget.pageWidgetList[index], + formKeyList[index], + ))); + widgetList.add(PageViewContentBox(Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + widget.submitMessage ?? "", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + color: Colors.white, fontWeight: FontWeight.w400, fontSize: 25), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + child: Text("Submit", style: TextStyle(fontSize: 14)), + style: ButtonStyle( + foregroundColor: + MaterialStateProperty.all(Colors.white), + backgroundColor: MaterialStateProperty.all( + colors.darkScaffoldColor), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + side: BorderSide( + color: colors.darkScaffoldColor)))), + onPressed: () { + bool isValid = true; + for (int i = 0; i < widgetLength - 1; i++) { + var isDataValid = formKeyList[i].currentState!.validate(); + isValid &= isDataValid; + formKeyList[i].currentState!.save(); + if (isDataValid) {} + } + widget.onSubmit(isValid); + }), + ), + ), + widget.saveData != null + ? Padding( + padding: EdgeInsets.only(top: 10), + child: SizedBox( + width: double.infinity, + height: 50, + child: ElevatedButton( + child: Text("Save Data", + style: + TextStyle(fontSize: 14, color: Colors.black)), + style: ButtonStyle( + foregroundColor: + MaterialStateProperty.all(Colors.white), + backgroundColor: + MaterialStateProperty.all(Colors.white), + shape: MaterialStateProperty.all< + RoundedRectangleBorder>( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + side: BorderSide(color: Colors.white)))), + onPressed: () { + widget.saveData(); + }), + ), + ) + : Container(), + Padding( + padding: EdgeInsets.only(top: 20, left: 10, right: 10), + child: Text( + widget.note ?? "", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + color: Colors.white38, + fontWeight: FontWeight.w400, + fontSize: 13), + ), + ) + ], + ), + ))); + } + + _onPageViewChange(int page) { + var isAllValid = true; + for (int i = 0; i < page; i++) { + setState(() { + var isValid = formKeyList[i].currentState!.validate(); + isAllValid &= isValid; + formKeyList[i].currentState!.save(); + if (isValid) {} + formErrorTile[i] = !isValid; + }); + } + if (widget.onChange != null) { + widget.onChange!(isAllValid); + } + setState(() { + count = page; + }); + } + + @override + Widget build(BuildContext context) { + return Container( + color: colors.darkScaffoldColor, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + StepCounterWidget(widgetLength, count, formErrorTile, controller), + Container( + height: MediaQuery.of(context).size.height * 0.85, + child: PreloadPageView.builder( + onPageChanged: _onPageViewChange, + scrollDirection: Axis.horizontal, + preloadPagesCount: widgetList.length - 1, + itemCount: widgetList.length, + controller: controller, + itemBuilder: (BuildContext context, int position) { + return widgetList[position]; + }), + ), + ], + ), + ); + } +} + +class FormKeepAlive extends StatefulWidget { + const FormKeepAlive(this.childWidget, this._formKey, {Key? key}) + : super(key: key); + + final Widget childWidget; + final GlobalObjectKey _formKey; + + @override + State createState() => _FormKeepAliveState(); +} + +class _FormKeepAliveState extends State + with AutomaticKeepAliveClientMixin { + @override + Widget build(BuildContext context) { + super.build(context); + return Form( + child: widget.childWidget, + key: widget._formKey, + onChanged: () { + //TODO: Decide if AutoSave as soon as changed or save after going to next page + widget._formKey.currentState!.save(); //AutoSave as each content page content is changed + }, + ); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/Widgets/GenderWidget.dart b/lib/Widgets/GenderWidget.dart new file mode 100644 index 0000000..4fc4ba4 --- /dev/null +++ b/lib/Widgets/GenderWidget.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:google_fonts/google_fonts.dart'; + +class GenderPickerWidget extends FormField { + GenderPickerWidget( + {FormFieldSetter? onSaved, + Function(String)? onChanged, + String? initialGender, + title, + selectedColor, + AutovalidateMode autoValidateMode = AutovalidateMode.disabled}) + : super( + onSaved: onSaved, + validator: (data) { + if (data == null) return "Please choose date"; + return null; + }, + initialValue: initialGender ?? MALE, + autovalidateMode: autoValidateMode, + builder: (FormFieldState state) { + onChanged!(state.value ?? MALE); + return Wrap( + + crossAxisAlignment: WrapCrossAlignment.center, + alignment: WrapAlignment.center, + runSpacing: 4.0, + children: [ + GenderWidget( + gender: MALE, + assetPath: "assets/svg/male.svg", + state: state, + successColor: selectedColor, + onChanged: onChanged), + GenderWidget( + gender: FEMALE, + assetPath: "assets/svg/female.svg", + state: state, + successColor: selectedColor, + onChanged: onChanged), + GenderWidget( + gender: OTHER, + assetPath: "assets/svg/transgender.svg", + state: state, + successColor: selectedColor, + onChanged: onChanged), + ], + ); + }); +} + +//assets/avatar_man.png +//assets/avatar_woman.png +class GenderWidget extends StatelessWidget { + const GenderWidget({ + Key? key, + required this.state, + required this.gender, + required this.assetPath, + this.successColor, + this.onChanged, + }) : super(key: key); + + final state; + final gender; + final assetPath; + final successColor; + final Function(String)? onChanged; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + state.didChange(gender); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircleAvatar( + maxRadius: 25, + backgroundColor: state.value == gender + ? successColor ?? colors.successColor + : Colors.transparent, + child: ClipOval( + child: SvgPicture.asset(assetPath), + ), + ), + Container( + child: Padding( + padding: EdgeInsets.only(left: 4, right: 15), + child: Chip( + backgroundColor: state.value == gender ? successColor ?? colors.successColor : colors.darkScaffoldColor, + label: Text(gender), + labelStyle: GoogleFonts.poppins(fontSize: 13,color: colors.darkPrimaryTextColor,fontWeight: state.value == gender ? FontWeight.bold : FontWeight.normal), + )), + ) + ], + ), + ); + } +} +//"assets/avatar_woman.png" diff --git a/lib/Widgets/IncomeWithTypeTextField.dart b/lib/Widgets/IncomeWithTypeTextField.dart new file mode 100644 index 0000000..37987f1 --- /dev/null +++ b/lib/Widgets/IncomeWithTypeTextField.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/DarkTheme.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +class IncomeWithTypeTextField extends StatefulWidget { + IncomeWithTypeTextField({ + Key? key, + required this.onSaved, + this.initialValue, + required this.hintText, + required this.text, + this.validate, + required this.listOfOptions, + this.initialDropdownValue, + }) : super(key: key); + + final void Function(String?, String?) onSaved; + final initialValue; + final String hintText; + final String text; + final String Function(String?)? validate; + final List listOfOptions; + final String? initialDropdownValue; + + @override + State createState() => + _IncomeWithTypeTextFieldState(); +} + +class _IncomeWithTypeTextFieldState extends State { + late String chosenOption; + + initState() { + super.initState(); + chosenOption = widget.initialDropdownValue ?? + widget.listOfOptions[widget.listOfOptions.length - 1]; + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 10.0, right: 10.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + flex: 2, + child: Card( + color: colors.darkScaffoldColor, + elevation: 0, + child: DropdownButtonHideUnderline( + child: ButtonTheme( + alignedDropdown: true, + child: DropdownButton( + value: chosenOption, + dropdownColor: colors.darkScaffoldColor, + isExpanded: true, + items: widget.listOfOptions.map((value) { + return DropdownMenuItem( + value: value, + child: Container( + color: colors.darkScaffoldColor, + child: Text( + value, + overflow: TextOverflow.ellipsis, + ), + padding: EdgeInsets.only(left: 8), + ), + ); + }).toList(), + onChanged: (newValue) { + setState(() { + chosenOption = newValue; + }); + }, + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor, + decorationColor: colors.errorColor), + ), + ), + ), + ), + ), + Expanded( + flex: 3, + child: TextFormField( + initialValue: widget.initialValue, + keyboardType: TextInputType.number, + autovalidateMode: AutovalidateMode.onUserInteraction, + style: darkTheme.DarkTheme.textTheme.bodyText2, + decoration: InputDecoration( + label: Text( + widget.text, + style: + GoogleFonts.poppins(color: colors.darkSecondaryTextColor), + ), + hintText: widget.hintText, + contentPadding: EdgeInsets.all(7.0), + ), + validator: widget.validate ?? + (value) { + if (value == "" || value == null) { + return "Enter Income"; + } + else if (int.tryParse(value) != null) { + if (double.parse(value) <= 0) + return "Income can't be less than or equal to 0"; + } else { + return "Income has to be a numeric value"; + } + }, + onSaved: (value) { + widget.onSaved(value, chosenOption); + }, + ), + ), + + ], + ), + ); + } +} diff --git a/lib/Widgets/LoadValidPageWidget.dart b/lib/Widgets/LoadValidPageWidget.dart new file mode 100644 index 0000000..1e7d2c8 --- /dev/null +++ b/lib/Widgets/LoadValidPageWidget.dart @@ -0,0 +1,86 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:http/http.dart' as http; +import 'package:oktoast/oktoast.dart'; + +import '../main.dart'; + +/*** + * This widget can be used between usual widgets to avoid rendering + * new pages when jwt not found. + * + * @param: + * Default Page, page to default to when jwt not found + * Target Page, page to load if jwt found + * + * @returns: + * Widget, appropriate widget depending on jwt state + * + * Usage: + * LoadValidPageWidget(Login(), Home()); + */ + +class LoadValidPageWidget extends StatelessWidget { + LoadValidPageWidget(this.DefaultPage, this.TargetPage, {Key? key}) + : super(key: key); + + final Widget DefaultPage; + final Widget TargetPage; + + Future _validateToken(String JWT) async { + String url = NETWORK_ADDRESS; + + var res = await http.get(Uri.http(url, '/api/validateToken'), headers: { + "Content-Type": "application/json", + 'user-auth-token': JWT + }).timeout( + const Duration(seconds: 30), + onTimeout: () { + return http.Response( + 'Server Timed out!', 408); // Request Timeout response status code + }, + ); + + return res; + } + + Future getVerifiedJwt(context) async { + var jwt = await jwtToken; + + if(jwt == "") return ""; + + try { + var res = await _validateToken(jwt); + if (res.statusCode == 401) { + await storage.delete(key: JWT_STORAGE_KEY); + showToast("Token could not be validated, logging out"); + return ""; + } else if (res.statusCode != 200) { + showToast("Couldn't validate token, continuing in offline mode!"); + return jwt; + } + } catch (e) { + showToast("Couldn't validate token, continuing in offline mode!"); + } + return jwt; + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: getVerifiedJwt(context), + builder: (context, data) { + if (!data.hasData) + return Scaffold( + body: Center( + child: CircularProgressIndicator(), + ), + ); + else if (data.hasData && data.data == '') + return DefaultPage; + else + return TargetPage; + }); + } +} diff --git a/lib/Widgets/LocationWidget.dart b/lib/Widgets/LocationWidget.dart new file mode 100644 index 0000000..fa28f91 --- /dev/null +++ b/lib/Widgets/LocationWidget.dart @@ -0,0 +1,163 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geolocator/geolocator.dart'; +import 'package:google_fonts/google_fonts.dart'; + +/** + * Form Widget to get current location with validation + */ + +class LocationWidgetField extends FormField { + LocationWidgetField( + {FormFieldSetter? onSaved, + FormFieldValidator? validator, + Position? defaultValue, + required BuildContext context, + required String title, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null) return "Location field empty"; + return null; + }, + initialValue: defaultValue, + autovalidateMode: autoValidateMode, + builder: (FormFieldState state) { + return Padding( + padding: + EdgeInsets.only(left: 20, right: 20, top: 10, bottom: 10), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Image(image: AssetImage("assets/location.png"),), + Padding( + padding: EdgeInsets.only(bottom: 30,top: 30), + child: Center( + child: Text(title, + textAlign: TextAlign.center, + style: GoogleFonts.montserrat( + fontSize: 25, color: Colors.white)), + ), + ), + Card( + elevation: 0, + color: colors.darkSecondBackgroundColor, + shape: RoundedRectangleBorder( + side: BorderSide( + width: 1.0, + color: state.hasError + ? colors.errorColor + : colors.darkSecondBackgroundColor), + ), + child: Padding( + padding: EdgeInsets.all(15), + child: Center( + child: state.hasError + ? Text( + state.errorText ?? "error", + style: GoogleFonts.poppins( + color: colors.errorColor, fontSize: 10), + ) + : Text( + state.value != null + ? state.value.toString() + : "Please fetch your location", + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + fontSize: 12, + color: colors.darkPrimaryTextColor)), + ), + ), + ), + Padding( + padding: EdgeInsets.only(top: 10, bottom: 5), + child: ElevatedButton( + onPressed: () async { + _determinePosition(context).then((value) { + state.didChange(value); + }).catchError((onError, stackTrace) { + state.didChange(null); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar( + content: Text(onError), + )); + }); + }, + child: Text( + 'Get location', + style: GoogleFonts.poppins( + color: colors.lightPrimaryTextColor), + ), + style: ElevatedButton.styleFrom( + minimumSize: Size(double.infinity, 50), + primary: colors.darkPrimaryTextColor, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20))), + ), + ), + ], + )); + }); +} + +Future _determinePosition(context) async { + bool serviceEnabled; + LocationPermission permission; + BuildContext? progressContext; + + serviceEnabled = await Geolocator.isLocationServiceEnabled(); + + if (!serviceEnabled) { + return Future.error( + 'Location services are disabled, try enabling location in your device'); + } + + permission = await Geolocator.checkPermission(); + if (permission == LocationPermission.denied) { + permission = await Geolocator.requestPermission(); + if (permission == LocationPermission.denied) { + return Future.error('Location permissions are denied'); + } + } + + if (permission == LocationPermission.deniedForever) { + return Future.error( + 'Location permissions are permanently denied, permission cannot be requested.'); + } + + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + progressContext = context; + return WillPopScope( + child: Dialog( + child: Padding( + padding: EdgeInsets.all(20), + child: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only(right: 20), + child: CircularProgressIndicator(), + ), + new Text( + "Fetching Location", + style: TextStyle(color: Colors.black), + ), + ], + ), + ), + ), + onWillPop: () async => false); + }, + ); + + var location = await Geolocator.getCurrentPosition( + desiredAccuracy: LocationAccuracy.best); + + Navigator.of(progressContext!, rootNavigator: true).pop(); + return location; +} diff --git a/lib/Widgets/LoginFormCard.dart b/lib/Widgets/LoginFormCard.dart new file mode 100644 index 0000000..118f63a --- /dev/null +++ b/lib/Widgets/LoginFormCard.dart @@ -0,0 +1,121 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +class FormCard extends StatefulWidget { + FormCard(this._usernameController, this._passwordController, this._nameError, + this._passwordError); + + final TextEditingController _usernameController; + final TextEditingController _passwordController; + final _nameError; + final _passwordError; + + @override + State createState() => _FormCardState(); +} + +class _FormCardState extends State { + var _showPassword = false; + + setUserName() async { + widget._usernameController.text = await getUserName; + } + + void initState() { + super.initState(); + setUserName(); + } + + @override + Widget build(BuildContext context) { + return new Container( + width: double.infinity, + padding: EdgeInsets.only(bottom: 1), + child: Padding( + padding: EdgeInsets.only(left: 8.0, right: 8.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Login", + textAlign: TextAlign.center, + style: GoogleFonts.montserrat( + fontSize: 40, color: colors.darkAccentColor)), + SizedBox( + height: 30, + ), + TextField( + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + controller: widget._usernameController, + decoration: InputDecoration( + hintText: "Enter username here", + label: Text("Username", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor)), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.darkSecondaryTextColor, width: 1.0)), + focusedBorder: OutlineInputBorder( + borderSide: + BorderSide(color: colors.successColor, width: 1.0)), + // border: OutlineInputBorder( + // borderSide: BorderSide( + // color: colors.darkSecondaryTextColor, width: 1.0 + // ), + // ), + floatingLabelStyle: + GoogleFonts.poppins(color: colors.darkAccentColor), + errorText: widget._nameError, + labelStyle: GoogleFonts.poppins(fontSize: 14)), + cursorColor: colors.darkPrimaryTextColor, + ), + SizedBox( + height: 40, + ), + TextField( + controller: widget._passwordController, + obscureText: !_showPassword, + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + decoration: InputDecoration( + suffixIcon: IconButton( + onPressed: () { + setState(() { + _showPassword = !_showPassword; + }); + }, + icon: Icon( + _showPassword ? Icons.visibility_off : Icons.visibility, + color: colors.darkAccentColor, + ), + ), + hintText: "Enter password here", + focusColor: Color(0xffF5A06D), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: colors.darkSecondaryTextColor, width: 1.0)), + focusedBorder: OutlineInputBorder( + borderSide: + BorderSide(color: colors.successColor, width: 1.0)), + border: OutlineInputBorder( + borderSide: + BorderSide(color: colors.successColor, width: 1.0), + ), + label: Text("Password", + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor)), + floatingLabelStyle: + GoogleFonts.poppins(color: colors.darkSecondaryTextColor), + errorText: widget._passwordError, + labelStyle: GoogleFonts.poppins( + fontSize: 14.0, color: colors.darkAccentColor), + )), + SizedBox( + height: 30, + ), + ], + ), + ), + ); + } +} diff --git a/lib/Widgets/NavigationDrawer.dart b/lib/Widgets/NavigationDrawer.dart new file mode 100644 index 0000000..fc6ee99 --- /dev/null +++ b/lib/Widgets/NavigationDrawer.dart @@ -0,0 +1,122 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Screens/ProfilePage.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:geo_spatial/Utils/Utils.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class NavigationDrawer extends StatelessWidget { + NavigationDrawer({Key? key}) : super(key: key); + final padding = EdgeInsets.symmetric(horizontal: 20); + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: getUserData, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + { + var dataJson = json.decode(snapshot.requireData); + var gender = dataJson[0]["gender"]; + + return Drawer( + child: Material( + color: colors.darkScaffoldColor, + child: Column( + children: [ + UserAccountsDrawerHeader( + currentAccountPicture: CircleAvatar( + child: ClipOval( + child: Image( + image: gender == "Male" + ? AssetImage("assets/avatar_man.png") + : AssetImage("assets/avatar_woman.png"), + ), + ), + ), + decoration: BoxDecoration( + image: DecorationImage( + fit: BoxFit.cover, + image: AssetImage("assets/Illustration.png"))), + accountName: Text( + dataJson[0]["Name"], + style: GoogleFonts.poppins( + color: colors.darkPrimaryTextColor, fontSize: 18), + ), + accountEmail: Text( + dataJson[0]["username"], + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + ), + buildMenuItem( + text: 'Home', + icon: Icons.home, + onTap: () { + Navigator.of(context).pop(); + }), + buildMenuItem( + text: 'Profile', + icon: Icons.person, + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => ProfilePage())); + }), + Expanded(child: Container()), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20.0), + child: Container( + height: 1, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide(color: Colors.grey), + ), + ), + ), + ), + buildMenuItem( + text: 'Sign Out', + icon: Icons.logout, + onTap: () async { + logoutDialog(context); + }, + ), + ], + ), + ), + ); + } + } else { + return Center( + child: CircularProgressIndicator(), + ); + } + }); + } + + Widget buildMenuItem({ + required String text, + required IconData icon, + VoidCallback? onTap, + }) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 10.0), + child: ListTile( + selectedTileColor: colors.darkAccentColor, + leading: Padding( + padding: EdgeInsets.only(left: 10), + child: Icon( + icon, + color: colors.darkAccentColor, + ), + ), + title: Text( + text, + style: GoogleFonts.poppins(color: colors.darkPrimaryTextColor), + ), + onTap: onTap, + ), + ); + } +} diff --git a/lib/Widgets/NestedOptionWidgetFormField.dart b/lib/Widgets/NestedOptionWidgetFormField.dart new file mode 100644 index 0000000..7650202 --- /dev/null +++ b/lib/Widgets/NestedOptionWidgetFormField.dart @@ -0,0 +1,138 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Widgets/NestedOptionsWidget.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:google_fonts/google_fonts.dart'; + +class NestedOptionWidgetFormField extends FormField> { + NestedOptionWidgetFormField( + {FormFieldSetter>? onSaved, + FormFieldValidator>? validator, + Function(List)? onChanged, + required context, + required String title, + required List nestedOptionData, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + initialValue: nestedOptionData, + onSaved: onSaved, + validator: validator ?? + (data) { + areSubOptionsChosen(i) { + int flag = 0; + i.subOptionDataMap!.forEach((key, value) { + if (value) { + flag++; + } + }); + return flag != 0; + } + + bool isSelected = false; + for (var i in data!) { + if (i.isSelected) { + if (!areSubOptionsChosen(i)) { + return "Please choose occupation under selected categories"; + } + } + isSelected |= i.isSelected; + } + if (!isSelected) { + return "Please choose an option"; + } + return null; + }, + builder: (state) { + getDisplayData() { + var selectedOptions = []; + for (var i in state.value!) { + if (i.isSelected) selectedOptions.add(i.boxName); + } + if (state.hasError) { + if (selectedOptions.isNotEmpty) { + return Text( + selectedOptions.join(", "), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: GoogleFonts.poppins(color: colors.errorColor), + ); + } + return Text( + state.errorText ?? "Please choose a value", + style: GoogleFonts.poppins(color: colors.errorColor), + ); + } else { + if (selectedOptions.isNotEmpty) { + return Text( + selectedOptions.join(", "), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 16), + ); + } else { + return Text( + "Please choose a value", + style: GoogleFonts.poppins( + color: Colors.white, + fontWeight: FontWeight.w400, + fontSize: 16), + ); + } + } + } + + return Padding( + padding: EdgeInsets.all(10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 8), + child: Text(title, + style: GoogleFonts.montserrat( + fontSize: 15, + color: colors.darkPrimaryTextColor)), + ), + Card( + elevation: 5, + margin: EdgeInsets.only(top: 3, bottom: 3), + color: colors.darkScaffoldColor, + child: ListTile( + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => NestedOptionWidget( + title: title, + onChanged: (val) { + state.didChange(val); + state.validate(); + }, + nestedOptionData: state.value!, + ), + )); + }, + //Pass a function which is called onSaved in the next page and add data to the class object + trailing: Icon( + Icons.arrow_right, + color: colors.darkSecondaryTextColor, + ), + title: getDisplayData(), + ), + ), + state.hasError + ? Container( + padding: EdgeInsets.all(10), + child: Text( + state.errorText ?? "error", + style: GoogleFonts.poppins( + color: colors.errorColor, fontSize: 10), + ), + ) + : Container() + ], + ), + ); + }); +} diff --git a/lib/Widgets/NestedOptionsWidget.dart b/lib/Widgets/NestedOptionsWidget.dart new file mode 100644 index 0000000..55bb8b6 --- /dev/null +++ b/lib/Widgets/NestedOptionsWidget.dart @@ -0,0 +1,140 @@ +import 'dart:convert'; + +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Widgets/AppBarBackButtonWidget.dart'; +import 'package:geo_spatial/Widgets/CheckBoxAddExtraDialog.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class NestedOptionData { + bool isSelected = false; + Map? subOptionDataMap; + String? boxName; + + NestedOptionData({this.subOptionDataMap, this.boxName}); + + toJsonString() { + return json.encode({ + "isSelected": isSelected, + "boxName": boxName, + "selectedData": json.encode(subOptionDataMap), + }); + } + + factory NestedOptionData.fromJson(String jsonObject) { + var decodedJson = json.decode(jsonObject); + var nestedDataObject = NestedOptionData(); + nestedDataObject.boxName = decodedJson['boxName'] as String; + nestedDataObject.isSelected = decodedJson['isSelected'] as bool; + nestedDataObject.subOptionDataMap = + Map.from(json.decode(decodedJson["selectedData"])); + return nestedDataObject; + } +} + +class NestedOptionWidget extends StatefulWidget { + const NestedOptionWidget( + {Key? key, required this.nestedOptionData, this.onChanged, this.title}) + : super(key: key); + + final List nestedOptionData; + final String? title; + final Function(List)? onChanged; + + @override + _NestedOptionWidgetState createState() => _NestedOptionWidgetState(); +} + +class _NestedOptionWidgetState extends State { + var selectedColor = Color(0xffffffff); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBarBackButton(widget.title ?? "Select Options"), + body: Padding( + padding: EdgeInsets.all(20), + child: Container( + decoration: BoxDecoration( + color: colors.darkSecondBackgroundColor, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Color(0xBC252426), + blurRadius: 8.0, + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(0), + child: ListView.builder( + itemCount: widget.nestedOptionData.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.all(5), + child: Container( + padding: EdgeInsets.all(10), + child: Column( + children: [ + Card( + elevation: 10, + color: colors.darkScaffoldColor, + child: CheckboxListTile( + activeColor: colors.darkAccentColor, + value: + widget.nestedOptionData[index].isSelected, + title: Text( + widget.nestedOptionData[index].boxName!, + style: GoogleFonts.poppins( + color: selectedColor, + fontWeight: FontWeight.w400, + fontSize: 18), + ), + onChanged: (val) { + setState(() { + //Enable the below commented if only one category can be chosen at a time + // for (var i in widget.nestedOptionData) { + // i.isSelected = false; + // } + widget.nestedOptionData[index].isSelected = + val!; + }); + if (widget.onChanged != null) + widget.onChanged!(widget.nestedOptionData); + }), + ), + widget.nestedOptionData[index].isSelected + ? Container( + margin: EdgeInsets.symmetric(horizontal: 5), + decoration: BoxDecoration( + color: colors.darkSecondAccentColor, + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(10), + bottomRight: Radius.circular(10))), + child: CheckBoxAddExtraAlertDialog( + hint: "Choose job", + autoValidateMode: AutovalidateMode.always, + autoSave: true, + onSaved: (map) { + widget.nestedOptionData[index] + .subOptionDataMap = map!; + if (widget.onChanged != null) + widget.onChanged!( + widget.nestedOptionData); + }, + dataMap: widget.nestedOptionData[index] + .subOptionDataMap!, + context: context), + ) + : Container() + ], + ), + ), + ); + }), + ), + ), + ), + ); + } +} diff --git a/lib/Widgets/OptionsFormWidget.dart b/lib/Widgets/OptionsFormWidget.dart new file mode 100644 index 0000000..a574847 --- /dev/null +++ b/lib/Widgets/OptionsFormWidget.dart @@ -0,0 +1,118 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +/** + * Implementation: + *OptionsWidget(options: [["Yes", "yes"], ["No", "no"]], setDefaultValue: false, onSaved: (data){print(data);}), + */ + +class OptionsWidget extends FormField { + OptionsWidget( + {FormFieldSetter? onSaved, + FormFieldValidator? validator, + Function(dynamic)? onChanged, + required List options, + required String title, + String? defaultValue, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null) return "Please choose an option"; + return null; + }, + initialValue: defaultValue, + autovalidateMode: autoValidateMode, + builder: (FormFieldState state) { + return Padding( + padding: const EdgeInsets.only(top: 40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 10), + child: Text( + title, + textAlign: TextAlign.center, + style: GoogleFonts.poppins( + fontSize: 15.0, color: colors.darkPrimaryTextColor), + ), + ), + Wrap( + alignment: WrapAlignment.center, + children: options + .map((e) => new OptionButton( + onChanged: onChanged, + text: e[0], + optionKey: e[1], + state: state, + isError: state.hasError, + isSelected: state.value == e[1])) + .toList()), + Padding( + padding: EdgeInsets.all(5), + child: state.hasError + ? Text( + state.errorText ?? "error", + style: GoogleFonts.poppins( + color: colors.errorColor, fontSize: 10), + ) + : Container(), + ) + ], + ), + ); + }); +} + +class OptionButton extends StatelessWidget { + const OptionButton( + {Key? key, + required this.text, + required this.optionKey, + required this.state, + required this.isSelected, + this.onChanged, + this.isError = false}) + : super(key: key); + + final text; + final optionKey; + final state; + final isSelected; + final isError; + final onChanged; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(left: 3, right: 3, top: 1, bottom: 1), + child: ElevatedButton( + style: ButtonStyle( + backgroundColor: MaterialStateProperty.all(isSelected + ? Color.fromRGBO(148, 182, 111, 1.0) + : isError + ? colors.errorColor + : colors.darkScaffoldColor), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(50)), + side: isError + ? BorderSide(color: Colors.red) + : BorderSide.none))), + onPressed: () { + state.didChange(optionKey); + if (onChanged != null) { + onChanged!(optionKey); + } + }, + child: Text( + text, + style: GoogleFonts.poppins(color: Colors.white), + )), + ); + } +} diff --git a/lib/Widgets/PageViewContentBox.dart b/lib/Widgets/PageViewContentBox.dart new file mode 100644 index 0000000..17d13ae --- /dev/null +++ b/lib/Widgets/PageViewContentBox.dart @@ -0,0 +1,37 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +class PageViewContentBox extends StatelessWidget { + const PageViewContentBox(this.centerWidget, {Key? key}) : super(key: key); + + final Widget centerWidget; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.all(20), + child: Container( + decoration: BoxDecoration( + color: colors.darkSecondBackgroundColor, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Color(0xBC252426), + blurRadius: 8.0, + ), + ], + ), + child: Padding( + padding: EdgeInsets.all(12), + child: CustomScrollView( + slivers: [ + SliverFillRemaining(hasScrollBody: false, child: centerWidget), + ], + ), + ), + ), + ); + } +} diff --git a/lib/Widgets/StartingEndingTimeWidget.dart b/lib/Widgets/StartingEndingTimeWidget.dart new file mode 100644 index 0000000..50f56dd --- /dev/null +++ b/lib/Widgets/StartingEndingTimeWidget.dart @@ -0,0 +1,102 @@ +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +class StartingEndingTimeWidget extends FormField> { + StartingEndingTimeWidget( + {FormFieldSetter>? onSaved, + FormFieldValidator>? validator, + label, + initialValue, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null || data.isEmpty) + return "Please enter a value"; + return null; + }, + initialValue: initialValue ?? [TimeOfDay.now(), TimeOfDay.now()], + autovalidateMode: autoValidateMode, + builder: (FormFieldState> state) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.only(bottom: 8), + child: Text(label ?? "Choose Starting and Ending Time", + style: GoogleFonts.montserrat( + fontSize: 15, + color: colors.darkPrimaryTextColor)), + ), + Card( + color: colors.darkScaffoldColor, + elevation: 10, + margin: EdgeInsets.only(bottom: 4), + child: Padding( + padding: + EdgeInsets.symmetric(horizontal: 15, vertical: 8), + child: Column( + children: [ + TimeBoxWidget( + timeMessage: "Starting Time: ", + state: state, + index: 0, + ), + TimeBoxWidget( + timeMessage: "Ending Time: ", + state: state, + index: 1, + ) + ], + ), + ), + ), + ]); + }); +} + +class TimeBoxWidget extends StatelessWidget { + const TimeBoxWidget( + {Key? key, + required this.timeMessage, + required this.state, + required this.index}) + : super(key: key); + + final String timeMessage; + final FormFieldState> state; + final int index; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded(flex: 1, child: Text(timeMessage)), + Expanded( + flex: 1, + child: ElevatedButton( + style: ElevatedButton.styleFrom(primary: colors.darkAccentColor), + onPressed: () async { + TimeOfDay? pickedTime = await showTimePicker( + context: context, + initialTime: state.value?.elementAt(index) ?? TimeOfDay.now(), + ); + var list = state.value; + list![index] = pickedTime!; + state.didChange(list); + }, + child: Text( + "${state.value![index].hour}:${state.value![index].minute} ${state.value![index].period == DayPeriod.am ? "AM" : "PM"}", + style: GoogleFonts.montserrat( + color: Colors.white, fontWeight: FontWeight.w400), + ), + ), + ) + ], + ); + } +} diff --git a/lib/Widgets/StepCounterWidget.dart b/lib/Widgets/StepCounterWidget.dart new file mode 100644 index 0000000..aa35930 --- /dev/null +++ b/lib/Widgets/StepCounterWidget.dart @@ -0,0 +1,132 @@ +import 'package:flutter/material.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; +import 'package:preload_page_view/preload_page_view.dart'; + +/** + * Widget for steps count in registration pages + * + * @param: + * int totalSteps: Total number of steps in registration + * int currentStep: Current position of registration + * + * @returns: + * Widget: Returns a StepProgressIndicator + */ + +class StepCounterWidget extends StatefulWidget { + const StepCounterWidget( + this.totalSteps, this.currentStep, this.errorArray, this.controller, + {Key? key}) + : super(key: key); + + final int totalSteps; + final int currentStep; + final List errorArray; + final PreloadPageController controller; + + @override + _StepCounterWidgetState createState() => _StepCounterWidgetState(); +} + +class _StepCounterWidgetState extends State { + @override + Widget build(BuildContext context) { + List checkBoxWidgetList = []; + + for (int i = 0; i < widget.totalSteps; i++) { + if (i == widget.totalSteps - 1) { + if (i == widget.currentStep) { + checkBoxWidgetList.add(CheckBox(5, widget.controller, i)); + } else { + checkBoxWidgetList.add(CheckBox(4, widget.controller, i)); + } + } else if (i < widget.currentStep) { + try { + widget.errorArray[i] + ? checkBoxWidgetList.add(CheckBox(0, widget.controller, i)) + : checkBoxWidgetList.add(CheckBox(1, widget.controller, i)); + } catch (error) { + checkBoxWidgetList.add(CheckBox(1, widget.controller, i)); + } + } else if (i == widget.currentStep) { + checkBoxWidgetList.add(CheckBox(2, widget.controller, i)); + } else { + checkBoxWidgetList.add(CheckBox(3, widget.controller, i)); + } + } + + return Padding( + padding: EdgeInsets.only(left: 10, right: 10), + child: Row( + children: checkBoxWidgetList, + ), + ); + } +} + +class CheckBox extends StatelessWidget { + const CheckBox(this.iconType, this.controller, this.tilePosition, {Key? key}) + : super(key: key); + final int iconType; + final PreloadPageController controller; + final int tilePosition; + + @override + Widget build(BuildContext context) { + IconData icon; + Color iconColor; + Color backgroundColor; + + if (iconType == 0) { + icon = Icons.close; + backgroundColor = Color.fromARGB(255, 255, 167, 167); + iconColor = Colors.red; + } else if (iconType == 1) { + icon = Icons.check; + iconColor = Colors.white; + backgroundColor = Color(0xff7bde27); + } else if (iconType == 2) { + icon = Icons.remove; + iconColor = Color.fromARGB(255, 255, 255, 255); + backgroundColor = colors.darkAccentColor; + } else if (iconType == 3) { + icon = Icons.remove; + iconColor = Color.fromARGB(255, 0, 0, 0); + backgroundColor = colors.darkSecondAccentColor; + } else if (iconType == 4) { + icon = Icons.upload_rounded; + iconColor = Color.fromARGB(255, 255, 255, 255); + backgroundColor = colors.darkSecondAccentColor; + } else { + icon = Icons.upload_rounded; + iconColor = Color.fromARGB(255, 255, 255, 255); + backgroundColor = colors.darkSecondAccentColor; + } + return Expanded( + child: Container( + decoration: BoxDecoration(), + margin: EdgeInsets.only(left: 3.0, right: 3.0), + child: Material( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20))), + color: backgroundColor, + child: InkWell( + onTap: () { + controller.animateToPage( + tilePosition, + curve: Curves.ease, + duration: Duration(seconds: 1), + ); + }, + child: Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Icon( + icon, + color: iconColor, + ), + ), + ), + ), + )); + } +} diff --git a/lib/Widgets/TagTextWidget.dart b/lib/Widgets/TagTextWidget.dart new file mode 100644 index 0000000..fa3c2ac --- /dev/null +++ b/lib/Widgets/TagTextWidget.dart @@ -0,0 +1,152 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; + +class TagTextWidget extends FormField> { + TagTextWidget( + {FormFieldSetter>? onSaved, + FormFieldValidator>? validator, + list, + required label, + required hint, + emptyListMessage, + errorField, + autofillHints, + search = const [], + initialValue, + AutovalidateMode autoValidateMode = AutovalidateMode.onUserInteraction}) + : super( + onSaved: onSaved, + validator: validator ?? + (data) { + if (data == null || data.isEmpty) + return errorField ?? "Please enter a value"; + return null; + }, + initialValue: initialValue ?? [], + autovalidateMode: autoValidateMode, + builder: (FormFieldState> state) { + final TextEditingController _contentEditingController = + TextEditingController(); + + ScrollController _scrollController = new ScrollController(); + + return Padding( + padding: EdgeInsets.only(bottom: 10), + child: Column( + children: [ + Padding( + padding: EdgeInsets.only(bottom: 10), + child: TypeAheadField( + hideOnEmpty: true, + hideSuggestionsOnKeyboardHide: false, + getImmediateSuggestions: true, + textFieldConfiguration: TextFieldConfiguration( + style: TextStyle(color: Colors.white), + controller: _contentEditingController, + onSubmitted: (string) { + if (!string.isEmpty) { + _contentEditingController.clear(); + List? list = state.value; + list?.add(string); + state.didChange(list); + } + }, + decoration: InputDecoration( + errorText: + state.hasError ? state.errorText : null, + label: Text( + label, + style: GoogleFonts.poppins( + color: colors.darkSecondaryTextColor), + ), + hintText: hint, + contentPadding: EdgeInsets.all(7.0), + )), + suggestionsCallback: (pattern) async { + return search.where((element) => element + .toString() + .toLowerCase() + .contains(pattern.toLowerCase())); + }, + itemBuilder: (context, suggestion) { + return ListTile( + title: Text(suggestion.toString(), + style: GoogleFonts.poppins(fontSize: 15)), + ); + }, + onSuggestionSelected: (suggestion) { + List? list = state.value; + list?.add(suggestion.toString()); + state.didChange(list); + }, + ), + ), + Container( + height: 35.0, + width: double.infinity, + child: state.value!.isEmpty + ? Center( + child: Text(emptyListMessage ?? "List is empty"), + ) + : ListView.builder( + controller: _scrollController, + scrollDirection: Axis.horizontal, + itemCount: state.value?.length, + itemBuilder: (BuildContext context, int index) { + return TagBox( + text: state.value![index], + delete: () { + List? list = state.value; + list?.removeAt(index); + state.didChange(list); + }); + }, + ), + ) + ], + ), + ); + }); +} + +class TagBox extends StatelessWidget { + const TagBox({Key? key, this.text, Function? this.delete}) : super(key: key); + + final text; + final delete; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(horizontal: 4.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), color: Colors.white), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Padding( + padding: EdgeInsets.only(left: 7, right: 2, top: 2, bottom: 2), + child: Text( + text, + style: TextStyle(color: Colors.black, fontSize: 15), + ), + ), + Padding( + padding: EdgeInsets.all(4), + child: GestureDetector( + onTap: () { + delete(); + }, + child: Icon( + Icons.cancel, + size: 15, + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index 4fdfda5..9cc27ec 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,42 +2,36 @@ import 'package:flutter/material.dart'; import 'package:geo_spatial/Screens/Login.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:geo_spatial/Screens/Home.dart'; +import 'package:flutter/services.dart'; +import 'package:geo_spatial/Utils/Constants.dart'; +import 'package:geo_spatial/Utils/DarkTheme.dart'; +import 'package:geo_spatial/Widgets/LoadValidPageWidget.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:geo_spatial/Utils/Colors.dart' as colors; -final storage = FlutterSecureStorage(); - -void main() { - runApp( - const MaterialApp( - debugShowCheckedModeBanner: false, - home: SafeArea( - child: MyApp(), - ), - ), - ); -} +//TODO: Build a modular function for HTTP requests -class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); - - Future get jwtToken async { - var jwt = await storage.read(key: "jwt"); - print('jwt' + jwt.toString()); +final storage = FlutterSecureStorage(); - if (jwt == null) return ""; - return jwt; +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + var data = await storage.read(key: REMEMBER_ME_KEY); + var rememberMe = true; + if (null != data) { + rememberMe = data == "true"; + if (!rememberMe) { + await storage.delete(key: JWT_STORAGE_KEY); + } } - @override - Widget build(BuildContext context) { - return FutureBuilder( - future: jwtToken, - builder: (context, data) { - if (!data.hasData) - return Login(); - else if (data.hasData && data.data == '') - return Login(); - else - return Home(); - }); - } + runApp(OKToast( + position: ToastPosition.center, + backgroundColor: colors.darkAccentColor, + child: MaterialApp( + home: rememberMe ? LoadValidPageWidget(Login(), Home()) : Login(), + debugShowCheckedModeBanner: false, + theme: darkTheme.DarkTheme), + )); } diff --git a/lib/objectbox-model.json b/lib/objectbox-model.json new file mode 100644 index 0000000..f42350c --- /dev/null +++ b/lib/objectbox-model.json @@ -0,0 +1,474 @@ +{ + "_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.", + "_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.", + "_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.", + "entities": [ + { + "id": "1:6144760902505378968", + "lastPropertyId": "9:1160256595193105843", + "name": "CommunityDataModel", + "properties": [ + { + "id": "1:4748866847843651725", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:2932393208152434267", + "name": "resourceType", + "type": 9 + }, + { + "id": "3:1921952090063309092", + "name": "villageCode", + "type": 9 + }, + { + "id": "4:4458344485253850474", + "name": "savedTime", + "type": 9 + }, + { + "id": "5:7168925326320672943", + "name": "dbLocationTopLeft", + "type": 9 + }, + { + "id": "6:6976643051535550913", + "name": "dbLocationTopRight", + "type": 9 + }, + { + "id": "7:2527558881981362435", + "name": "dbLocationBottomLeft", + "type": 9 + }, + { + "id": "8:1374390598853638581", + "name": "dbLocationBottomRight", + "type": 9 + }, + { + "id": "9:1160256595193105843", + "name": "recordCollectingUserId", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "2:4604626538020621410", + "lastPropertyId": "47:9107986757309043468", + "name": "FamilyMemberIndividualDataModel", + "properties": [ + { + "id": "1:1615626269752887015", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:147960419452912546", + "name": "userName", + "type": 9 + }, + { + "id": "3:2641592509733256058", + "name": "dateOfBirth", + "type": 10 + }, + { + "id": "4:6282594208002927050", + "name": "gender", + "type": 9 + }, + { + "id": "5:4209209735115259461", + "name": "phoneNumber", + "type": 9 + }, + { + "id": "6:3962014586057530124", + "name": "educationQualification", + "type": 9 + }, + { + "id": "7:1340435734295744333", + "name": "aadhaarNumber", + "type": 9 + }, + { + "id": "8:8202265740818534316", + "name": "dailyWageWorker", + "type": 9 + }, + { + "id": "11:742592545502650523", + "name": "pension", + "type": 9 + }, + { + "id": "12:7975675992055446810", + "name": "businessStatus", + "type": 9 + }, + { + "id": "13:747564586513409332", + "name": "maritalStatus", + "type": 9 + }, + { + "id": "14:5573484003127214285", + "name": "specialSkills", + "type": 30 + }, + { + "id": "18:2506597441281996495", + "name": "surgeries", + "type": 9 + }, + { + "id": "19:7773359300531977330", + "name": "anganwadiServicesAware", + "type": 9 + }, + { + "id": "20:9088237078871159207", + "name": "anganwadiServicesUsing", + "type": 9 + }, + { + "id": "21:591653671698069367", + "name": "anganwadiServicesUsedList", + "type": 30 + }, + { + "id": "25:515443054774028092", + "name": "useOfTobacco", + "type": 9 + }, + { + "id": "26:8707238561404829402", + "name": "useOfAlcohol", + "type": 9 + }, + { + "id": "27:3309599826830426346", + "name": "aarogyaSetuInstalled", + "type": 9 + }, + { + "id": "28:9084202418978987072", + "name": "vizhithiruInstalled", + "type": 9 + }, + { + "id": "29:7889719359007222937", + "name": "dataValid", + "type": 1 + }, + { + "id": "31:4870102737459248754", + "name": "dbVulnerabilities", + "type": 9 + }, + { + "id": "33:5419770240499089417", + "name": "workTimings", + "type": 30 + }, + { + "id": "34:339180766123450759", + "name": "noOfDaysWorking", + "type": 9 + }, + { + "id": "35:239463832765470197", + "name": "PHCServicesUsed", + "type": 9 + }, + { + "id": "36:6440758785035669475", + "name": "privateClinicServicesUsed", + "type": 9 + }, + { + "id": "37:3741391841915175758", + "name": "employed", + "type": 9 + }, + { + "id": "38:2451270514680374685", + "name": "income", + "type": 9 + }, + { + "id": "39:5436158745852723253", + "name": "incomeType", + "type": 9 + }, + { + "id": "40:4028603457625037657", + "name": "dbPrivateServiceReason", + "type": 9 + }, + { + "id": "41:3132879446055335430", + "name": "dbCommunicableDiseases", + "type": 9 + }, + { + "id": "42:7751946170395515723", + "name": "dbFrequentAilments", + "type": 9 + }, + { + "id": "43:4854856293984079980", + "name": "dbNonCommunicableDiseases", + "type": 9 + }, + { + "id": "44:558549105718785352", + "name": "dbTobaccoProducts", + "type": 9 + }, + { + "id": "45:8806096688498887024", + "name": "dbOccupationData", + "type": 9 + }, + { + "id": "46:1773687084148916152", + "name": "student", + "type": 9 + }, + { + "id": "47:9107986757309043468", + "name": "studentEducationCategory", + "type": 9 + } + ], + "relations": [] + }, + { + "id": "3:4555229639046191310", + "lastPropertyId": "38:7524624993274240071", + "name": "FamilyMembersCommonDataModel", + "properties": [ + { + "id": "1:8819136016483451605", + "name": "id", + "type": 6, + "flags": 1 + }, + { + "id": "2:3437476224699639583", + "name": "drinkingWater", + "type": 9 + }, + { + "id": "4:2341047533460923742", + "name": "toiletFacility", + "type": 9 + }, + { + "id": "5:111976571800950215", + "name": "communityToilet", + "type": 9 + }, + { + "id": "6:8175958428232054206", + "name": "environmentSanitationLevel", + "type": 9 + }, + { + "id": "7:7080507576734769781", + "name": "runningWaterAvailable", + "type": 9 + }, + { + "id": "8:3619777862295069103", + "name": "noOfTwoWheelers", + "type": 9 + }, + { + "id": "9:2220681223517389029", + "name": "noOfThreeWheelers", + "type": 9 + }, + { + "id": "10:5295960391830025761", + "name": "noOfFourWheelers", + "type": 9 + }, + { + "id": "11:3999230000658269584", + "name": "isCattleOwned", + "type": 9 + }, + { + "id": "12:8174000252850380247", + "name": "incomeFromCattle", + "type": 9 + }, + { + "id": "13:4187254125313827388", + "name": "isFarmLandOwned", + "type": 9 + }, + { + "id": "14:4007865345223693029", + "name": "isSeedsPreserved", + "type": 9 + }, + { + "id": "15:5799753283360608792", + "name": "isKitchenGardenOwned", + "type": 9 + }, + { + "id": "16:3272250098967751212", + "name": "addressOne", + "type": 9 + }, + { + "id": "17:5993366458798453696", + "name": "addressTwo", + "type": 9 + }, + { + "id": "18:8246574557213969028", + "name": "city", + "type": 9 + }, + { + "id": "19:5398790887074809282", + "name": "locationPageValid", + "type": 1 + }, + { + "id": "20:6657479069084504293", + "name": "commonDetailsValid", + "type": 1 + }, + { + "id": "22:5541702793145940965", + "name": "dbLocationTopLeft", + "type": 9 + }, + { + "id": "23:4155729105605878928", + "name": "dbLocationTopRight", + "type": 9 + }, + { + "id": "24:176578608674560191", + "name": "dbLocationBottomLeft", + "type": 9 + }, + { + "id": "25:3352596760349944439", + "name": "dbLocationBottomRight", + "type": 9 + }, + { + "id": "26:8858146981830191665", + "name": "dbTwoThreeWheelManufacturer", + "type": 9 + }, + { + "id": "27:6657331618266238890", + "name": "dbTwoFourManufacturer", + "type": 9 + }, + { + "id": "28:2360124385132929587", + "name": "dbLocalFoodMap", + "type": 9 + }, + { + "id": "29:5230846993278344596", + "name": "dbPreservedSeedsMap", + "type": 9 + }, + { + "id": "30:2725907391283288263", + "name": "dbTreesOwnedMap", + "type": 9 + }, + { + "id": "31:257396080593114234", + "name": "dbKitchenGardenPlants", + "type": 9 + }, + { + "id": "32:2980984211940443041", + "name": "dbSourceOfDrinkingWater", + "type": 9 + }, + { + "id": "33:2417488989427376885", + "name": "villageCode", + "type": 9 + }, + { + "id": "34:938904163813263655", + "name": "savedTime", + "type": 9 + }, + { + "id": "35:4854280675953919579", + "name": "dbNoToiletsWhy", + "type": 9 + }, + { + "id": "36:6442255301640644335", + "name": "dbCropsCultivated", + "type": 9 + }, + { + "id": "37:8711686748126605615", + "name": "headOfFamily", + "type": 9 + }, + { + "id": "38:7524624993274240071", + "name": "recordCollectingUserId", + "type": 9 + } + ], + "relations": [ + { + "id": "1:3641078863127427509", + "name": "individualDataList", + "targetId": "2:4604626538020621410" + } + ] + } + ], + "lastEntityId": "3:4555229639046191310", + "lastIndexId": "0:0", + "lastRelationId": "1:3641078863127427509", + "lastSequenceId": "0:0", + "modelVersion": 5, + "modelVersionParserMinimum": 5, + "retiredEntityUids": [], + "retiredIndexUids": [], + "retiredPropertyUids": [ + 961043903550204529, + 6821885131227205219, + 3511831625273329956, + 8089710746679848906, + 4567441488943246138, + 1321911158882624161, + 1780571115080959247, + 5383502869453245964, + 2820386840249227222, + 5611188519781040934, + 1258910779661384685, + 1328642062638523745 + ], + "retiredRelationUids": [], + "version": 1 +} \ No newline at end of file diff --git a/lib/objectbox.g.dart b/lib/objectbox.g.dart new file mode 100644 index 0000000..3cbc849 --- /dev/null +++ b/lib/objectbox.g.dart @@ -0,0 +1,1476 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: camel_case_types + +import 'dart:typed_data'; + +import 'package:objectbox/flatbuffers/flat_buffers.dart' as fb; +import 'package:objectbox/internal.dart'; // generated code can access "internal" functionality +import 'package:objectbox/objectbox.dart'; +import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart'; + +import 'Model/CommunityDataModel.dart'; +import 'Model/FamilyDataModels.dart'; + +export 'package:objectbox/objectbox.dart'; // so that callers only have to import this file + +final _entities = [ + ModelEntity( + id: const IdUid(1, 6144760902505378968), + name: 'CommunityDataModel', + lastPropertyId: const IdUid(9, 1160256595193105843), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 4748866847843651725), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 2932393208152434267), + name: 'resourceType', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 1921952090063309092), + name: 'villageCode', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(4, 4458344485253850474), + name: 'savedTime', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(5, 7168925326320672943), + name: 'dbLocationTopLeft', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(6, 6976643051535550913), + name: 'dbLocationTopRight', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(7, 2527558881981362435), + name: 'dbLocationBottomLeft', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(8, 1374390598853638581), + name: 'dbLocationBottomRight', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(9, 1160256595193105843), + name: 'recordCollectingUserId', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(2, 4604626538020621410), + name: 'FamilyMemberIndividualDataModel', + lastPropertyId: const IdUid(47, 9107986757309043468), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 1615626269752887015), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 147960419452912546), + name: 'userName', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(3, 2641592509733256058), + name: 'dateOfBirth', + type: 10, + flags: 0), + ModelProperty( + id: const IdUid(4, 6282594208002927050), + name: 'gender', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(5, 4209209735115259461), + name: 'phoneNumber', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(6, 3962014586057530124), + name: 'educationQualification', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(7, 1340435734295744333), + name: 'aadhaarNumber', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(8, 8202265740818534316), + name: 'dailyWageWorker', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(11, 742592545502650523), + name: 'pension', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(12, 7975675992055446810), + name: 'businessStatus', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(13, 747564586513409332), + name: 'maritalStatus', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(14, 5573484003127214285), + name: 'specialSkills', + type: 30, + flags: 0), + ModelProperty( + id: const IdUid(18, 2506597441281996495), + name: 'surgeries', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(19, 7773359300531977330), + name: 'anganwadiServicesAware', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(20, 9088237078871159207), + name: 'anganwadiServicesUsing', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(21, 591653671698069367), + name: 'anganwadiServicesUsedList', + type: 30, + flags: 0), + ModelProperty( + id: const IdUid(25, 515443054774028092), + name: 'useOfTobacco', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(26, 8707238561404829402), + name: 'useOfAlcohol', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(27, 3309599826830426346), + name: 'aarogyaSetuInstalled', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(28, 9084202418978987072), + name: 'vizhithiruInstalled', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(29, 7889719359007222937), + name: 'dataValid', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(31, 4870102737459248754), + name: 'dbVulnerabilities', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(33, 5419770240499089417), + name: 'workTimings', + type: 30, + flags: 0), + ModelProperty( + id: const IdUid(34, 339180766123450759), + name: 'noOfDaysWorking', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(35, 239463832765470197), + name: 'PHCServicesUsed', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(36, 6440758785035669475), + name: 'privateClinicServicesUsed', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(37, 3741391841915175758), + name: 'employed', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(38, 2451270514680374685), + name: 'income', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(39, 5436158745852723253), + name: 'incomeType', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(40, 4028603457625037657), + name: 'dbPrivateServiceReason', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(41, 3132879446055335430), + name: 'dbCommunicableDiseases', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(42, 7751946170395515723), + name: 'dbFrequentAilments', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(43, 4854856293984079980), + name: 'dbNonCommunicableDiseases', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(44, 558549105718785352), + name: 'dbTobaccoProducts', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(45, 8806096688498887024), + name: 'dbOccupationData', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(46, 1773687084148916152), + name: 'student', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(47, 9107986757309043468), + name: 'studentEducationCategory', + type: 9, + flags: 0) + ], + relations: [], + backlinks: []), + ModelEntity( + id: const IdUid(3, 4555229639046191310), + name: 'FamilyMembersCommonDataModel', + lastPropertyId: const IdUid(38, 7524624993274240071), + flags: 0, + properties: [ + ModelProperty( + id: const IdUid(1, 8819136016483451605), + name: 'id', + type: 6, + flags: 1), + ModelProperty( + id: const IdUid(2, 3437476224699639583), + name: 'drinkingWater', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(4, 2341047533460923742), + name: 'toiletFacility', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(5, 111976571800950215), + name: 'communityToilet', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(6, 8175958428232054206), + name: 'environmentSanitationLevel', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(7, 7080507576734769781), + name: 'runningWaterAvailable', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(8, 3619777862295069103), + name: 'noOfTwoWheelers', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(9, 2220681223517389029), + name: 'noOfThreeWheelers', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(10, 5295960391830025761), + name: 'noOfFourWheelers', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(11, 3999230000658269584), + name: 'isCattleOwned', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(12, 8174000252850380247), + name: 'incomeFromCattle', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(13, 4187254125313827388), + name: 'isFarmLandOwned', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(14, 4007865345223693029), + name: 'isSeedsPreserved', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(15, 5799753283360608792), + name: 'isKitchenGardenOwned', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(16, 3272250098967751212), + name: 'addressOne', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(17, 5993366458798453696), + name: 'addressTwo', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(18, 8246574557213969028), + name: 'city', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(19, 5398790887074809282), + name: 'locationPageValid', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(20, 6657479069084504293), + name: 'commonDetailsValid', + type: 1, + flags: 0), + ModelProperty( + id: const IdUid(22, 5541702793145940965), + name: 'dbLocationTopLeft', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(23, 4155729105605878928), + name: 'dbLocationTopRight', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(24, 176578608674560191), + name: 'dbLocationBottomLeft', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(25, 3352596760349944439), + name: 'dbLocationBottomRight', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(26, 8858146981830191665), + name: 'dbTwoThreeWheelManufacturer', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(27, 6657331618266238890), + name: 'dbTwoFourManufacturer', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(28, 2360124385132929587), + name: 'dbLocalFoodMap', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(29, 5230846993278344596), + name: 'dbPreservedSeedsMap', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(30, 2725907391283288263), + name: 'dbTreesOwnedMap', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(31, 257396080593114234), + name: 'dbKitchenGardenPlants', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(32, 2980984211940443041), + name: 'dbSourceOfDrinkingWater', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(33, 2417488989427376885), + name: 'villageCode', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(34, 938904163813263655), + name: 'savedTime', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(35, 4854280675953919579), + name: 'dbNoToiletsWhy', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(36, 6442255301640644335), + name: 'dbCropsCultivated', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(37, 8711686748126605615), + name: 'headOfFamily', + type: 9, + flags: 0), + ModelProperty( + id: const IdUid(38, 7524624993274240071), + name: 'recordCollectingUserId', + type: 9, + flags: 0) + ], + relations: [ + ModelRelation( + id: const IdUid(1, 3641078863127427509), + name: 'individualDataList', + targetId: const IdUid(2, 4604626538020621410)) + ], + backlinks: []) +]; + +/// Open an ObjectBox store with the model declared in this file. +Future openStore( + {String? directory, + int? maxDBSizeInKB, + int? fileMode, + int? maxReaders, + bool queriesCaseSensitiveDefault = true, + String? macosApplicationGroup}) async => + Store(getObjectBoxModel(), + directory: directory ?? (await defaultStoreDirectory()).path, + maxDBSizeInKB: maxDBSizeInKB, + fileMode: fileMode, + maxReaders: maxReaders, + queriesCaseSensitiveDefault: queriesCaseSensitiveDefault, + macosApplicationGroup: macosApplicationGroup); + +/// ObjectBox model definition, pass it to [Store] - Store(getObjectBoxModel()) +ModelDefinition getObjectBoxModel() { + final model = ModelInfo( + entities: _entities, + lastEntityId: const IdUid(3, 4555229639046191310), + lastIndexId: const IdUid(0, 0), + lastRelationId: const IdUid(1, 3641078863127427509), + lastSequenceId: const IdUid(0, 0), + retiredEntityUids: const [], + retiredIndexUids: const [], + retiredPropertyUids: const [ + 961043903550204529, + 6821885131227205219, + 3511831625273329956, + 8089710746679848906, + 4567441488943246138, + 1321911158882624161, + 1780571115080959247, + 5383502869453245964, + 2820386840249227222, + 5611188519781040934, + 1258910779661384685, + 1328642062638523745 + ], + retiredRelationUids: const [], + modelVersion: 5, + modelVersionParserMinimum: 5, + version: 1); + + final bindings = { + CommunityDataModel: EntityDefinition( + model: _entities[0], + toOneRelations: (CommunityDataModel object) => [], + toManyRelations: (CommunityDataModel object) => {}, + getId: (CommunityDataModel object) => object.id, + setId: (CommunityDataModel object, int id) { + object.id = id; + }, + objectToFB: (CommunityDataModel object, fb.Builder fbb) { + final resourceTypeOffset = object.resourceType == null + ? null + : fbb.writeString(object.resourceType!); + final villageCodeOffset = object.villageCode == null + ? null + : fbb.writeString(object.villageCode!); + final savedTimeOffset = object.savedTime == null + ? null + : fbb.writeString(object.savedTime!); + final dbLocationTopLeftOffset = object.dbLocationTopLeft == null + ? null + : fbb.writeString(object.dbLocationTopLeft!); + final dbLocationTopRightOffset = object.dbLocationTopRight == null + ? null + : fbb.writeString(object.dbLocationTopRight!); + final dbLocationBottomLeftOffset = object.dbLocationBottomLeft == null + ? null + : fbb.writeString(object.dbLocationBottomLeft!); + final dbLocationBottomRightOffset = + object.dbLocationBottomRight == null + ? null + : fbb.writeString(object.dbLocationBottomRight!); + final recordCollectingUserIdOffset = + object.recordCollectingUserId == null + ? null + : fbb.writeString(object.recordCollectingUserId!); + fbb.startTable(10); + fbb.addInt64(0, object.id); + fbb.addOffset(1, resourceTypeOffset); + fbb.addOffset(2, villageCodeOffset); + fbb.addOffset(3, savedTimeOffset); + fbb.addOffset(4, dbLocationTopLeftOffset); + fbb.addOffset(5, dbLocationTopRightOffset); + fbb.addOffset(6, dbLocationBottomLeftOffset); + fbb.addOffset(7, dbLocationBottomRightOffset); + fbb.addOffset(8, recordCollectingUserIdOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = CommunityDataModel( + resourceType: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 6), + villageCode: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 8)) + ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0) + ..savedTime = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 10) + ..dbLocationTopLeft = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 12) + ..dbLocationTopRight = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 14) + ..dbLocationBottomLeft = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 16) + ..dbLocationBottomRight = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 18) + ..recordCollectingUserId = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 20); + + return object; + }), + FamilyMemberIndividualDataModel: EntityDefinition< + FamilyMemberIndividualDataModel>( + model: _entities[1], + toOneRelations: (FamilyMemberIndividualDataModel object) => [], + toManyRelations: (FamilyMemberIndividualDataModel object) => {}, + getId: (FamilyMemberIndividualDataModel object) => object.id, + setId: (FamilyMemberIndividualDataModel object, int id) { + object.id = id; + }, + objectToFB: (FamilyMemberIndividualDataModel object, fb.Builder fbb) { + final userNameOffset = object.userName == null + ? null + : fbb.writeString(object.userName!); + final genderOffset = + object.gender == null ? null : fbb.writeString(object.gender!); + final phoneNumberOffset = object.phoneNumber == null + ? null + : fbb.writeString(object.phoneNumber!); + final educationQualificationOffset = + object.educationQualification == null + ? null + : fbb.writeString(object.educationQualification!); + final aadhaarNumberOffset = object.aadhaarNumber == null + ? null + : fbb.writeString(object.aadhaarNumber!); + final dailyWageWorkerOffset = object.dailyWageWorker == null + ? null + : fbb.writeString(object.dailyWageWorker!); + final pensionOffset = + object.pension == null ? null : fbb.writeString(object.pension!); + final businessStatusOffset = object.businessStatus == null + ? null + : fbb.writeString(object.businessStatus!); + final maritalStatusOffset = object.maritalStatus == null + ? null + : fbb.writeString(object.maritalStatus!); + final specialSkillsOffset = object.specialSkills == null + ? null + : fbb.writeList(object.specialSkills! + .map(fbb.writeString) + .toList(growable: false)); + final surgeriesOffset = object.surgeries == null + ? null + : fbb.writeString(object.surgeries!); + final anganwadiServicesAwareOffset = + object.anganwadiServicesAware == null + ? null + : fbb.writeString(object.anganwadiServicesAware!); + final anganwadiServicesUsingOffset = + object.anganwadiServicesUsing == null + ? null + : fbb.writeString(object.anganwadiServicesUsing!); + final anganwadiServicesUsedListOffset = + object.anganwadiServicesUsedList == null + ? null + : fbb.writeList(object.anganwadiServicesUsedList! + .map(fbb.writeString) + .toList(growable: false)); + final useOfTobaccoOffset = object.useOfTobacco == null + ? null + : fbb.writeString(object.useOfTobacco!); + final useOfAlcoholOffset = object.useOfAlcohol == null + ? null + : fbb.writeString(object.useOfAlcohol!); + final aarogyaSetuInstalledOffset = object.aarogyaSetuInstalled == null + ? null + : fbb.writeString(object.aarogyaSetuInstalled!); + final vizhithiruInstalledOffset = object.vizhithiruInstalled == null + ? null + : fbb.writeString(object.vizhithiruInstalled!); + final dbVulnerabilitiesOffset = object.dbVulnerabilities == null + ? null + : fbb.writeString(object.dbVulnerabilities!); + final workTimingsOffset = object.workTimings == null + ? null + : fbb.writeList(object.workTimings! + .map(fbb.writeString) + .toList(growable: false)); + final noOfDaysWorkingOffset = object.noOfDaysWorking == null + ? null + : fbb.writeString(object.noOfDaysWorking!); + final PHCServicesUsedOffset = object.PHCServicesUsed == null + ? null + : fbb.writeString(object.PHCServicesUsed!); + final privateClinicServicesUsedOffset = + object.privateClinicServicesUsed == null + ? null + : fbb.writeString(object.privateClinicServicesUsed!); + final employedOffset = object.employed == null + ? null + : fbb.writeString(object.employed!); + final incomeOffset = + object.income == null ? null : fbb.writeString(object.income!); + final incomeTypeOffset = object.incomeType == null + ? null + : fbb.writeString(object.incomeType!); + final dbPrivateServiceReasonOffset = + object.dbPrivateServiceReason == null + ? null + : fbb.writeString(object.dbPrivateServiceReason!); + final dbCommunicableDiseasesOffset = + object.dbCommunicableDiseases == null + ? null + : fbb.writeString(object.dbCommunicableDiseases!); + final dbFrequentAilmentsOffset = object.dbFrequentAilments == null + ? null + : fbb.writeString(object.dbFrequentAilments!); + final dbNonCommunicableDiseasesOffset = + object.dbNonCommunicableDiseases == null + ? null + : fbb.writeString(object.dbNonCommunicableDiseases!); + final dbTobaccoProductsOffset = object.dbTobaccoProducts == null + ? null + : fbb.writeString(object.dbTobaccoProducts!); + final dbOccupationDataOffset = object.dbOccupationData == null + ? null + : fbb.writeString(object.dbOccupationData!); + final studentOffset = + object.student == null ? null : fbb.writeString(object.student!); + final studentEducationCategoryOffset = + object.studentEducationCategory == null + ? null + : fbb.writeString(object.studentEducationCategory!); + fbb.startTable(48); + fbb.addInt64(0, object.id); + fbb.addOffset(1, userNameOffset); + fbb.addInt64(2, object.dateOfBirth?.millisecondsSinceEpoch); + fbb.addOffset(3, genderOffset); + fbb.addOffset(4, phoneNumberOffset); + fbb.addOffset(5, educationQualificationOffset); + fbb.addOffset(6, aadhaarNumberOffset); + fbb.addOffset(7, dailyWageWorkerOffset); + fbb.addOffset(10, pensionOffset); + fbb.addOffset(11, businessStatusOffset); + fbb.addOffset(12, maritalStatusOffset); + fbb.addOffset(13, specialSkillsOffset); + fbb.addOffset(17, surgeriesOffset); + fbb.addOffset(18, anganwadiServicesAwareOffset); + fbb.addOffset(19, anganwadiServicesUsingOffset); + fbb.addOffset(20, anganwadiServicesUsedListOffset); + fbb.addOffset(24, useOfTobaccoOffset); + fbb.addOffset(25, useOfAlcoholOffset); + fbb.addOffset(26, aarogyaSetuInstalledOffset); + fbb.addOffset(27, vizhithiruInstalledOffset); + fbb.addBool(28, object.dataValid); + fbb.addOffset(30, dbVulnerabilitiesOffset); + fbb.addOffset(32, workTimingsOffset); + fbb.addOffset(33, noOfDaysWorkingOffset); + fbb.addOffset(34, PHCServicesUsedOffset); + fbb.addOffset(35, privateClinicServicesUsedOffset); + fbb.addOffset(36, employedOffset); + fbb.addOffset(37, incomeOffset); + fbb.addOffset(38, incomeTypeOffset); + fbb.addOffset(39, dbPrivateServiceReasonOffset); + fbb.addOffset(40, dbCommunicableDiseasesOffset); + fbb.addOffset(41, dbFrequentAilmentsOffset); + fbb.addOffset(42, dbNonCommunicableDiseasesOffset); + fbb.addOffset(43, dbTobaccoProductsOffset); + fbb.addOffset(44, dbOccupationDataOffset); + fbb.addOffset(45, studentOffset); + fbb.addOffset(46, studentEducationCategoryOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + final dateOfBirthValue = + const fb.Int64Reader().vTableGetNullable(buffer, rootOffset, 8); + final object = FamilyMemberIndividualDataModel( + userName: const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 6)) + ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0) + ..dateOfBirth = dateOfBirthValue == null + ? null + : DateTime.fromMillisecondsSinceEpoch(dateOfBirthValue) + ..gender = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 10) + ..phoneNumber = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 12) + ..educationQualification = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 14) + ..aadhaarNumber = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 16) + ..dailyWageWorker = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 18) + ..pension = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 24) + ..businessStatus = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 26) + ..maritalStatus = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 28) + ..specialSkills = + const fb.ListReader(fb.StringReader(), lazy: false) + .vTableGetNullable(buffer, rootOffset, 30) + ..surgeries = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 38) + ..anganwadiServicesAware = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 40) + ..anganwadiServicesUsing = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 42) + ..anganwadiServicesUsedList = + const fb.ListReader(fb.StringReader(), lazy: false) + .vTableGetNullable(buffer, rootOffset, 44) + ..useOfTobacco = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 52) + ..useOfAlcohol = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 54) + ..aarogyaSetuInstalled = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 56) + ..vizhithiruInstalled = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 58) + ..dataValid = + const fb.BoolReader().vTableGetNullable(buffer, rootOffset, 60) + ..dbVulnerabilities = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 64) + ..workTimings = + const fb.ListReader(fb.StringReader(), lazy: false) + .vTableGetNullable(buffer, rootOffset, 68) + ..noOfDaysWorking = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 70) + ..PHCServicesUsed = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 72) + ..privateClinicServicesUsed = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 74) + ..employed = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 76) + ..income = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 78) + ..incomeType = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 80) + ..dbPrivateServiceReason = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 82) + ..dbCommunicableDiseases = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 84) + ..dbFrequentAilments = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 86) + ..dbNonCommunicableDiseases = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 88) + ..dbTobaccoProducts = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 90) + ..dbOccupationData = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 92) + ..student = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 94) + ..studentEducationCategory = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 96); + + return object; + }), + FamilyMembersCommonDataModel: EntityDefinition< + FamilyMembersCommonDataModel>( + model: _entities[2], + toOneRelations: (FamilyMembersCommonDataModel object) => [], + toManyRelations: (FamilyMembersCommonDataModel object) => { + RelInfo.toMany(1, object.id): + object.individualDataList + }, + getId: (FamilyMembersCommonDataModel object) => object.id, + setId: (FamilyMembersCommonDataModel object, int id) { + object.id = id; + }, + objectToFB: (FamilyMembersCommonDataModel object, fb.Builder fbb) { + final drinkingWaterOffset = object.drinkingWater == null + ? null + : fbb.writeString(object.drinkingWater!); + final toiletFacilityOffset = object.toiletFacility == null + ? null + : fbb.writeString(object.toiletFacility!); + final communityToiletOffset = object.communityToilet == null + ? null + : fbb.writeString(object.communityToilet!); + final environmentSanitationLevelOffset = + object.environmentSanitationLevel == null + ? null + : fbb.writeString(object.environmentSanitationLevel!); + final runningWaterAvailableOffset = + object.runningWaterAvailable == null + ? null + : fbb.writeString(object.runningWaterAvailable!); + final noOfTwoWheelersOffset = object.noOfTwoWheelers == null + ? null + : fbb.writeString(object.noOfTwoWheelers!); + final noOfThreeWheelersOffset = object.noOfThreeWheelers == null + ? null + : fbb.writeString(object.noOfThreeWheelers!); + final noOfFourWheelersOffset = object.noOfFourWheelers == null + ? null + : fbb.writeString(object.noOfFourWheelers!); + final isCattleOwnedOffset = object.isCattleOwned == null + ? null + : fbb.writeString(object.isCattleOwned!); + final incomeFromCattleOffset = object.incomeFromCattle == null + ? null + : fbb.writeString(object.incomeFromCattle!); + final isFarmLandOwnedOffset = object.isFarmLandOwned == null + ? null + : fbb.writeString(object.isFarmLandOwned!); + final isSeedsPreservedOffset = object.isSeedsPreserved == null + ? null + : fbb.writeString(object.isSeedsPreserved!); + final isKitchenGardenOwnedOffset = object.isKitchenGardenOwned == null + ? null + : fbb.writeString(object.isKitchenGardenOwned!); + final addressOneOffset = object.addressOne == null + ? null + : fbb.writeString(object.addressOne!); + final addressTwoOffset = object.addressTwo == null + ? null + : fbb.writeString(object.addressTwo!); + final cityOffset = + object.city == null ? null : fbb.writeString(object.city!); + final dbLocationTopLeftOffset = object.dbLocationTopLeft == null + ? null + : fbb.writeString(object.dbLocationTopLeft!); + final dbLocationTopRightOffset = object.dbLocationTopRight == null + ? null + : fbb.writeString(object.dbLocationTopRight!); + final dbLocationBottomLeftOffset = object.dbLocationBottomLeft == null + ? null + : fbb.writeString(object.dbLocationBottomLeft!); + final dbLocationBottomRightOffset = + object.dbLocationBottomRight == null + ? null + : fbb.writeString(object.dbLocationBottomRight!); + final dbTwoThreeWheelManufacturerOffset = + object.dbTwoThreeWheelManufacturer == null + ? null + : fbb.writeString(object.dbTwoThreeWheelManufacturer!); + final dbTwoFourManufacturerOffset = + object.dbTwoFourManufacturer == null + ? null + : fbb.writeString(object.dbTwoFourManufacturer!); + final dbLocalFoodMapOffset = object.dbLocalFoodMap == null + ? null + : fbb.writeString(object.dbLocalFoodMap!); + final dbPreservedSeedsMapOffset = object.dbPreservedSeedsMap == null + ? null + : fbb.writeString(object.dbPreservedSeedsMap!); + final dbTreesOwnedMapOffset = object.dbTreesOwnedMap == null + ? null + : fbb.writeString(object.dbTreesOwnedMap!); + final dbKitchenGardenPlantsOffset = + object.dbKitchenGardenPlants == null + ? null + : fbb.writeString(object.dbKitchenGardenPlants!); + final dbSourceOfDrinkingWaterOffset = + object.dbSourceOfDrinkingWater == null + ? null + : fbb.writeString(object.dbSourceOfDrinkingWater!); + final villageCodeOffset = object.villageCode == null + ? null + : fbb.writeString(object.villageCode!); + final savedTimeOffset = object.savedTime == null + ? null + : fbb.writeString(object.savedTime!); + final dbNoToiletsWhyOffset = object.dbNoToiletsWhy == null + ? null + : fbb.writeString(object.dbNoToiletsWhy!); + final dbCropsCultivatedOffset = object.dbCropsCultivated == null + ? null + : fbb.writeString(object.dbCropsCultivated!); + final headOfFamilyOffset = object.headOfFamily == null + ? null + : fbb.writeString(object.headOfFamily!); + final recordCollectingUserIdOffset = + object.recordCollectingUserId == null + ? null + : fbb.writeString(object.recordCollectingUserId!); + fbb.startTable(39); + fbb.addInt64(0, object.id); + fbb.addOffset(1, drinkingWaterOffset); + fbb.addOffset(3, toiletFacilityOffset); + fbb.addOffset(4, communityToiletOffset); + fbb.addOffset(5, environmentSanitationLevelOffset); + fbb.addOffset(6, runningWaterAvailableOffset); + fbb.addOffset(7, noOfTwoWheelersOffset); + fbb.addOffset(8, noOfThreeWheelersOffset); + fbb.addOffset(9, noOfFourWheelersOffset); + fbb.addOffset(10, isCattleOwnedOffset); + fbb.addOffset(11, incomeFromCattleOffset); + fbb.addOffset(12, isFarmLandOwnedOffset); + fbb.addOffset(13, isSeedsPreservedOffset); + fbb.addOffset(14, isKitchenGardenOwnedOffset); + fbb.addOffset(15, addressOneOffset); + fbb.addOffset(16, addressTwoOffset); + fbb.addOffset(17, cityOffset); + fbb.addBool(18, object.locationPageValid); + fbb.addBool(19, object.commonDetailsValid); + fbb.addOffset(21, dbLocationTopLeftOffset); + fbb.addOffset(22, dbLocationTopRightOffset); + fbb.addOffset(23, dbLocationBottomLeftOffset); + fbb.addOffset(24, dbLocationBottomRightOffset); + fbb.addOffset(25, dbTwoThreeWheelManufacturerOffset); + fbb.addOffset(26, dbTwoFourManufacturerOffset); + fbb.addOffset(27, dbLocalFoodMapOffset); + fbb.addOffset(28, dbPreservedSeedsMapOffset); + fbb.addOffset(29, dbTreesOwnedMapOffset); + fbb.addOffset(30, dbKitchenGardenPlantsOffset); + fbb.addOffset(31, dbSourceOfDrinkingWaterOffset); + fbb.addOffset(32, villageCodeOffset); + fbb.addOffset(33, savedTimeOffset); + fbb.addOffset(34, dbNoToiletsWhyOffset); + fbb.addOffset(35, dbCropsCultivatedOffset); + fbb.addOffset(36, headOfFamilyOffset); + fbb.addOffset(37, recordCollectingUserIdOffset); + fbb.finish(fbb.endTable()); + return object.id; + }, + objectFromFB: (Store store, ByteData fbData) { + final buffer = fb.BufferContext(fbData); + final rootOffset = buffer.derefObject(0); + + final object = FamilyMembersCommonDataModel() + ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0) + ..drinkingWater = + const fb.StringReader().vTableGetNullable(buffer, rootOffset, 6) + ..toiletFacility = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 10) + ..communityToilet = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 12) + ..environmentSanitationLevel = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 14) + ..runningWaterAvailable = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 16) + ..noOfTwoWheelers = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 18) + ..noOfThreeWheelers = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 20) + ..noOfFourWheelers = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 22) + ..isCattleOwned = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 24) + ..incomeFromCattle = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 26) + ..isFarmLandOwned = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 28) + ..isSeedsPreserved = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 30) + ..isKitchenGardenOwned = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 32) + ..addressOne = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 34) + ..addressTwo = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 36) + ..city = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 38) + ..locationPageValid = + const fb.BoolReader().vTableGetNullable(buffer, rootOffset, 40) + ..commonDetailsValid = + const fb.BoolReader().vTableGetNullable(buffer, rootOffset, 42) + ..dbLocationTopLeft = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 46) + ..dbLocationTopRight = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 48) + ..dbLocationBottomLeft = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 50) + ..dbLocationBottomRight = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 52) + ..dbTwoThreeWheelManufacturer = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 54) + ..dbTwoFourManufacturer = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 56) + ..dbLocalFoodMap = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 58) + ..dbPreservedSeedsMap = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 60) + ..dbTreesOwnedMap = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 62) + ..dbKitchenGardenPlants = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 64) + ..dbSourceOfDrinkingWater = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 66) + ..villageCode = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 68) + ..savedTime = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 70) + ..dbNoToiletsWhy = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 72) + ..dbCropsCultivated = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 74) + ..headOfFamily = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 76) + ..recordCollectingUserId = const fb.StringReader() + .vTableGetNullable(buffer, rootOffset, 78); + InternalToManyAccess.setRelInfo( + object.individualDataList, + store, + RelInfo.toMany(1, object.id), + store.box()); + return object; + }) + }; + + return ModelDefinition(model, bindings); +} + +/// [CommunityDataModel] entity fields to define ObjectBox queries. +class CommunityDataModel_ { + /// see [CommunityDataModel.id] + static final id = + QueryIntegerProperty(_entities[0].properties[0]); + + /// see [CommunityDataModel.resourceType] + static final resourceType = + QueryStringProperty(_entities[0].properties[1]); + + /// see [CommunityDataModel.villageCode] + static final villageCode = + QueryStringProperty(_entities[0].properties[2]); + + /// see [CommunityDataModel.savedTime] + static final savedTime = + QueryStringProperty(_entities[0].properties[3]); + + /// see [CommunityDataModel.dbLocationTopLeft] + static final dbLocationTopLeft = + QueryStringProperty(_entities[0].properties[4]); + + /// see [CommunityDataModel.dbLocationTopRight] + static final dbLocationTopRight = + QueryStringProperty(_entities[0].properties[5]); + + /// see [CommunityDataModel.dbLocationBottomLeft] + static final dbLocationBottomLeft = + QueryStringProperty(_entities[0].properties[6]); + + /// see [CommunityDataModel.dbLocationBottomRight] + static final dbLocationBottomRight = + QueryStringProperty(_entities[0].properties[7]); + + /// see [CommunityDataModel.recordCollectingUserId] + static final recordCollectingUserId = + QueryStringProperty(_entities[0].properties[8]); +} + +/// [FamilyMemberIndividualDataModel] entity fields to define ObjectBox queries. +class FamilyMemberIndividualDataModel_ { + /// see [FamilyMemberIndividualDataModel.id] + static final id = QueryIntegerProperty( + _entities[1].properties[0]); + + /// see [FamilyMemberIndividualDataModel.userName] + static final userName = QueryStringProperty( + _entities[1].properties[1]); + + /// see [FamilyMemberIndividualDataModel.dateOfBirth] + static final dateOfBirth = + QueryIntegerProperty( + _entities[1].properties[2]); + + /// see [FamilyMemberIndividualDataModel.gender] + static final gender = QueryStringProperty( + _entities[1].properties[3]); + + /// see [FamilyMemberIndividualDataModel.phoneNumber] + static final phoneNumber = + QueryStringProperty( + _entities[1].properties[4]); + + /// see [FamilyMemberIndividualDataModel.educationQualification] + static final educationQualification = + QueryStringProperty( + _entities[1].properties[5]); + + /// see [FamilyMemberIndividualDataModel.aadhaarNumber] + static final aadhaarNumber = + QueryStringProperty( + _entities[1].properties[6]); + + /// see [FamilyMemberIndividualDataModel.dailyWageWorker] + static final dailyWageWorker = + QueryStringProperty( + _entities[1].properties[7]); + + /// see [FamilyMemberIndividualDataModel.pension] + static final pension = QueryStringProperty( + _entities[1].properties[8]); + + /// see [FamilyMemberIndividualDataModel.businessStatus] + static final businessStatus = + QueryStringProperty( + _entities[1].properties[9]); + + /// see [FamilyMemberIndividualDataModel.maritalStatus] + static final maritalStatus = + QueryStringProperty( + _entities[1].properties[10]); + + /// see [FamilyMemberIndividualDataModel.specialSkills] + static final specialSkills = + QueryStringVectorProperty( + _entities[1].properties[11]); + + /// see [FamilyMemberIndividualDataModel.surgeries] + static final surgeries = QueryStringProperty( + _entities[1].properties[12]); + + /// see [FamilyMemberIndividualDataModel.anganwadiServicesAware] + static final anganwadiServicesAware = + QueryStringProperty( + _entities[1].properties[13]); + + /// see [FamilyMemberIndividualDataModel.anganwadiServicesUsing] + static final anganwadiServicesUsing = + QueryStringProperty( + _entities[1].properties[14]); + + /// see [FamilyMemberIndividualDataModel.anganwadiServicesUsedList] + static final anganwadiServicesUsedList = + QueryStringVectorProperty( + _entities[1].properties[15]); + + /// see [FamilyMemberIndividualDataModel.useOfTobacco] + static final useOfTobacco = + QueryStringProperty( + _entities[1].properties[16]); + + /// see [FamilyMemberIndividualDataModel.useOfAlcohol] + static final useOfAlcohol = + QueryStringProperty( + _entities[1].properties[17]); + + /// see [FamilyMemberIndividualDataModel.aarogyaSetuInstalled] + static final aarogyaSetuInstalled = + QueryStringProperty( + _entities[1].properties[18]); + + /// see [FamilyMemberIndividualDataModel.vizhithiruInstalled] + static final vizhithiruInstalled = + QueryStringProperty( + _entities[1].properties[19]); + + /// see [FamilyMemberIndividualDataModel.dataValid] + static final dataValid = + QueryBooleanProperty( + _entities[1].properties[20]); + + /// see [FamilyMemberIndividualDataModel.dbVulnerabilities] + static final dbVulnerabilities = + QueryStringProperty( + _entities[1].properties[21]); + + /// see [FamilyMemberIndividualDataModel.workTimings] + static final workTimings = + QueryStringVectorProperty( + _entities[1].properties[22]); + + /// see [FamilyMemberIndividualDataModel.noOfDaysWorking] + static final noOfDaysWorking = + QueryStringProperty( + _entities[1].properties[23]); + + /// see [FamilyMemberIndividualDataModel.PHCServicesUsed] + static final PHCServicesUsed = + QueryStringProperty( + _entities[1].properties[24]); + + /// see [FamilyMemberIndividualDataModel.privateClinicServicesUsed] + static final privateClinicServicesUsed = + QueryStringProperty( + _entities[1].properties[25]); + + /// see [FamilyMemberIndividualDataModel.employed] + static final employed = QueryStringProperty( + _entities[1].properties[26]); + + /// see [FamilyMemberIndividualDataModel.income] + static final income = QueryStringProperty( + _entities[1].properties[27]); + + /// see [FamilyMemberIndividualDataModel.incomeType] + static final incomeType = + QueryStringProperty( + _entities[1].properties[28]); + + /// see [FamilyMemberIndividualDataModel.dbPrivateServiceReason] + static final dbPrivateServiceReason = + QueryStringProperty( + _entities[1].properties[29]); + + /// see [FamilyMemberIndividualDataModel.dbCommunicableDiseases] + static final dbCommunicableDiseases = + QueryStringProperty( + _entities[1].properties[30]); + + /// see [FamilyMemberIndividualDataModel.dbFrequentAilments] + static final dbFrequentAilments = + QueryStringProperty( + _entities[1].properties[31]); + + /// see [FamilyMemberIndividualDataModel.dbNonCommunicableDiseases] + static final dbNonCommunicableDiseases = + QueryStringProperty( + _entities[1].properties[32]); + + /// see [FamilyMemberIndividualDataModel.dbTobaccoProducts] + static final dbTobaccoProducts = + QueryStringProperty( + _entities[1].properties[33]); + + /// see [FamilyMemberIndividualDataModel.dbOccupationData] + static final dbOccupationData = + QueryStringProperty( + _entities[1].properties[34]); + + /// see [FamilyMemberIndividualDataModel.student] + static final student = QueryStringProperty( + _entities[1].properties[35]); + + /// see [FamilyMemberIndividualDataModel.studentEducationCategory] + static final studentEducationCategory = + QueryStringProperty( + _entities[1].properties[36]); +} + +/// [FamilyMembersCommonDataModel] entity fields to define ObjectBox queries. +class FamilyMembersCommonDataModel_ { + /// see [FamilyMembersCommonDataModel.id] + static final id = QueryIntegerProperty( + _entities[2].properties[0]); + + /// see [FamilyMembersCommonDataModel.drinkingWater] + static final drinkingWater = + QueryStringProperty( + _entities[2].properties[1]); + + /// see [FamilyMembersCommonDataModel.toiletFacility] + static final toiletFacility = + QueryStringProperty( + _entities[2].properties[2]); + + /// see [FamilyMembersCommonDataModel.communityToilet] + static final communityToilet = + QueryStringProperty( + _entities[2].properties[3]); + + /// see [FamilyMembersCommonDataModel.environmentSanitationLevel] + static final environmentSanitationLevel = + QueryStringProperty( + _entities[2].properties[4]); + + /// see [FamilyMembersCommonDataModel.runningWaterAvailable] + static final runningWaterAvailable = + QueryStringProperty( + _entities[2].properties[5]); + + /// see [FamilyMembersCommonDataModel.noOfTwoWheelers] + static final noOfTwoWheelers = + QueryStringProperty( + _entities[2].properties[6]); + + /// see [FamilyMembersCommonDataModel.noOfThreeWheelers] + static final noOfThreeWheelers = + QueryStringProperty( + _entities[2].properties[7]); + + /// see [FamilyMembersCommonDataModel.noOfFourWheelers] + static final noOfFourWheelers = + QueryStringProperty( + _entities[2].properties[8]); + + /// see [FamilyMembersCommonDataModel.isCattleOwned] + static final isCattleOwned = + QueryStringProperty( + _entities[2].properties[9]); + + /// see [FamilyMembersCommonDataModel.incomeFromCattle] + static final incomeFromCattle = + QueryStringProperty( + _entities[2].properties[10]); + + /// see [FamilyMembersCommonDataModel.isFarmLandOwned] + static final isFarmLandOwned = + QueryStringProperty( + _entities[2].properties[11]); + + /// see [FamilyMembersCommonDataModel.isSeedsPreserved] + static final isSeedsPreserved = + QueryStringProperty( + _entities[2].properties[12]); + + /// see [FamilyMembersCommonDataModel.isKitchenGardenOwned] + static final isKitchenGardenOwned = + QueryStringProperty( + _entities[2].properties[13]); + + /// see [FamilyMembersCommonDataModel.addressOne] + static final addressOne = QueryStringProperty( + _entities[2].properties[14]); + + /// see [FamilyMembersCommonDataModel.addressTwo] + static final addressTwo = QueryStringProperty( + _entities[2].properties[15]); + + /// see [FamilyMembersCommonDataModel.city] + static final city = QueryStringProperty( + _entities[2].properties[16]); + + /// see [FamilyMembersCommonDataModel.locationPageValid] + static final locationPageValid = + QueryBooleanProperty( + _entities[2].properties[17]); + + /// see [FamilyMembersCommonDataModel.commonDetailsValid] + static final commonDetailsValid = + QueryBooleanProperty( + _entities[2].properties[18]); + + /// see [FamilyMembersCommonDataModel.dbLocationTopLeft] + static final dbLocationTopLeft = + QueryStringProperty( + _entities[2].properties[19]); + + /// see [FamilyMembersCommonDataModel.dbLocationTopRight] + static final dbLocationTopRight = + QueryStringProperty( + _entities[2].properties[20]); + + /// see [FamilyMembersCommonDataModel.dbLocationBottomLeft] + static final dbLocationBottomLeft = + QueryStringProperty( + _entities[2].properties[21]); + + /// see [FamilyMembersCommonDataModel.dbLocationBottomRight] + static final dbLocationBottomRight = + QueryStringProperty( + _entities[2].properties[22]); + + /// see [FamilyMembersCommonDataModel.dbTwoThreeWheelManufacturer] + static final dbTwoThreeWheelManufacturer = + QueryStringProperty( + _entities[2].properties[23]); + + /// see [FamilyMembersCommonDataModel.dbTwoFourManufacturer] + static final dbTwoFourManufacturer = + QueryStringProperty( + _entities[2].properties[24]); + + /// see [FamilyMembersCommonDataModel.dbLocalFoodMap] + static final dbLocalFoodMap = + QueryStringProperty( + _entities[2].properties[25]); + + /// see [FamilyMembersCommonDataModel.dbPreservedSeedsMap] + static final dbPreservedSeedsMap = + QueryStringProperty( + _entities[2].properties[26]); + + /// see [FamilyMembersCommonDataModel.dbTreesOwnedMap] + static final dbTreesOwnedMap = + QueryStringProperty( + _entities[2].properties[27]); + + /// see [FamilyMembersCommonDataModel.dbKitchenGardenPlants] + static final dbKitchenGardenPlants = + QueryStringProperty( + _entities[2].properties[28]); + + /// see [FamilyMembersCommonDataModel.dbSourceOfDrinkingWater] + static final dbSourceOfDrinkingWater = + QueryStringProperty( + _entities[2].properties[29]); + + /// see [FamilyMembersCommonDataModel.villageCode] + static final villageCode = QueryStringProperty( + _entities[2].properties[30]); + + /// see [FamilyMembersCommonDataModel.savedTime] + static final savedTime = QueryStringProperty( + _entities[2].properties[31]); + + /// see [FamilyMembersCommonDataModel.dbNoToiletsWhy] + static final dbNoToiletsWhy = + QueryStringProperty( + _entities[2].properties[32]); + + /// see [FamilyMembersCommonDataModel.dbCropsCultivated] + static final dbCropsCultivated = + QueryStringProperty( + _entities[2].properties[33]); + + /// see [FamilyMembersCommonDataModel.headOfFamily] + static final headOfFamily = QueryStringProperty( + _entities[2].properties[34]); + + /// see [FamilyMembersCommonDataModel.recordCollectingUserId] + static final recordCollectingUserId = + QueryStringProperty( + _entities[2].properties[35]); + + /// see [FamilyMembersCommonDataModel.individualDataList] + static final individualDataList = QueryRelationToMany< + FamilyMembersCommonDataModel, + FamilyMemberIndividualDataModel>(_entities[2].relations[0]); +} diff --git a/pubspec.lock b/pubspec.lock index cfccc93..a759543 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,13 +1,62 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + url: "https://pub.dartlang.org" + source: hosted + version: "31.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + url: "https://pub.dartlang.org" + source: hosted + version: "2.8.0" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.1" + asn1lib: + dependency: transitive + description: + name: asn1lib + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.1" + version: "2.8.2" + auto_size_text: + dependency: "direct main" + description: + name: auto_size_text + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" + automated_testing_framework: + dependency: transitive + description: + name: automated_testing_framework + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.2" + automated_testing_framework_models: + dependency: transitive + description: + name: automated_testing_framework_models + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.9+5" boolean_selector: dependency: transitive description: @@ -15,13 +64,69 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.7" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.3" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.4" characters: dependency: transitive description: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: @@ -29,6 +134,27 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + child_builder: + dependency: transitive + description: + name: child_builder + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0+3" + cli_util: + dependency: transitive + description: + name: cli_util + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.5" clock: dependency: transitive description: @@ -36,34 +162,153 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" collection: dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" + connectivity_plus: + dependency: "direct main" + description: + name: connectivity_plus + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0" + connectivity_plus_linux: + dependency: transitive + description: + name: connectivity_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + connectivity_plus_macos: + dependency: transitive + description: + name: connectivity_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + connectivity_plus_platform_interface: + dependency: transitive + description: + name: connectivity_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + connectivity_plus_web: + dependency: transitive + description: + name: connectivity_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + connectivity_plus_windows: + dependency: transitive + description: + name: connectivity_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.4" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" + dbus: + dependency: transitive + description: + name: dbus + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.8" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0" + device_info_plus_linux: + dependency: transitive + description: + name: device_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + device_info_plus_macos: + dependency: transitive + description: + name: device_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.3" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.3.0+1" + device_info_plus_web: + dependency: transitive + description: + name: device_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + device_info_plus_windows: + dependency: transitive + description: + name: device_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + encrypt: + dependency: transitive + description: + name: encrypt + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.1" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" ffi: dependency: transitive description: @@ -78,36 +323,195 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_keyboard_visibility: + dependency: transitive + description: + name: flutter_keyboard_visibility + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + flutter_keyboard_visibility_platform_interface: + dependency: transitive + description: + name: flutter_keyboard_visibility_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + flutter_keyboard_visibility_web: + dependency: transitive + description: + name: flutter_keyboard_visibility_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" + flutter_markdown: + dependency: transitive + description: + name: flutter_markdown + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.10+3" + flutter_rounded_date_picker: + dependency: "direct main" + description: + name: flutter_rounded_date_picker + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" flutter_secure_storage: dependency: "direct main" description: name: flutter_secure_storage url: "https://pub.dartlang.org" source: hosted - version: "4.2.1" + version: "5.0.2" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.2" flutter_svg: dependency: "direct main" description: name: flutter_svg url: "https://pub.dartlang.org" source: hosted - version: "0.23.0" + version: "1.0.3" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_typeahead: + dependency: "direct main" + description: + name: flutter_typeahead + url: "https://pub.dartlang.org" + source: hosted + version: "3.2.4" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + form_validation: + dependency: transitive + description: + name: form_validation + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0+10" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" + gender_picker: + dependency: "direct main" + description: + name: gender_picker + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + url: "https://pub.dartlang.org" + source: hosted + version: "8.0.4" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.1" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4" + glob: + dependency: transitive + description: + name: glob + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" google_fonts: dependency: "direct main" description: name: google_fonts url: "https://pub.dartlang.org" source: hosted + version: "2.2.0" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted version: "2.1.0" http: dependency: "direct main" @@ -116,6 +520,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.13.4" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" http_parser: dependency: transitive description: @@ -123,6 +534,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.0.0" + interpolation: + dependency: transitive + description: + name: interpolation + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" intl: dependency: transitive description: @@ -130,13 +548,97 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.17.0" + io: + dependency: transitive + description: + name: io + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.3" + js: + dependency: transitive + description: + name: js + url: "https://pub.dartlang.org" + source: hosted + version: "0.6.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.0" + json_class: + dependency: transitive + description: + name: json_class + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2+8" + json_conditional: + dependency: transitive + description: + name: json_conditional + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0+9" + json_dynamic_widget: + dependency: "direct main" + description: + name: json_dynamic_widget + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.2+5" + json_path: + dependency: transitive + description: + name: json_path + url: "https://pub.dartlang.org" + source: hosted + version: "0.3.1" + json_schema2: + dependency: transitive + description: + name: json_schema2 + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2+7" + json_theme: + dependency: transitive + description: + name: json_theme + url: "https://pub.dartlang.org" + source: hosted + version: "4.0.0+7" + logging: + dependency: transitive + description: + name: logging + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + markdown: + dependency: transitive + description: + name: markdown + url: "https://pub.dartlang.org" + source: hosted + version: "5.0.0" matcher: dependency: transitive description: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10" + version: "0.12.11" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.4" meta: dependency: transitive description: @@ -144,62 +646,174 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.7.0" + mime: + dependency: transitive + description: + name: mime + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + nested: + dependency: transitive + description: + name: nested + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + nm: + dependency: transitive + description: + name: nm + url: "https://pub.dartlang.org" + source: hosted + version: "0.4.2" + objectbox: + dependency: "direct main" + description: + name: objectbox + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + objectbox_flutter_libs: + dependency: "direct main" + description: + name: objectbox_flutter_libs + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + objectbox_generator: + dependency: "direct dev" + description: + name: objectbox_generator + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + oktoast: + dependency: "direct main" + description: + name: oktoast + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.5" + package_config: + dependency: transitive + description: + name: package_config + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.2" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + url: "https://pub.dartlang.org" + source: hosted + version: "1.4.2" + package_info_plus_linux: + dependency: transitive + description: + name: package_info_plus_linux + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" + package_info_plus_macos: + dependency: transitive + description: + name: package_info_plus_macos + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2" + package_info_plus_web: + dependency: transitive + description: + name: package_info_plus_web + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" + package_info_plus_windows: + dependency: transitive + description: + name: package_info_plus_windows + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" path_drawing: dependency: transitive description: name: path_drawing url: "https://pub.dartlang.org" source: hosted - version: "0.5.1+1" + version: "1.0.0" path_parsing: dependency: transitive description: name: path_parsing url: "https://pub.dartlang.org" source: hosted - version: "0.2.1" + version: "1.0.0" path_provider: dependency: transitive description: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.8" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.11" + path_provider_ios: + dependency: transitive + description: + name: path_provider_ios + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.7" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.5" path_provider_macos: dependency: transitive description: name: path_provider_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.5" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.3" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.5" petitparser: dependency: transitive description: @@ -213,21 +827,105 @@ packages: name: platform url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.2" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.dartlang.org" + source: hosted + version: "3.6.1" + pool: + dependency: transitive + description: + name: pool + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.0" + preload_page_view: + dependency: "direct main" + description: + name: preload_page_view + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.6" process: dependency: transitive description: name: process url: "https://pub.dartlang.org" source: hosted - version: "4.2.3" + version: "4.2.4" + provider: + dependency: transitive + description: + name: provider + url: "https://pub.dartlang.org" + source: hosted + version: "6.0.3" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.0" + rest_client: + dependency: transitive + description: + name: rest_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4+7" + rfc_6901: + dependency: transitive + description: + name: rfc_6901 + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.1" + rxdart: + dependency: transitive + description: + name: rxdart + url: "https://pub.dartlang.org" + source: hosted + version: "0.27.5" + shelf: + dependency: transitive + description: + name: shelf + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" simple_gesture_detector: dependency: transitive description: @@ -240,13 +938,20 @@ packages: description: flutter source: sdk version: "0.0.99" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" source_span: dependency: transitive description: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -254,6 +959,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.10.0" + static_translations: + dependency: transitive + description: + name: static_translations + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1+7" stream_channel: dependency: transitive description: @@ -261,6 +973,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" string_scanner: dependency: transitive description: @@ -274,7 +993,14 @@ packages: name: table_calendar url: "https://pub.dartlang.org" source: hosted - version: "3.0.2" + version: "3.0.3" + template_expressions: + dependency: transitive + description: + name: template_expressions + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.7+4" term_glyph: dependency: transitive description: @@ -288,7 +1014,14 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.4.9" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: @@ -296,12 +1029,47 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" + uri: + dependency: transitive + description: + name: uri + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.6" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted + version: "2.1.2" + visibility_detector: + dependency: "direct main" + description: + name: visibility_detector + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.2" + watcher: + dependency: transitive + description: + name: watcher + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + url: "https://pub.dartlang.org" + source: hosted version: "2.1.0" win32: dependency: transitive @@ -309,7 +1077,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.2.9" + version: "2.3.8" xdg_directories: dependency: transitive description: @@ -324,6 +1092,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.3.1" + yaml: + dependency: transitive + description: + name: yaml + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.1" + yaon: + dependency: transitive + description: + name: yaon + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.1+3" sdks: - dart: ">=2.14.0 <3.0.0" - flutter: ">=2.5.0" + dart: ">=2.17.0 <3.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index f94a7b4..36b628c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,15 +15,25 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+1 +version: 1.0.2+1 environment: sdk: ">=2.12.0 <3.0.0" dependencies: - flutter_svg: 0.23.0 + connectivity_plus: ^2.0.2 + visibility_detector: ^0.2.2 + oktoast: ^3.1.5 + preload_page_view: ^0.1.6 + flutter_typeahead: ^3.2.4 + objectbox: ^1.3.0 + objectbox_flutter_libs: any + flutter_svg: ^1.0.3 + geolocator: ^8.0.4 + auto_size_text: ^3.0.0 http: 0.13.4 - flutter_secure_storage: ^4.2.1 + flutter_secure_storage: ^5.0.2 + json_dynamic_widget: ^5.0.2+5 flutter: sdk: flutter @@ -32,9 +42,13 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 google_fonts: - table_calendar: + table_calendar: + gender_picker: ^1.1.0 + flutter_rounded_date_picker: #TODO: Verify and remove5 dev_dependencies: + build_runner: ^2.0.0 + objectbox_generator: any flutter_test: sdk: flutter diff --git a/test/widget_test.dart b/test/widget_test.dart index b2262ff..591231f 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -7,13 +7,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:geo_spatial/Screens/Login.dart'; import 'package:geo_spatial/main.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); + await tester.pumpWidget((Login())); // Verify that our counter starts at 0. expect(find.text('0'), findsOneWidget);