diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 17d9de068a3b7d3697a0c051fbdabf4cd5fe2b9d..c4134b3a46b80cc2c7458c02701980ff479f42e1 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"path_provider","dependencies":[]}]} \ No newline at end of file +{"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"google_maps_flutter","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"image_picker","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"location","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"share","dependencies":[]},{"name":"shared_preferences","dependencies":["shared_preferences_macos","shared_preferences_web"]},{"name":"shared_preferences_macos","dependencies":[]},{"name":"shared_preferences_web","dependencies":[]},{"name":"sqflite","dependencies":[]}]} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5864c705ed88d200dd8a7719d5baf08f32d33826..a1b47e53bf30b0552bf6204186dc275a0899c63b 100644 --- a/.gitignore +++ b/.gitignore @@ -287,3 +287,7 @@ modules.xml .venv/ # End of https://www.gitignore.io/api/linux,django,python,pycharm+all + +tests.output + +.flutter-plugins-dependencies diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4cfb91bf51135db32fff7416340c2118cf1f6e5a..fbd6615a2ec21b9bd6fb852fee1d523ee96c427d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,26 +1,46 @@ stages: + - lint - test + - sonarqube - deploy - - show variables: APP_NAME: "bisaGo" +before_script: + - export PATH=$PATH:/sdk/android-sdk-linux/platform-tools/ + - echo flutter.sdk=/sdk/flutter > android/local.properties + - flutter pub get + +image: michael09/flutter:28-1.12.13_hotfix.9 + +Lint: + stage: lint + script: + - flutter analyze + Test: stage: test - image: jro7/flutter_lcov script: - - echo Testing $APP_NAME - - flutter doctor -v - flutter test --coverage + - flutter test --machine > tests.output - lcov --summary coverage/lcov.info - genhtml coverage/lcov.info --output=coverage - coverage: '/lines......: \d+\.\d+\%/' artifacts: - name: mobile-coverage + expire_in: 1 hour paths: - - $CI_PROJECT_DIR/coverage + - coverage/lcov.info + - tests.output +Sonarqube: + dependencies: + - Test + stage: sonarqube + before_script: + - export PATH=$PATH:/sdk/flutter/bin/cache/dart-sdk/bin + - flutter pub get + script: + - sonar-scanner -Dsonar.login=$SONARQUBE_TOKEN -Dsonar.branch.name=$CI_COMMIT_REF_NAME -Dsonar.projectKey=$SONARQUBE_PROJECT_KEY -X DeployToProduction: @@ -61,7 +81,7 @@ DeployToStaging: refs: - staging before_script: - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.7-stable.tar.xz && tar xf flutter.tar.xz -C / + - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.8-stable.tar.xz && tar xf flutter.tar.xz -C / - export PATH=$PATH:/flutter/bin - apt-get update && apt-get install gnupg -y - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs @@ -87,7 +107,7 @@ DeployToDevelopment: refs: - /^US-.*$/ before_script: - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.7-stable.tar.xz && tar xf flutter.tar.xz -C / + - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.8-stable.tar.xz && tar xf flutter.tar.xz -C / - export PATH=$PATH:/flutter/bin - apt-get update && apt-get install gnupg -y - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs @@ -100,18 +120,4 @@ DeployToDevelopment: - appcenter login --token=$APPCENTER_API_TOKEN - appcenter distribute release -f build/app/outputs/apk/release/app-release.apk --app $APPCENTER_APP_NAME_DEV --group $APPCENTER_GROUP_TARGET environment: - name: development - - - -ShowCoverage: - image: alpine - stage: show - dependencies: - - Test - script: - - mkdir -p mobile-coverage/ - - mv coverage/* mobile-coverage/ - artifacts: - paths: - - $CI_PROJECT_DIR/mobile-coverage/ \ No newline at end of file + name: development \ No newline at end of file diff --git a/README.md b/README.md index fffd55cee840908d0f2468a8de31c2ab9062393b..3d8e061da9a275b2ed93782d2258f4f94d6341e7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,66 @@ -# PPLapangan Tembak & PoiPoLe - DTB Layanan Siswa Disabilitas (Front End) +# PPLapangan Tembak & PoiPoLe - DTB Layanan Siswa Disabilitas (Front End) - bisaGo Code Coverage -------------- -[![coverage report](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/dtb-beasiswa-miskin-dan-disabilitas/pplapangan-tembak-dtb-layanan-siswa-disabilitas/badges/staging/coverage.svg)](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/dtb-beasiswa-miskin-dan-disabilitas/pplapangan-tembak-dtb-layanan-siswa-disabilitas/commits/staging) +[![coverage report](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/dtb-beasiswa-miskin-dan-disabilitas/pplapangan-tembak-dtb-layanan-siswa-disabilitas/badges/staging/coverage.svg?job=Test)](https://gitlab.cs.ui.ac.id/ppl-fasilkom-ui/2020/ppl-c/dtb-beasiswa-miskin-dan-disabilitas/pplapangan-tembak-dtb-layanan-siswa-disabilitas/commits/staging) +>bisaGo is a mobile application made with Flutter and Django REST API to gather information from users about disability friendly facilities. +## Developers + +PPLapanganTembak +1. [Adzkia Aisyah Afrah Hardian](https://gitlab.cs.ui.ac.id/adzkia.aisyah) +2. [Agnes Handoko](https://gitlab.cs.ui.ac.id/agneshandoko) +3. [Fakhira Devina](https://gitlab.cs.ui.ac.id/hiradevina) +4. [Faza Siti Sabira Prakoso](https://gitlab.cs.ui.ac.id/fazasabirappl) +5. [Firriyal bin Yahya](https://gitlab.cs.ui.ac.id/feriyalbinyahya) + +PoiPoLeGan +1. [Bimo Iman Smartadi](https://gitlab.cs.ui.ac.id/bimo.iman) +2. [Bayukanta Iqbal Gunawan](https://gitlab.cs.ui.ac.id/Bayukanta) +3. [Dzaky Noor Hasyim](https://gitlab.cs.ui.ac.id/NoorHasyim) +4. [Muhammad Abdurrahman](https://gitlab.cs.ui.ac.id/muhammad.abdurrahman71) +5. [Usman Sidiq](https://gitlab.cs.ui.ac.id/usman.sidiq71) + + + +## Table of Content + +* Install +* Running Development Mode + +## Install +The front end side uses Flutter, for installing please head to the [official documentation of Flutter](https://flutter.dev/docs/get-started/install) + +Make sure you already installed everything to work with Flutter with command: +```bash +flutter doctor -v +``` + +Install all the package dependencies in `pubspec.yaml` +```bash +flutter pub get +``` +Get your [Maps API Key](https://developers.google.com/maps/documentation/android-sdk/get-api-key) and put the key on `android/local.properties` +```bash +MAPS_API_KEY=Bu*************** +``` + +## Running Development Mode +Run the app using the development flavor +```bash +flutter run -t lib/main_dev.dart +``` +## Building Models with JsonSerializable +Jadi abis get dari API, jsonnya di map ke models biar rapih. +1. Tulis ada field apa aja dari jsonnya (bisa liat contoh yang di models/lokasi.dart) +2. bagian 'part of {nama models}.g.dart' itu harus ditulis di model yg mau dibuat. di awal emang merah, tapi biarin aja +3. kalo semua field udah di tulis, run +```bash +flutter pub run build_runner build +``` +4. nanti akan ke build file {nama models}.g.dart, yang di nomor 2 merah harusnya udah gak merah lagi + +## Passing Data with BLoC +Udah ada contohnya di /bloc (implementasi di screen nya ada di page/pencarian/pencarian.dart) +Bisa baca [disini](https://itnext.io/flutter-handling-your-network-api-calls-like-a-boss-936eef296547) sebagai panduannya \ No newline at end of file diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5246b3eccb66a25b9f81e3d3f65636a86a444e8e --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,5 @@ +include: package:pedantic/analysis_options.yaml + +analyzer: + exclude: + - "**/*.g.dart" \ No newline at end of file diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs index e8895216fd3c0c3af4c4522334775f41b7deb42e..7ce47463d1b3c98baee08f1b6cd5b5fe5c375ddc 100644 --- a/android/.settings/org.eclipse.buildship.core.prefs +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -1,2 +1,13 @@ +arguments= +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) connection.project.dir= eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_171.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/android/app/build.gradle b/android/app/build.gradle index 3429514798da079f2d4097ca77bbe6274d7e1931..191a87db47db43b4c6e8ddf24d24a53afb03aa97 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -21,9 +21,13 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } +def localPropertyApiToken = localProperties.getProperty("MAPS_API_KEY") +def systemEnvApiToken = System.getenv('MAPS_API_KEY') + apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" +def MAPS_API_KEY = localPropertyApiToken != null ? localPropertyApiToken : systemEnvApiToken android { compileSdkVersion 28 @@ -44,12 +48,13 @@ android { versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + manifestPlaceholders = [MAPS_API_KEY: MAPS_API_KEY] } buildTypes { release { // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. + // Signing with the debug keys for now, so flutter run --release works. signingConfig signingConfigs.debug } } @@ -64,4 +69,4 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} +} \ No newline at end of file diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 38838990d69858f983edbee6e8acf5a32c10ef0a..eac51190b63296f719b720b468a0f4f39846afba 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -4,4 +4,5 @@ to allow setting breakpoints, to provide hot reload, etc. --> + diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4b8980cbbfc8130d30a97caab2d260e5ae7ce461..6782f488f66280a2a535ddcd63842c11e2fdde0b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -8,7 +8,7 @@ + android:icon="@mipmap/launcher_icon"> + diff --git a/android/app/src/main/res/mipmap-hdpi/launcher_icon.png b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..77d7fa183cfe94bec5e53f3f8f634ff1ef422884 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/launcher_icon.png b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c83fa7614bc85964ca364e966dda34f61fa97248 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a31c0801ba39b64f67346a05c88aee3681541bb3 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..efec05dd687ab7ebc29c34da5270650ca42d2812 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..214f1299f3e68381d9db562d339fd6648d8f7892 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png differ diff --git a/android/build.gradle b/android/build.gradle index 3100ad2d55532e58ed44b53dd3c2a04c5bcaf160..6f110de1f2998db83a12f1904667881a7f470604 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.2.0' } } @@ -17,7 +18,6 @@ allprojects { jcenter() } } - rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" @@ -28,4 +28,4 @@ subprojects { task clean(type: Delete) { delete rootProject.buildDir -} +} \ No newline at end of file diff --git a/android/gradle.properties b/android/gradle.properties index 38c8d4544ff1c4419409796aa6c1caee2c262ff7..28276e2ce4a982395bef4f2ee1878f64cc6f0f42 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -2,3 +2,6 @@ org.gradle.jvmargs=-Xmx1536M android.enableR8=true android.useAndroidX=true android.enableJetifier=true +android.enableJetifier=true +android.useAndroidX=true +org.gradle.jvmargs=-Xmx1536M diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 296b146b7318dd58663296dbb7555df9ff328ec2..63ab3ae08f9e4c3ddbbac64e0c3aadee390f7c22 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip diff --git a/android/settings_aar.gradle b/android/settings_aar.gradle new file mode 100644 index 0000000000000000000000000000000000000000..e7b4def49cb53d9aa04228dd3edb14c9e635e003 --- /dev/null +++ b/android/settings_aar.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/assets/icon/2x/current_loc.png b/assets/icon/2x/current_loc.png new file mode 100644 index 0000000000000000000000000000000000000000..1c55a3058fc5c1429bac6949380435d055b2c689 Binary files /dev/null and b/assets/icon/2x/current_loc.png differ diff --git a/assets/icon/2x/icon_launcher.png b/assets/icon/2x/icon_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..2c188192f166ed99579ec79c664074e12fd25e99 Binary files /dev/null and b/assets/icon/2x/icon_launcher.png differ diff --git a/assets/icon/3x/current_loc.png b/assets/icon/3x/current_loc.png new file mode 100644 index 0000000000000000000000000000000000000000..930d897dceee528d3c2b13135718a712246099f8 Binary files /dev/null and b/assets/icon/3x/current_loc.png differ diff --git a/assets/icon/3x/icon_launcher.png b/assets/icon/3x/icon_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..cf5be9783e1ab2b8561990ea143d0082d4183eb8 Binary files /dev/null and b/assets/icon/3x/icon_launcher.png differ diff --git a/assets/icon/current_loc.png b/assets/icon/current_loc.png new file mode 100644 index 0000000000000000000000000000000000000000..08fc2db183a39b330b1526f39c681d9518b67539 Binary files /dev/null and b/assets/icon/current_loc.png differ diff --git a/assets/icon/icon_launcher.png b/assets/icon/icon_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..7c82fa986afdb49514350a6e24dbb1998727f9be Binary files /dev/null and b/assets/icon/icon_launcher.png differ diff --git a/assets/icon/loc.png b/assets/icon/loc.png new file mode 100644 index 0000000000000000000000000000000000000000..a7c8787a3af5b53f89978d11d8af32d2a032697f Binary files /dev/null and b/assets/icon/loc.png differ diff --git a/assets/images/disabletoilet.jpg b/assets/images/disabletoilet.jpg new file mode 100644 index 0000000000000000000000000000000000000000..74ce1ac58fd215c325a41b25404e6b3e05712ea3 Binary files /dev/null and b/assets/images/disabletoilet.jpg differ diff --git a/assets/images/margocity.jpg b/assets/images/margocity.jpg new file mode 100644 index 0000000000000000000000000000000000000000..af9bc7e0b559cb8d63d8a12e60cd03b01783e315 Binary files /dev/null and b/assets/images/margocity.jpg differ diff --git a/assets/logo/google.png b/assets/logo/google.png new file mode 100644 index 0000000000000000000000000000000000000000..2ef869d64c542bfa652312d35e2fea1757456558 Binary files /dev/null and b/assets/logo/google.png differ diff --git a/assets/logo/google.svg b/assets/logo/google.svg new file mode 100644 index 0000000000000000000000000000000000000000..7f1d5e497be41367280aece388d69ab4c999aab1 --- /dev/null +++ b/assets/logo/google.svg @@ -0,0 +1,37 @@ + + + + + + + + + + +]> + + + + + + + + + + + + + + + diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee85b89bd111b779db6116b130509ab6d4b..e8efba114687be7d0e4e5d026a31f5efd04d20bf 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 592ceee85b89bd111b779db6116b130509ab6d4b..399e9340e6f617f68676161ad4a64edcbe483115 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 0000000000000000000000000000000000000000..b30a428b5e77ede0fd1d2cb7009f930e42d8def1 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,90 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.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 parse_KV_file(file, separator='=') + file_abs_path = File.expand_path(file) + if !File.exists? file_abs_path + return []; + end + generated_key_values = {} + skip_line_start_symbols = ["#", "/"] + File.foreach(file_abs_path) do |line| + next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ } + plugin = line.split(pattern=separator) + if plugin.length == 2 + podname = plugin[0].strip() + path = plugin[1].strip() + podpath = File.expand_path("#{path}", file_abs_path) + generated_key_values[podname] = podpath + else + puts "Invalid plugin specification: #{line}" + end + end + generated_key_values +end + +target 'Runner' do + use_frameworks! + use_modular_headers! + + # Flutter Pod + + copied_flutter_dir = File.join(__dir__, 'Flutter') + copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework') + copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec') + unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path) + # Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet. + # That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration. + # CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist. + + generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig') + unless File.exist?(generated_xcode_build_settings_path) + raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path) + cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR']; + + unless File.exist?(copied_framework_path) + FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir) + end + unless File.exist?(copied_podspec_path) + FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir) + end + end + + # Keep pod path relative so it can be checked into Podfile.lock. + pod 'Flutter', :path => 'Flutter' + + # Plugin Pods + + # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock + # referring to absolute paths on developers' machines. + system('rm -rf .symlinks') + system('mkdir -p .symlinks/plugins') + plugin_pods = parse_KV_file('../.flutter-plugins') + plugin_pods.each do |name, path| + symlink = File.join('.symlinks', 'plugins', name) + File.symlink(path, symlink) + pod name, :path => File.join(symlink, 'ios') + end +end + +# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system. +install! 'cocoapods', :disable_input_output_paths => true + +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ENABLE_BITCODE'] = 'NO' + end + end +end diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index b0b73cb408abdca327f4490f43bcaa3d8985e9d7..e6fbe067943bc4bdfa163df12b63f83ad2c499ee 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + A713680F956827CC800E5882 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 608DBD9F25B5A1E158194D12 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -37,11 +38,14 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 27B4326A6F124C13099D180A /* 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 = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; + 608DBD9F25B5A1E158194D12 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 94561A220A1B4EFA7831E0FC /* 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 = ""; }; 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 = ""; }; 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; @@ -50,6 +54,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 = ""; }; + F7D6823AE5698B88142C285E /* 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 = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -59,12 +64,24 @@ files = ( 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, + A713680F956827CC800E5882 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 829932E47EADAEFD209551C7 /* Pods */ = { + isa = PBXGroup; + children = ( + 94561A220A1B4EFA7831E0FC /* Pods-Runner.debug.xcconfig */, + F7D6823AE5698B88142C285E /* Pods-Runner.release.xcconfig */, + 27B4326A6F124C13099D180A /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -84,6 +101,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 829932E47EADAEFD209551C7 /* Pods */, + F0491B426155A7C9E1ADB1A7 /* Frameworks */, ); sourceTree = ""; }; @@ -118,6 +137,14 @@ name = "Supporting Files"; sourceTree = ""; }; + F0491B426155A7C9E1ADB1A7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 608DBD9F25B5A1E158194D12 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -125,12 +152,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 45875E25277A3BB7443A1483 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + A6A877344DE185CEA8904842 /* [CP] Embed Pods Frameworks */, + 17BFDE4BCED4D29A440D5CB6 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -189,6 +219,21 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 17BFDE4BCED4D29A440D5CB6 /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -203,6 +248,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; }; + 45875E25277A3BB7443A1483 /* [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; @@ -217,6 +284,21 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A6A877344DE185CEA8904842 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "[CP] Embed Pods Frameworks"; + outputPaths = ( + ); + 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 */ diff --git a/ios/Runner.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a16ed0f1cd0c2409d848bf489b93fefa3b2..21a3cc14c74e969ab1548274a8512ebfecc40f78 100644 --- a/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + 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 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..300ae2f80ad2814cc466704e147c06059e78e345 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png 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 index 28c6bf03016f6c994b70f38d1b7346e5831b531f..ada4b7fe4d79380d3e1dae5a73fc2fee19c833a7 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png 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 index 2ccbfd967d9697cd4b83225558af2911e9571c9b..8eea4dd22c0f64e7e2e729c1bf4429e382c01287 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png 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 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..9d8723cce631060e3706563d92eed7a599334f5e 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png 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 index 4cde12118dda48d71e01fcb589a74d069c5d7cb5..1eacd7844cd572c44122b00b633ff674b09f3ced 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png 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 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..d7c6ebbeb3447d068bc1740d810dc31400202935 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png 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 index dcdc2306c28505ebc0b6c3a359c4d252bf626b9f..11656b43ffd81643db2f44232753f5734558448c 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png 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 index 2ccbfd967d9697cd4b83225558af2911e9571c9b..8eea4dd22c0f64e7e2e729c1bf4429e382c01287 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png 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 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..b23aabf9ee96e2e82b91c7cd3b8af95e39079d59 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png 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 index a6d6b8609df07bf62e5100a53a01510388bd2b22..7bb01ba0916c018d6b493da8b33167bed53a08b1 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2dbb06f0c78bc1d593744c560c79a902218b7ab5 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a2cc47629e4fc439af429f37995d8fa3785f3ece Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..e292b43465108f58c1c77f37bd77be4967009a33 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d877aba55fc7f9500f2377807f4b55dee73974d3 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png 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 index a6d6b8609df07bf62e5100a53a01510388bd2b22..7bb01ba0916c018d6b493da8b33167bed53a08b1 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png 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 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..e35743855f7dd22f7aba64ae49f5fd72bb0e7c45 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..77d7fa183cfe94bec5e53f3f8f634ff1ef422884 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png differ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efec05dd687ab7ebc29c34da5270650ca42d2812 Binary files /dev/null and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png 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 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..4dbd42d651705769af62603611dfccc3b46cb768 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png 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 index 6a84f41e14e27f4b11f16f9ee39279ac98f8d5ac..837710082fe7d5b9a57fbcfe87c56b999a8893a3 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png 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 index d0e1f58536026aebc4f1f70e481f6993c9ff088d..d67bc9485fe151a679841955dc61a110f4f37e0d 100644 Binary files a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index a59339f96fd8e242ff675f7614e9e0694560cf00..cabde0c6aab2c1ee612e96a4065549e071e9235f 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -41,5 +41,12 @@ UIViewControllerBasedStatusBarAppearance + + NSPhotoLibraryUsageDescription + Need to upload image + NSCameraUsageDescription + Need to upload image + NSMicrophoneUsageDescription + Need to upload image diff --git a/lib/app.dart b/lib/app.dart new file mode 100644 index 0000000000000000000000000000000000000000..8cad8a1b11de7af4dda03c2d73420a241d262d5c --- /dev/null +++ b/lib/app.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; + +class BisaGo extends StatelessWidget { + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'bisaGo', + theme: ThemeData( + fontFamily: 'Muli', + backgroundColor: Colors.white, + ), + home: Dashboard(), + + ); + } +} diff --git a/lib/bloc/KomentarBloc.dart b/lib/bloc/KomentarBloc.dart new file mode 100644 index 0000000000000000000000000000000000000000..0e98647f7509444ebde5124847ed5dc1221590d5 --- /dev/null +++ b/lib/bloc/KomentarBloc.dart @@ -0,0 +1,73 @@ +import 'dart:async'; + +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/repository/KomentarRepository.dart'; + +class KomentarBloc { + KomentarRepository _komentarRepository; + StreamController _komentarListController; + List allKomentarFromApi; + + StreamSink> get komentarListSink => + _komentarListController.sink; + Stream> get komentarListStream => + _komentarListController.stream; + + KomentarBloc(String namaLokasi) { + _komentarListController = StreamController>(); + _komentarRepository = KomentarRepository(); + fetchKomentarList(namaLokasi); + } + + fetchKomentarList(String namaLokasi) async { + komentarListSink.add(NetworkModel.loading('Getting Komentar')); + try { + KomentarList komentarListResponse = + await _komentarRepository.fetchKomentar(namaLokasi); + allKomentarFromApi = List.from(komentarListResponse.allKomentar); + + komentarListSink.add(NetworkModel.completed(komentarListResponse)); + } catch (e) { + komentarListSink.add(NetworkModel.error(e.toString())); + print("$e"); + } + } + + filterKomentarList(String tag, bool value, List currentList) { + if (value) { + for (var komentar in allKomentarFromApi) { + if (komentar.tag.contains(tag)) { + currentList.add(komentar); + } + } + } else { + currentList.removeWhere((komentar) => komentar.tag.contains(tag)); + } + komentarListSink.add(NetworkModel.completed(KomentarList(currentList))); + } + + sortKomentarList(int option, List currentList) { + if (option == 0) { + currentList.sort((next_komentar, prev_komentar) => + prev_komentar.date_time.compareTo(next_komentar.date_time)); + } else if (option == 1) { + currentList.sort((next_komentar, prev_komentar) => + (prev_komentar.like + prev_komentar.dislike) + .compareTo(next_komentar.like + next_komentar.dislike)); + } else if (option == 2) { + currentList.sort((next_komentar, prev_komentar) => + prev_komentar.like.compareTo(next_komentar.like)); + } + komentarListSink.add(NetworkModel.completed(KomentarList(currentList))); + } + + resetKomentarList() { + komentarListSink + .add(NetworkModel.completed(KomentarList(allKomentarFromApi))); + } + + dispose() { + _komentarListController?.close(); + } +} diff --git a/lib/bloc/KomentarPostingBloc.dart b/lib/bloc/KomentarPostingBloc.dart new file mode 100644 index 0000000000000000000000000000000000000000..c909cfbcf1bd89f578f555e67e740bc88a38d57b --- /dev/null +++ b/lib/bloc/KomentarPostingBloc.dart @@ -0,0 +1,54 @@ +import 'dart:async'; +import 'package:ppl_disabilitas/model/komentarPosting.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/repository/KomentarPostingRepository.dart'; + +class KomentarPostingBloc { + KomentarPostingRepository _komentarPostingRepository; + StreamController _komentarPostingListController; + List allKomentarPositngFromApi; + + StreamSink> get komentarPostingListSink => + _komentarPostingListController.sink; + Stream> get komentarPostingListStream => + _komentarPostingListController.stream; + + + + KomentarPostingBloc(String namaLokasi, int id) { + _komentarPostingListController = StreamController>(); + _komentarPostingRepository = KomentarPostingRepository(); + fetchKomentarPostingList(namaLokasi,id); + } + + fetchKomentarPostingList(String namaLokasi,int id) async { + komentarPostingListSink.add(NetworkModel.loading('Getting Komentar')); + try { + KomentarPostingList komentarPostingListResponse = + await _komentarPostingRepository.fetchKomentarPosting(namaLokasi,id); + allKomentarPositngFromApi = List.from(komentarPostingListResponse.allKomentar); + + komentarPostingListSink.add(NetworkModel.completed(komentarPostingListResponse)); + } catch (e) { + komentarPostingListSink.add(NetworkModel.error(e.toString())); + print("$e"); + } + } + + addKomentarPost(String namaLokasi, int id, Map data) async { + // var response = _komentarPostingRepository.addKomentarPosting(namaLokasi, id, data); + // if(response.data['response'] == 'komentar added'){ + // return true; + // } + // return false; + } + + resetKomentarPostingList() { + komentarPostingListSink + .add(NetworkModel.completed(KomentarPostingList(allKomentarPositngFromApi))); + } + + dispose() { + _komentarPostingListController?.close(); + } +} diff --git a/lib/bloc/LokasiResponseBloc.dart b/lib/bloc/LokasiResponseBloc.dart new file mode 100644 index 0000000000000000000000000000000000000000..401a8a05d2ce032e86ec7e3908de9a52de44f005 --- /dev/null +++ b/lib/bloc/LokasiResponseBloc.dart @@ -0,0 +1,60 @@ +import 'dart:async'; + +import 'package:ppl_disabilitas/model/lokasi.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/repository/LokasiRepository.dart'; + +class LokasiResponseBloc { + StreamController _recentSearchController; + LokasiRepository _lokasiRepository; + StreamController _lokasiListController; + + StreamSink> get recentSearchSink => + _recentSearchController.sink; + Stream> get recentSearchStream => + _recentSearchController.stream; + + StreamSink> get lokasiListSink => + _lokasiListController.sink; + Stream> get lokasiListStream => + _lokasiListController.stream; + + LokasiResponseBloc() { + _lokasiListController = + StreamController>(); + _recentSearchController = StreamController>(); + _lokasiRepository = LokasiRepository(); + fetchLokasiList(); + fetchRecentSearch(); + } + + fetchLokasiList() async { + lokasiListSink.add(NetworkModel.loading('Getting Locations')); + try { + final lokasiListResponse = + await _lokasiRepository.fetchLokasi(); + lokasiListSink.add(NetworkModel.completed(lokasiListResponse)); + } catch (e) { + lokasiListSink.add(NetworkModel.error(e.toString())); + } + } + + fetchRecentSearch() async { + recentSearchSink.add(NetworkModel.loading('Getting Recent Search')); + try { + final recentSearchData = await _lokasiRepository.fetchRecentSearch(); + recentSearchSink.add(NetworkModel.completed(recentSearchData)); + } catch (e) { + recentSearchSink.add(NetworkModel.error(e.toString())); + } + } + + saveRecentSearch(Lokasi search) async { + await _lokasiRepository.saveRecentSearch(search); + } + + dispose() { + _recentSearchController?.close(); + _lokasiListController?.close(); + } +} diff --git a/lib/bloc/SekolahBloc.dart b/lib/bloc/SekolahBloc.dart new file mode 100644 index 0000000000000000000000000000000000000000..423a78f4c44f92652ce7bee0d2e83012854bd2d1 --- /dev/null +++ b/lib/bloc/SekolahBloc.dart @@ -0,0 +1,83 @@ +import 'dart:async'; + +import 'package:ppl_disabilitas/model/sekolah.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/repository/SekolahRepository.dart'; + +class SekolahBloc { + SekolahRepository _sekolahRepository; + StreamController _sekolahListController; + List allSekolahFromApi; + + StreamSink> get sekolahListSink => + _sekolahListController.sink; + Stream> get sekolahListStream => + _sekolahListController.stream; + + SekolahBloc() { + _sekolahListController = StreamController>(); + _sekolahRepository = SekolahRepository(); + fetchSekolahList(); + } + + fetchSekolahList() async { + sekolahListSink.add(NetworkModel.loading('Getting Sekolah')); + try { + SekolahList sekolahListResponse = await _sekolahRepository.fetchSekolah(); + allSekolahFromApi = List.from(sekolahListResponse.allSekolah); + sekolahListSink.add(NetworkModel.completed(sekolahListResponse)); + } catch (e) { + sekolahListSink.add(NetworkModel.error(e.toString())); + print("$e"); + } + } + + filterbyKecamatan( + String kecamatan, bool value, List currentList) { + if (value) { + for (var sekolah in allSekolahFromApi) { + if (sekolah.alamat.toLowerCase().contains(kecamatan.toLowerCase())) { + currentList.add(sekolah); + } + } + } else { + currentList.removeWhere((sekolah) => + sekolah.alamat.toLowerCase().contains(kecamatan.toLowerCase())); + } + sekolahListSink.add(NetworkModel.completed(SekolahList(currentList))); + } + + filterbyKategoriSekolah( + String kategori, bool val, List currentList) { + if (val) { + for (var sekolah in allSekolahFromApi) { + if (sekolah.jenis_sekolah.contains(kategori)) { + currentList.add(sekolah); + } + } + } else { + currentList.removeWhere((sekolah) => + sekolah.jenis_sekolah.contains(kategori)); + } + sekolahListSink.add(NetworkModel.completed(SekolahList(currentList))); + } + + filterbyTingkatSekolah( + String tingkatSekolah, bool val, List currentList) { + if (val) { + for (var sekolah in allSekolahFromApi) { + if (sekolah.name.toLowerCase().startsWith(tingkatSekolah.toLowerCase())) { + currentList.add(sekolah); + } + } + } else { + currentList.removeWhere((sekolah) => + sekolah.name.toLowerCase().startsWith(tingkatSekolah.toLowerCase())); + } + sekolahListSink.add(NetworkModel.completed(SekolahList(currentList))); + } + + dispose() { + _sekolahListController?.close(); + } +} diff --git a/lib/component/ImageHolder.dart b/lib/component/ImageHolder.dart new file mode 100644 index 0000000000000000000000000000000000000000..ca0dbd0a813e3ed781ee5c1beb6fb5521e65e532 --- /dev/null +++ b/lib/component/ImageHolder.dart @@ -0,0 +1,23 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +class ImageHolder extends StatelessWidget { + final String url; + ImageHolder({@required this.url}); + @override + Widget build(BuildContext context) { + return CachedNetworkImage( + imageUrl: url, + imageBuilder: (context, imageProvider) => Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + image: DecorationImage(image: imageProvider, fit: BoxFit.fill)), + ), + placeholder: (context, _) => + const Center(child: CircularProgressIndicator()), + errorWidget: (context, url, error) => Container( + child: Center(child: Text('Failed to load images'),), + ), + ); + } +} diff --git a/lib/component/bisago_appbar.dart b/lib/component/bisago_appbar.dart new file mode 100644 index 0000000000000000000000000000000000000000..2ad2fcf7ee2cb75bd5f46a80b98a869c2977a00b --- /dev/null +++ b/lib/component/bisago_appbar.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; + +class BisaGoAppBar extends StatelessWidget implements PreferredSizeWidget { + final String title; + BisaGoAppBar({this.title = 'bisaGo', Key key}) : super(key: key); + @override + final Size preferredSize = const Size.fromHeight(55); + @override + Widget build(BuildContext context) { + return AppBar( + elevation: 15, + centerTitle: true, + backgroundColor: greenPrimary, + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.all(doubleSpace), + child: Text( + title, + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), + ), + ) + ], + ), + ); + } +} diff --git a/lib/component/bisago_drawer.dart b/lib/component/bisago_drawer.dart new file mode 100644 index 0000000000000000000000000000000000000000..e46799e21515813befb9d1621e69fe7a78c855e8 --- /dev/null +++ b/lib/component/bisago_drawer.dart @@ -0,0 +1,160 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/page/login/login.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class BisaGoDrawer extends StatelessWidget { + final List> drawerList = [ + {'title': 'Beranda', 'icon': Icons.home}, + {'title': 'Riwayat Pencarian', 'icon': Icons.history}, + {'title': 'Tentang Aplikasi', 'icon': Icons.info}, + {'title': 'Login', 'icon': Icons.keyboard_backspace} + ]; + + @override + Widget build(BuildContext context) { + final menus = drawerList.map((menu) { + return _createListTile( + context: context, icon: menu['icon'], title: menu['title']); + }).toList(); + final drawerItem = [ + Container( + height: 130, + child: DrawerHeader( + decoration: BoxDecoration( + color: greenPrimary, + ), + child: Row( + children: [ + SizedBox( + width: 40, + child: FloatingActionButton( + heroTag: null, + backgroundColor: Colors.white, + elevation: 0, + onPressed: () => {}, + ), + ), + Padding( + padding: EdgeInsets.all(doubleSpace), + child: Text( + 'Nama Orang', + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + ], + ), + ), + ), + Container( + decoration: + BoxDecoration(border: Border(top: BorderSide(color: Colors.white))), + ), + ]; + menus.forEach((menu) { + drawerItem.add(menu); + }); + + return Theme( + data: Theme.of(context).copyWith( + canvasColor: greenPrimary, + ), + child: Drawer( + child: ListView(padding: EdgeInsets.zero, children: drawerItem), + ), + ); + } + + Widget _createListTile({BuildContext context, IconData icon, String title}) { + if (title == 'Login') { + return Container( + child: FutureBuilder( + future: changeLoginDrawer(), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return Container( + child: ListTile( + leading: Icon( + icon, + color: Colors.white, + size: 30, + ), + title: Text( + snapshot.data, + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + onTap: () async { + await checkLoginStatus(context); + }, + ), + decoration: BoxDecoration( + color: greenPrimary, + border: Border( + bottom: BorderSide(color: Colors.white), + ), + ), + ); + } + return Container(); + }), + ); + } + return Container( + child: ListTile( + leading: Icon( + icon, + color: Colors.white, + size: 30, + ), + title: Text( + title, + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + onTap: () {}, + ), + decoration: BoxDecoration( + color: greenPrimary, + border: Border( + bottom: BorderSide(color: Colors.white), + ), + ), + ); + } + + Future changeLoginDrawer() async { + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + if (sharedPreferences.getString("token") == null) { + return 'Login'; + } else { + return 'Logout'; + } + } + + checkLoginStatus(BuildContext context) async { + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + if (sharedPreferences.getString("token") == null) { + _navigateToLoginPage(context); + } else { + print('okeee'); + await sharedPreferences.clear(); + await Navigator.pushNamed(context, '/'); + } + } + + void _navigateToLoginPage(BuildContext context) { + final route = MaterialPageRoute(builder: (_) => Login()); + Navigator.of(context).push(route); + } +} diff --git a/lib/component/informasi_sekolah_appbar.dart b/lib/component/informasi_sekolah_appbar.dart new file mode 100644 index 0000000000000000000000000000000000000000..7d3208d8368da07e8bc378c9ff9205b1fa5057d5 --- /dev/null +++ b/lib/component/informasi_sekolah_appbar.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; + +class InformasiSekolahAppBar extends StatelessWidget implements PreferredSizeWidget { + @override + final Size preferredSize = Size.fromHeight(55); + @override + Widget build(BuildContext context) { + return AppBar( + elevation: 15, + centerTitle: true, + backgroundColor: greenPrimary, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, size: 20), + key: Key('Back Icon Key'), + onPressed: () => Navigator.pop(context, 'Take me back')), + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding(padding: EdgeInsets.all(doubleSpace), + child: Text( + "Informasi Sekolah", + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), + ),) + + ], + ), + ); + } +} diff --git a/lib/component/tambah_komentar_appbar.dart b/lib/component/tambah_komentar_appbar.dart new file mode 100644 index 0000000000000000000000000000000000000000..c82c63cd3ded57e35d6b7e637513385e68d62ca0 --- /dev/null +++ b/lib/component/tambah_komentar_appbar.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; + +class TambahKomentarAppBar extends StatelessWidget implements PreferredSizeWidget { + @override + final Size preferredSize = Size.fromHeight(55); + @override + Widget build(BuildContext context) { + return AppBar( + elevation: 15, + centerTitle: true, + backgroundColor: greenPrimary, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, size: 20), + key: Key('Back Icon Key'), + onPressed: () => Navigator.pop(context, 'Take me back')), + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding(padding: EdgeInsets.all(doubleSpace), + child: Text( + "Tambah Komentar", + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), + ),) + + ], + ), + ); + } +} diff --git a/lib/config/custom_serializer.dart b/lib/config/custom_serializer.dart new file mode 100644 index 0000000000000000000000000000000000000000..266807319f374decbfc8f1c12fff950889bd1ab6 --- /dev/null +++ b/lib/config/custom_serializer.dart @@ -0,0 +1,5 @@ +import 'package:intl/intl.dart'; + +class CustomSerializer { + static DateTime stringToDateTime(String date) => DateFormat("dd-MM-yyyy hh:mm:ss").parse(date); +} diff --git a/lib/config/strings.dart b/lib/config/strings.dart index 1ea733ee1ace43fca3f9d713a28d6d2949b3838b..eba80e1adce409ce05e18ad5f129ce513b18784d 100644 --- a/lib/config/strings.dart +++ b/lib/config/strings.dart @@ -1,16 +1,58 @@ // Frequently used strings are stored here // No hardcoding string view files. Store here. -final String DEV_BASE_URL = "poipole.herokuapp.com"; -final String BASE_URL = "poipole.herokuapp.com"; -String KEY = ""; -String CSRF = ""; -String SESSION_ID = ""; - -setKey(String key) { - KEY = key; +const String devBaseURL = "poipole.herokuapp.com"; +const String baseURL = "poipole.herokuapp.com"; +String key = ""; +String csrf = ""; +String sessionId = ""; + +setKey(String newKey) { + key = newKey; +} + +setSessionId(String newSessionId) { + sessionId = newSessionId; } -setSessionId(String sessionId) { - SESSION_ID = sessionId; +final tags = { + 'KR': 'kursiroda', + 'LF': 'liftdisabilitas', + 'TD': 'toiletdisabilitas', + 'MM': 'masjid', + 'GB': 'guidingblock', + 'BM': 'bidangmiring', + 'CP': 'temandisabilitas', + 'JI': 'jurubahasaisyarat', + 'TN': 'tongkatdisabilitasnetra', + 'KD': 'kursiumumdisabilitas', + 'PK': 'tempatparkirdisabilitas', + 'RT': 'runningtext', + 'TB': 'tempatparkirbiasa' +}; + +Map STATUS_SEKOLAH = { + 'Swasta': 'SW', + 'Negri': 'NG', + 'Internasional': 'IT' +}; +Map STATUS_SEKOLAH_REVERSED = { + 'SW' : 'Swasta', + 'NG' : 'Negri', + 'IT' : 'Internasional' +}; +Map JENIS = { + 'Inklusi': 'IK', + 'Segregasi': 'SG' +}; +Map JENIS_REVERSED = { + 'IK': 'Inklusi', + 'SG': 'Segregasi' +}; + + + + +getTag(String tag) { + return tags[tag]; } \ No newline at end of file diff --git a/lib/config/styles.dart b/lib/config/styles.dart index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4bcb0f0f244128a3a1c7066b249f756833c957ad 100644 --- a/lib/config/styles.dart +++ b/lib/config/styles.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; + +const Color white = Color(0xffFFFFFF); +const Color greenPrimary = Color(0xff3A903A); +const Color greenPale = Color(0xff4FBA4F); +const Color redPrimary = Color(0xffC60000); +const Color grayPrimary = Color(0xff645C5C); + +const double superSmallSpace = 2.0; +const double smallSpace = 4.0; +const double regularSpace = 8.0; +const double regularBiggerSpace = 12.0; +const double doubleSpace = 16.0; +const double tripleSpace = 32.0; +const double spaceFourty = 45.0; +const double quartetSpace = 64.0; +const double spaceFourtyEight = 48.0; + +final List regularShadow = [ + BoxShadow( + color: Colors.black.withOpacity(0.25), + blurRadius: 7.0, // has the effect of softening the shadow + offset: Offset( + 5.0, // horizontal, move right 10 + 5.0, // vertical, movesn down 10 + ), + ) +]; + +final List smallShadow = [ + BoxShadow( + color: Colors.black.withOpacity(0.25), + blurRadius: 2.0, // has the effect of softening the shadow + offset: Offset( + 1.5, // horizontal, move right 10 + 1.5, // vertical, move down 10 + ), + ) +]; + +final BorderRadius regularBorderRadius = BorderRadius.circular(10); +final BorderRadius doubleBorderRadius = BorderRadius.circular(20); diff --git a/lib/flavor/flavor.dart b/lib/flavor/flavor.dart index e1508bf0c46a7068aaf370a55a46f6cfad1bc0d6..09201b9c32fa3cd40c726742a9164dc3768f497f 100644 --- a/lib/flavor/flavor.dart +++ b/lib/flavor/flavor.dart @@ -7,9 +7,9 @@ class ApiFlavor { static String getBaseUrl() { if (ApiFlavor.flavor == BuildFlavor.development.toString()) { - return DEV_BASE_URL; + return devBaseURL; } else { - return BASE_URL; + return baseURL; } } diff --git a/lib/globalnetwork.dart b/lib/globalnetwork.dart new file mode 100644 index 0000000000000000000000000000000000000000..b2e731207dfa40fce69fb8130cd8cfd8ed9ac4f6 --- /dev/null +++ b/lib/globalnetwork.dart @@ -0,0 +1,40 @@ +import 'package:dio/dio.dart'; +import 'package:mockito/mockito.dart'; + +class MockHttpClient extends Mock implements Dio {} + +var dio; + +getDioInstance(String env) { + dio = env == 'build' ? Dio() : MockHttpClient(); +} + +mockLokasiDependencies() { + when(dio.get( + any, + )).thenAnswer((_) async { + final expected = Future>>>.value( + Response>>(statusCode: 200, data: [ + { + "id": 1, + "name": "Soppeng", + "latitude": 100039203300.0, + "longitude": 100000000000.0, + "alamat": "Jalan Margonda Raya", + "no_telp": "081111111111", + "image": "test.jpg" + } + ])); + return expected; + }); +} + +mockFasilitasDependencies(Map mockFasilitas) { + when(dio.get( + any, + )).thenAnswer((_) async { + final expected = Future>>.value( + Response>(statusCode: 200, data: mockFasilitas)); + return expected; + }); +} diff --git a/lib/main.dart b/lib/main.dart index 4ed6580765258a9ac737ab7948dde4e5fe17c9bc..dba33069a72f06577c57d7c262e605d4ceb562dd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,97 +1,11 @@ import 'package:flutter/material.dart'; - +import 'package:ppl_disabilitas/app.dart'; import 'flavor/flavor.dart'; +import 'globalnetwork.dart'; void main() { + getDioInstance('build'); + dio.options.receiveTimeout = 15000; ApiFlavor.flavor = BuildFlavor.production.toString(); - runApp(MyApp()); -} -class MyApp extends StatelessWidget { - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, - ), - home: MyHomePage(title: 'bisaGo'), - ); - } -} - -class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); - - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - - final String title; - - @override - _MyHomePageState createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 30)), - backgroundColor: Color(0xff3a903a) - - ), - body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Invoke "debug painting" (press "p" in the console, choose the - // "Toggle Debug Paint" action from the Flutter Inspector in Android - // Studio, or the "Toggle Debug Paint" command in Visual Studio Code) - // to see the wireframe for each widget. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Hello World', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 40) - ), - ], - ), - ), - - ); - } + runApp(BisaGo()); } diff --git a/lib/main_dev.dart b/lib/main_dev.dart index c20de18f73673f33c4e8659aa3f5ebba4e21f63c..606b2d7f8e1a6d839fcae9ac697d7aad7f7fa337 100644 --- a/lib/main_dev.dart +++ b/lib/main_dev.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/app.dart'; import 'flavor/flavor.dart'; -import 'main.dart'; void main() { ApiFlavor.flavor = BuildFlavor.development.toString(); - runApp(MyApp()); + runApp(BisaGo()); } \ No newline at end of file diff --git a/lib/model/komentar.dart b/lib/model/komentar.dart new file mode 100644 index 0000000000000000000000000000000000000000..7182e4677191c27b26132db3749d9baa05fa1645 --- /dev/null +++ b/lib/model/komentar.dart @@ -0,0 +1,34 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:ppl_disabilitas/config/custom_serializer.dart'; + +part 'komentar.g.dart'; + +@JsonSerializable() +class KomentarList { + final List allKomentar; + KomentarList(this.allKomentar); +} + +@JsonSerializable() +class KomentarModel { + final int id; + final String nama_lokasi; + final String deskripsi; + final String creator; + @JsonKey(name: 'date_time', fromJson: CustomSerializer.stringToDateTime) + final DateTime date_time; + final int like; + final int dislike; + final int rating; + final List tag; + final String image; + final bool is_verified; + + KomentarModel( + {this.id, this.nama_lokasi, this.deskripsi, this.creator, this.date_time, + this.like, this.dislike, this.rating, this.tag, this.image, this.is_verified}); + + factory KomentarModel.fromJson(Map json) => _$KomentarModelFromJson(json); + + Map toJson() => _$KomentarModelToJson(this); +} diff --git a/lib/model/komentar.g.dart b/lib/model/komentar.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..61c3060dcdcea8a5cb9a297cf532fc9d0a6fb4f0 --- /dev/null +++ b/lib/model/komentar.g.dart @@ -0,0 +1,53 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'komentar.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +KomentarList _$KomentarListFromJson(Map json) { + return KomentarList( + (json['allKomentar'] as List) + ?.map((e) => e == null + ? null + : KomentarModel.fromJson(e as Map)) + ?.toList(), + ); +} + +Map _$KomentarListToJson(KomentarList instance) => + { + 'allKomentar': instance.allKomentar, + }; + +KomentarModel _$KomentarModelFromJson(Map json) { + return KomentarModel( + id: json['id'] as int, + nama_lokasi: json['nama_lokasi'] as String, + deskripsi: json['deskripsi'] as String, + creator: json['creator'] as String, + date_time: CustomSerializer.stringToDateTime(json['date_time'] as String), + like: json['like'] as int, + dislike: json['dislike'] as int, + rating: json['rating'] as int, + tag: (json['tag'] as List)?.map((e) => e as String)?.toList(), + image: json['image'] as String, + is_verified: json['is_verified'] as bool, + ); +} + +Map _$KomentarModelToJson(KomentarModel instance) => + { + 'id': instance.id, + 'nama_lokasi': instance.nama_lokasi, + 'deskripsi': instance.deskripsi, + 'creator': instance.creator, + 'date_time': instance.date_time?.toIso8601String(), + 'like': instance.like, + 'dislike': instance.dislike, + 'rating': instance.rating, + 'tag': instance.tag, + 'image': instance.image, + 'is_verified': instance.is_verified, + }; diff --git a/lib/model/komentarPosting.dart b/lib/model/komentarPosting.dart new file mode 100644 index 0000000000000000000000000000000000000000..200731e03593a57bc988db51e45defc5867ba101 --- /dev/null +++ b/lib/model/komentarPosting.dart @@ -0,0 +1,27 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:ppl_disabilitas/config/custom_serializer.dart'; + +part 'komentarPosting.g.dart'; + +@JsonSerializable() +class KomentarPostingList { + final List allKomentar; + KomentarPostingList(this.allKomentar); +} + +@JsonSerializable() +class KomentarPostingModel { + final int id; + final String deskripsi; + final String creator; + @JsonKey(name:'date_time', fromJson: CustomSerializer.stringToDateTime) + final DateTime date_time; + + + KomentarPostingModel( + {this.id,this.deskripsi, this.creator, this.date_time}); + + factory KomentarPostingModel.fromJson(Map json) => _$KomentarPostingModelFromJson(json); + + Map toJson() => _$KomentarPostingModelToJson(this); +} diff --git a/lib/model/komentarPosting.g.dart b/lib/model/komentarPosting.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..27f21bf79e17e4e2c5425d00b931c6af9ff6bece --- /dev/null +++ b/lib/model/komentarPosting.g.dart @@ -0,0 +1,41 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'komentarPosting.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +KomentarPostingList _$KomentarPostingListFromJson(Map json) { + return KomentarPostingList( + (json['allKomentar'] as List) + ?.map((e) => e == null + ? null + : KomentarPostingModel.fromJson(e as Map)) + ?.toList(), + ); +} + +Map _$KomentarPostingListToJson( + KomentarPostingList instance) => + { + 'allKomentar': instance.allKomentar, + }; + +KomentarPostingModel _$KomentarPostingModelFromJson(Map json) { + return KomentarPostingModel( + id: json['id'] as int, + deskripsi: json['deskripsi'] as String, + creator: json['creator'] as String, + date_time: CustomSerializer.stringToDateTime(json['date_time'] as String), + ); +} + +Map _$KomentarPostingModelToJson( + KomentarPostingModel instance) => + { + 'id': instance.id, + 'deskripsi': instance.deskripsi, + 'creator': instance.creator, + 'date_time': instance.date_time?.toIso8601String(), + }; diff --git a/lib/model/lokasi.dart b/lib/model/lokasi.dart new file mode 100644 index 0000000000000000000000000000000000000000..020fe369a004f00903d228bff13b8a0bce7560f0 --- /dev/null +++ b/lib/model/lokasi.dart @@ -0,0 +1,24 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'lokasi.g.dart'; +@JsonSerializable() +class LokasiListResponse { + List listLokasi; + + LokasiListResponse(this.listLokasi); +} + +@JsonSerializable(nullable: true) +class Lokasi { + int id; + String name; + double latitude; + double longitude; + String alamat; + String image; + String no_telp; + + Lokasi(); + + factory Lokasi.fromJson(Map json) => _$LokasiFromJson(json); + Map toJson() => _$LokasiToJson(this); +} diff --git a/lib/model/lokasi.g.dart b/lib/model/lokasi.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..68a5ac9d568bec015b93239456f17ef90b8e9700 --- /dev/null +++ b/lib/model/lokasi.g.dart @@ -0,0 +1,42 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'lokasi.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +LokasiListResponse _$LokasiListResponseFromJson(Map json) { + return LokasiListResponse( + (json['listLokasi'] as List) + ?.map((e) => + e == null ? null : Lokasi.fromJson(e as Map)) + ?.toList(), + ); +} + +Map _$LokasiListResponseToJson(LokasiListResponse instance) => + { + 'listLokasi': instance.listLokasi, + }; + +Lokasi _$LokasiFromJson(Map json) { + return Lokasi() + ..id = json['id'] as int + ..name = json['name'] as String + ..latitude = (json['latitude'] as num)?.toDouble() + ..longitude = (json['longitude'] as num)?.toDouble() + ..alamat = json['alamat'] as String + ..image = json['image'] as String + ..no_telp = json['no_telp'] as String; +} + +Map _$LokasiToJson(Lokasi instance) => { + 'id': instance.id, + 'name': instance.name, + 'latitude': instance.latitude, + 'longitude': instance.longitude, + 'alamat': instance.alamat, + 'image': instance.image, + 'no_telp': instance.no_telp, + }; diff --git a/lib/model/sekolah.dart b/lib/model/sekolah.dart new file mode 100644 index 0000000000000000000000000000000000000000..f5aa5f8d6140b210600ad356f11cdef08be2d812 --- /dev/null +++ b/lib/model/sekolah.dart @@ -0,0 +1,26 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'sekolah.g.dart'; +@JsonSerializable() +class SekolahList { + List allSekolah; + + SekolahList(this.allSekolah); +} + +@JsonSerializable() +class SekolahModel { + int id; + String name; + String alamat; + String no_telp; + String website; + int jumlah_siswa; + String status; + String jenis_sekolah; + String akreditasi; + + SekolahModel(); + + factory SekolahModel.fromJson(Map json) => _$SekolahModelFromJson(json); + Map toJson() => _$SekolahModelToJson(this); +} \ No newline at end of file diff --git a/lib/model/sekolah.g.dart b/lib/model/sekolah.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..2baf76f8ac40b4b2e6c47b9ef0e8f02ba8b83f30 --- /dev/null +++ b/lib/model/sekolah.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'sekolah.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SekolahList _$SekolahListFromJson(Map json) { + return SekolahList( + (json['allSekolah'] as List) + ?.map((e) => + e == null ? null : SekolahModel.fromJson(e as Map)) + ?.toList(), + ); +} + +Map _$SekolahListToJson(SekolahList instance) => + { + 'allSekolah': instance.allSekolah, + }; + +SekolahModel _$SekolahModelFromJson(Map json) { + return SekolahModel() + ..id = json['id'] as int + ..name = json['name'] as String + ..alamat = json['alamat'] as String + ..no_telp = json['no_telp'] as String + ..website = json['website'] as String + ..jumlah_siswa = json['jumlah_siswa'] as int + ..status = json['status'] as String + ..jenis_sekolah = json['jenis_sekolah'] as String + ..akreditasi = json['akreditasi'] as String; +} + +Map _$SekolahModelToJson(SekolahModel instance) => + { + 'id': instance.id, + 'name': instance.name, + 'alamat': instance.alamat, + 'no_telp': instance.no_telp, + 'website': instance.website, + 'jumlah_siswa': instance.jumlah_siswa, + 'status': instance.status, + 'jenis_sekolah': instance.jenis_sekolah, + 'akreditasi': instance.akreditasi, + }; diff --git a/lib/model/user.dart b/lib/model/user.dart new file mode 100644 index 0000000000000000000000000000000000000000..0fabc0d866e1753f03375e384925329dbbc6e5d9 --- /dev/null +++ b/lib/model/user.dart @@ -0,0 +1,40 @@ +import 'dart:convert'; + +class User { + bool is_login; + String username; + String name; + String email; + String phone_number; + String token; + + User({this.is_login, this.username, this.name, this.email, this.phone_number, this.token}); + + factory User.fromJson(Map map) { + return User( + username: map["username"], + name: map["name"], + email: map["email"], + phone_number: map["phone_number"],); + } + + Map toJson() { + return {"username": username, "name": name, "email": email, "phone_number": phone_number}; + } + + @override + String toString() { + return 'User{"username": $username, "name": $name, "email": $email, "phone_number": $phone_number}'; + } + +} + +List userFromJson(String jsonData) { + final data = json.decode(jsonData); + return List.from(data.map((item) => User.fromJson(item))); +} + +String userToJson(User data) { + final jsonData = data.toJson(); + return json.encode(jsonData); +} \ No newline at end of file diff --git a/lib/network/CustomException.dart b/lib/network/CustomException.dart new file mode 100644 index 0000000000000000000000000000000000000000..7d533760addfda8e9f174f86d4caef0ac0f8c9b6 --- /dev/null +++ b/lib/network/CustomException.dart @@ -0,0 +1,27 @@ +class CustomException implements Exception { + final _message; + final _prefix; + + CustomException([this._message, this._prefix]); + + String toString() { + return "$_prefix$_message"; + } +} + +class FetchDataException extends CustomException { + FetchDataException([String message]) + : super(message, "Error During Communication: "); +} + +class BadRequestException extends CustomException { + BadRequestException([message]) : super(message, "Invalid Request: "); +} + +class UnauthorisedException extends CustomException { + UnauthorisedException([message]) : super(message, "Unauthorised: "); +} + +class InvalidInputException extends CustomException { + InvalidInputException([String message]) : super(message, "Invalid Input: "); +} \ No newline at end of file diff --git a/lib/network/cookies_interface.dart b/lib/network/cookies_interface.dart index 5d597734c317a996cbabb13446d1ead6e8565e4c..4bb6c1f6d030cf38bdee87ab503ed021f7ba747c 100644 --- a/lib/network/cookies_interface.dart +++ b/lib/network/cookies_interface.dart @@ -1,24 +1,23 @@ import 'dart:convert'; import 'dart:io'; -import '../config/strings.dart'; + import 'package:path_provider/path_provider.dart'; +import 'package:ppl_disabilitas/config/strings.dart'; class CookiesInterface { - - static Future checkCookieFileAvailability() async { + Future checkCookieFileAvailability({String fileName}) async { Directory dir; - await getApplicationDocumentsDirectory().then( - (Directory directory) { - dir = directory; - } - ); - File cookieFile = File(dir.path + "/cookies.json"); - bool cookiesExist = cookieFile.existsSync(); + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + final cookieFile = File("${dir.path}/$fileName.json"); + final cookiesExist = cookieFile.existsSync(); return cookiesExist; } - static Future createCookieFile(Map responseHeaders) async { + Future createSignInCookie( + {Map responseHeaders}) async { try { String setCookie; String csrfToken; @@ -27,45 +26,79 @@ class CookiesInterface { List cookiesList; Directory dir; - await getApplicationDocumentsDirectory().then( - (Directory directory) { - dir = directory; - } - ); - File cookieFile = new File(dir.path + "/cookies.json"); + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + final cookieFile = File("${dir.path}/usercookies.json"); cookieFile.createSync(); setCookie = responseHeaders["set-cookie"]; if (setCookie != null) { csrfToken = setCookie.split(";")[0].split("=")[1]; sessionId = setCookie.split(";")[4].split(",")[1].split("=")[1]; - userKey = KEY; + userKey = key; } - cookiesList = [ csrfToken, sessionId, userKey, ]; - cookieFile.writeAsStringSync(json.encode(cookiesList)); - return; + return cookieFile; } on Exception catch (e) { print(e.toString()); - throw e; + rethrow; } } - static Future> getCookieFile() async { + Future createSearchHistoryCookie( + {Map recentSearch}) async { + print("recent searrch $recentSearch"); Directory dir; - await getApplicationDocumentsDirectory().then( - (Directory directory) { - dir = directory; + List currentSearchHistory; + try { + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + final cookieFile = File('${dir.path}/searchhistory.json'); + cookieFile.createSync(); + await checkCookieFileAvailability(fileName: "searchhistory") + .then((available) async { + if (available) { + await getCookieFile(fileName: "searchhistory").then((cookie) { + if (cookie == null) { + currentSearchHistory = []; + } else { + currentSearchHistory = cookie == "" ? [] : json.decode(cookie); + } + if (!currentSearchHistory.contains(recentSearch)) { + currentSearchHistory.insert(0, recentSearch); + } + }); + } else { + currentSearchHistory = []; } - ); - File file = File(dir.path + "/cookies.json"); + await cookieFile.writeAsString(json.encode(currentSearchHistory)); + }); + return cookieFile; + } on Exception catch (e) { + print(e.toString()); + rethrow; + } + } - dynamic res = file.readAsStringSync(); - return json.decode(res); + Future getCookieFile({String fileName}) async { + Directory dir; + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + final file = File("${dir.path}/$fileName.json"); + dynamic res; + try { + res = file.readAsStringSync(); + } on Exception { + res = []; + } + return res; } -} \ No newline at end of file +} diff --git a/lib/network/data/network_model.dart b/lib/network/data/network_model.dart index 0b49f62ae5e64f811b2e0622b4444ef5843ec64a..f42bffafabfe8b772622147ab6b0e697dddfc463 100644 --- a/lib/network/data/network_model.dart +++ b/lib/network/data/network_model.dart @@ -1,11 +1,16 @@ -class NetworkModel { - var response; - int statusCode; - String errorMessage; +class NetworkModel { + Status status; + T data; + String message; - NetworkModel({ - this.response, - this.statusCode, - this.errorMessage, - }); + NetworkModel.loading(this.message) : status = Status.LOADING; + NetworkModel.completed(this.data) : status = Status.COMPLETED; + NetworkModel.error(this.message) : status = Status.ERROR; + + @override + String toString() { + return "Status : $status \n Message : $message \n Data : $data"; + } } + +enum Status { LOADING, COMPLETED, ERROR } diff --git a/lib/network/dummy.dart b/lib/network/dummy.dart new file mode 100644 index 0000000000000000000000000000000000000000..af243edff6d51ee244328a97c28eda75d7f526d3 --- /dev/null +++ b/lib/network/dummy.dart @@ -0,0 +1,165 @@ +final mall = [ + { + "nama": "Garrison", + "latitude": -29.7127463, + "longitude": -51.2422395, + "alamat": "39 Florence Crossing", + "telepon": "+55 427 384 8575" + }, + { + "nama": "Merchant", + "latitude": 59.3528754, + "longitude": 24.0551606, + "alamat": "479 Tennessee Alley", + "telepon": "+372 472 370 4597" + }, + { + "nama": "Sachs", + "latitude": 53.7109905, + "longitude": 20.6879247, + "alamat": "238 Hermina Park", + "telepon": "+48 574 907 6433" + }, + { + "nama": "Mccormick", + "latitude": -40.1929865, + "longitude": 175.2929384, + "alamat": "70127 Warrior Pass", + "telepon": "+64 280 260 5446" + }, + { + "nama": "Columbus", + "latitude": 38.627216, + "longitude": -9.1035863, + "alamat": "502 Carberry Park", + "telepon": "+351 321 303 5722" + }, + { + "nama": "Homewood", + "latitude": 55.6849184, + "longitude": 12.5506988, + "alamat": "95032 Stephen Crossing", + "telepon": "+45 542 945 6476" + }, + { + "nama": "Fallview", + "latitude": -8.4824984, + "longitude": 118.9586867, + "alamat": "75544 Farragut Center", + "telepon": "+62 436 950 7980" + }, + { + "nama": "Sugar", + "latitude": 40.09864, + "longitude": 119.949545, + "alamat": "1251 Logan Hill", + "telepon": "+86 212 470 4195" + }, + { + "nama": "Holy Cross", + "latitude": 16.6482598, + "longitude": 101.0118776, + "alamat": "7 Corry Drive", + "telepon": "+66 136 457 5719" + }, + { + "nama": "Bashford", + "latitude": 12.3730419, + "longitude": 14.2076222, + "alamat": "92 Rockefeller Road", + "telepon": "+234 119 536 3649" + } +]; + +final postingan = [ + { + "nama_orang": "Barny Folkerd", + "suka": 1, + "tidak_suka": 1, + "diverifikasi": true, + "foto": "http://dummyimage.com/128x141.png/ff4444/ffffff", + "date": "12/22/2019", + "time": "3:57 AM" + }, + { + "nama_orang": "Erhart Cicchillo", + "suka": 2, + "tidak_suka": 2, + "diverifikasi": true, + "foto": "http://dummyimage.com/128x141.png/5fa2dd/ffffff", + "date": "1/8/2020", + "time": "6:38 PM" + }, + { + "nama_orang": "Jori Biaggioli", + "suka": 3, + "tidak_suka": 3, + "diverifikasi": true, + "foto": "http://dummyimage.com/128x141.png/cc0000/ffffff", + "date": "7/23/2019", + "time": "5:59 AM" + }, + { + "nama_orang": "Giacinta Mirando", + "suka": 4, + "tidak_suka": 4, + "diverifikasi": true, + "foto": "http://dummyimage.com/128x141.png/dddddd/000000", + "date": "12/3/2019", + "time": "11:14 PM" + }, + { + "nama_orang": "Reece Seals", + "suka": 5, + "tidak_suka": 5, + "diverifikasi": false, + "foto": "http://dummyimage.com/128x141.png/cc0000/ffffff", + "date": "11/6/2019", + "time": "11:27 PM" + }, + { + "nama_orang": "Lark McReidy", + "suka": 6, + "tidak_suka": 6, + "diverifikasi": true, + "foto": "http://dummyimage.com/128x141.png/dddddd/000000", + "date": "1/15/2020", + "time": "11:05 AM" + }, + { + "nama_orang": "Helli Gentsch", + "suka": 7, + "tidak_suka": 7, + "diverifikasi": false, + "foto": "http://dummyimage.com/128x141.png/cc0000/ffffff", + "date": "1/24/2020", + "time": "9:17 PM" + }, + { + "nama_orang": "Beniamino Dadd", + "suka": 8, + "tidak_suka": 8, + "diverifikasi": true, + "foto": "http://dummyimage.com/128x141.png/dddddd/000000", + "date": "1/17/2020", + "time": "12:34 PM" + }, + { + "nama_orang": "Mar Outridge", + "suka": 9, + "tidak_suka": 9, + "diverifikasi": false, + "foto": "http://dummyimage.com/128x141.png/5fa2dd/ffffff", + "date": "9/16/2019", + "time": "12:17 AM" + }, + { + "nama_orang": "Domenic Pennetta", + "suka": 10, + "tidak_suka": 10, + "diverifikasi": false, + "foto": "http://dummyimage.com/128x141.png/dddddd/000000", + "date": "4/4/2019", + "time": "9:46 PM" + } +]; diff --git a/lib/network/network_interface.dart b/lib/network/network_interface.dart index 698fcbcad74721fedacedca274c1754647acef32..793f5783b0821c1c532c871cf2c55cbb74e75f6e 100644 --- a/lib/network/network_interface.dart +++ b/lib/network/network_interface.dart @@ -1,136 +1,99 @@ import 'dart:convert'; -import 'package:ppl_disabilitas/flavor/flavor.dart'; -import 'data/network_model.dart'; -import 'package:http/http.dart' as http; -import '../config/strings.dart'; -import 'cookies_interface.dart'; +import 'package:dio/dio.dart'; +import 'package:ppl_disabilitas/globalnetwork.dart'; +import 'package:ppl_disabilitas/network/CustomException.dart'; +import 'dart:io'; -class NetworkInterface { - String url = ApiFlavor.getBaseUrl(); - String key = KEY; +import 'package:shared_preferences/shared_preferences.dart'; - // POST request - Future post({ - String path, - dynamic bodyParams, +class NetworkInterface { + Future post({ + String url, + Map bodyParams, bool isLogin, + bool formData = true, }) async { - Map headersJson = await _buildRequestHeader(isLogin); - NetworkModel model; + var responseJson; try { - model = await http.post( - "$url$path", - body: json.encode(bodyParams), - headers: headersJson, - ).then((response) async { - Map responseBody = json.decode(response.body); - if (!isLogin) { - if (responseBody.containsKey("key")) { - setKey(responseBody["key"]); - } - await CookiesInterface.createCookieFile(response.headers); - } - return NetworkModel( - statusCode: response.statusCode, - response: responseBody, - ); - }); - if (model.statusCode >= 400) { - throw Exception(); - } - } on Exception catch (e) { - NetworkModel errorModel = NetworkModel( - statusCode: model.statusCode, - errorMessage: e.toString(), - response: model.response); - model = errorModel; - } + SharedPreferences sharedPreferences = + await SharedPreferences.getInstance(); + dio.options.headers['Authorization'] = + 'Token ${sharedPreferences.getString('token')}'; + dio.options.headers['content-type'] = 'application/json'; - return model; + final response = await dio.post( + "$url", + data: formData ? FormData.fromMap(bodyParams) : json.encode(bodyParams), + ); + responseJson = _response(response); + } on SocketException { + throw FetchDataException("No Internet Connection"); + } catch (e) { + print(e.response.toString()); + print(e.toString()); + } + return responseJson; } - // GET request - Future get({ - String path, - bool isLogin, - }) async { - Map headersJson = await _buildRequestHeader(isLogin); - NetworkModel model; + + Future put({String url}) async { + var responseJson; try { - model = await http - .get( - "$url$path", - headers: headersJson, - ) - .then((response) { - dynamic responseBody = json.decode(response.body); - return NetworkModel( - statusCode: response.statusCode, - response: responseBody, - ); - }); - if (model.statusCode >= 400) { - throw Exception(); + SharedPreferences sharedPreferences = + await SharedPreferences.getInstance(); + dio.options.headers['Authorization'] = + 'Token ${sharedPreferences.getString('token')}'; + final response = await dio.put( + url, + ); + responseJson = response.data; + } on SocketException { + throw FetchDataException("No Internet Connection"); + } on DioError catch (e){ + if (e.response.statusCode == 406) { + return e.response.data; } - } on Exception catch (e) { - NetworkModel errorModel = NetworkModel( - statusCode: model.statusCode, - errorMessage: e.toString(), - response: model.response); - model = errorModel; } - - return model; + return responseJson; } - - // PATCH request - Future patch({ - String path, - dynamic bodyParams, + Future get({ + String url, bool isLogin, }) async { - NetworkModel model; - Map headersJson = await _buildRequestHeader(isLogin); + var responseJson; try { - model = await http - .patch( - "$url$path", - body: json.encode(bodyParams), - headers: headersJson, - ) - .then((response) { - print(response.body.toString()); - return NetworkModel( - statusCode: response.statusCode, - response: jsonDecode(response.body), - ); - }); - if (model.statusCode >= 400) { - throw Exception(); - } - } on Exception catch (e) { - NetworkModel errorModel = NetworkModel( - statusCode: model.statusCode, - errorMessage: e.toString(), - response: model.response); - model = errorModel; + final response = await dio.get( + "$url", + ); + responseJson = _response(response); + } on SocketException { + throw FetchDataException("No Internet Connection"); + } catch (e) { + print(e.toString()); } - - return model; + return responseJson; } - Future> _buildRequestHeader(bool isLogin) async { - Map headers = Map(); - headers.putIfAbsent("Content-Type", () => "application/json"); - if (isLogin) { - List cookieFile = await CookiesInterface.getCookieFile(); - setKey(cookieFile[2]); - key = cookieFile[2]; - headers.putIfAbsent("Authorization", () => 'Token $key'); - headers.putIfAbsent("X-CSRFToken", () => cookieFile[0]); - headers.putIfAbsent("Cookie", - () => "csrftoken=${cookieFile[0]};sessionid=${cookieFile[1]}"); - return headers; + dynamic _response(Response response) { + switch (response.statusCode) { + case 200: + return response.data; + case 201: + return response.data; + case 400: + throw BadRequestException(response.data.toString()); + break; + case 404: + print(response.data); + break; + case 403: + throw UnauthorisedException(response.data.toString()); + case 406: + return response.data; + + default: + throw FetchDataException( + 'Error occured while Communication with Server with status : ${response.statusCode}'); } } -} \ No newline at end of file +} diff --git a/lib/page/addInformasi/addInfromasi.dart b/lib/page/addInformasi/addInfromasi.dart new file mode 100644 index 0000000000000000000000000000000000000000..6664178fdfbb44e63b3d9072dc246c2512ce3dcc --- /dev/null +++ b/lib/page/addInformasi/addInfromasi.dart @@ -0,0 +1,313 @@ +import 'dart:io'; +import 'dart:async'; + +import 'package:http/http.dart' as http; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/utils/customDeskripsiField.dart'; +import 'package:ppl_disabilitas/utils/customButton.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smooth_star_rating/smooth_star_rating.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + + +class AddInformasi extends StatefulWidget{ + final String nama; + AddInformasiState createState() => AddInformasiState(); + + AddInformasi({this.nama}); +} + +class AddInformasiState extends State { + File _image; + TextEditingController deskripsiController = TextEditingController(); + var rating = 0.0; + var tag = ''; + final GlobalKey _formKey = GlobalKey(); + Map fasilitas = { + 'Kursi Roda': false, + 'Lift Disabilitas': false, + 'Toilet Disabilitas': false, + 'Masjid/Mushola': false, + 'Guiding Block': false, + 'Bidang Miring': false, + 'Teman Disabilitas': false, + 'Juru Bahasa Isyarat': false, + 'Tongkat Disabilitas Netra':false, + 'Kursi Umum Disabilitas': false, + 'Tempat Parkir Disabilitas': false, + 'Running Text': false, + 'Tempat Parkir Biasa' : false, + }; + + Map tags = { + 'Kursi Roda': 'KD', + 'Lift Disabilitas': 'LF', + 'Toilet Disabilitas': 'TD', + 'Masjid/Mushola': 'MM', + 'Guiding Block': 'GB', + 'Bidang Miring': 'BM', + 'Teman Disabilitas': 'CP', + 'Juru Bahasa Isyarat': 'JI', + 'Tongkat Disabilitas Netra':'TN', + 'Kursi Umum Disabilitas': 'KD', + 'Tempat Parkir Disabilitas': 'PK', + 'Running Text': 'RT', + 'Tempat Parkir Biasa' : 'TB', + }; + + Future _getImage() async { + var image = await ImagePicker.pickImage(source: ImageSource.gallery); + + setState(() { + _image = image; + print('_image : $_image'); + }); + } + Future _clearImage() async { + + setState(() { + _image = null; + print('_image : $_image'); + }); + } + + Future _clearCheckBox() async{ + fasilitas.forEach((k, v) { + var key = k; + fasilitas[key]=false; + }); + } + + + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Tambah Informasi'), + + centerTitle: true, + backgroundColor: Color(0xff3A903A), + ), + body: SingleChildScrollView( + child: Form( + key: _formKey, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 20), + Text("Foto Fasilitas",style: TextStyle(fontSize: 18),textAlign: TextAlign.left,), + GridView.count( + key: Key('Input Gambar'), + shrinkWrap: true, + primary: false, + padding: const EdgeInsets.all(10), + crossAxisSpacing: 10, + crossAxisCount: 2, + children: [ + GestureDetector( + onTap: _getImage, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20.0), + topRight: Radius.circular(20.0), + bottomLeft: Radius.circular(20.0), + bottomRight: Radius.circular(20.0), + ), + color: Colors.black12, + ), + child: _image == null ? Icon(FontAwesomeIcons.plus) : Image.file(_image), + ), + ) + ], + ), + CustomDeskripsiField( + title: 'Informasi Fasilitas', + key: Key('Text Field Informasi'), + onSaved: (input) { + }, + validator: FieldValidator.validateInfo, + controller: deskripsiController, + ), + SizedBox(height: 20), + Text("Tag Pencarian",style: TextStyle(fontSize: 18),textAlign: TextAlign.left,), + ListView( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + key: Key('Checkbox Fasilitas'), + children: fasilitas.keys.map((String key) { + return CheckboxListTile( + title: Text(key), + value: fasilitas[key], + onChanged: (bool value) { + setState(() { + fasilitas[key] = value; + }); + }, + ); + }).toList(), + ), + SizedBox(height: 20), + Container( + alignment: Alignment.center, + key: Key('Star Rating'), + child: SmoothStarRating( + allowHalfRating: false, + onRatingChanged: (v) { + rating = v; + setState(() {}); + }, + starCount: 5, + rating: rating, + size: 40.0, + filledIconData: Icons.star, + halfFilledIconData: Icons.star_half, + color: Colors.green, + borderColor: Colors.green, + spacing:0.0, + ), + ), + Container( + margin: EdgeInsets.fromLTRB(0, 30, 0, 10), + alignment: Alignment.center, + child: Row( + children: [ + Expanded( + child: ButtonTheme( + key: Key("Batal Button"), + minWidth: double.infinity, + height: 40, + child: RaisedButton( + padding: EdgeInsets.symmetric(vertical: 15), + highlightElevation: 0.0, + splashColor: Color(0xff3A903A), + highlightColor: Color(0xff3A903A), + elevation: 0.0, + color: Colors.white70, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + side: BorderSide(color: Color(0xff3A903A)) + ), + + child: Text( + 'Batal', + style: TextStyle(fontSize: 20, color: Colors.black, fontWeight: FontWeight.bold), + ), + onPressed: (){ + _resetInput(); + } + + ), + + ), + ), + + SizedBox(width: 5,), + Expanded( + child : ButtonTheme( + key: Key("Simpan Button"), + minWidth: double.infinity, + height: 40, + child: submitButton( + 'Simpan', _validateInformationInput), + ), + + ), + + ], + ), + ), + + ], + ), + ), + + ) + + ) + + + ); + + } + + addInfo(String tag, String deskripsi, String rating) async { + for(MapEntry me in fasilitas.entries) { + if(me.value == true) tag = tag + tags[me.key] + ' '; + } + Map data = { + 'tag': tag, + 'deskripsi': deskripsi, + 'rating' : rating, + }; + + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + String namaTempat = widget.nama.replaceAll(" ", "%20"); + var response = await http.post( + 'http://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/add-fasilitas/$namaTempat/', + headers: {"Authorization" : "token " + sharedPreferences.getString("token")}, + body: data); + if (response.statusCode == 201) { + successDialog(context); + Timer(Duration(seconds: 2), () { + Navigator.pop(context); + Navigator.pop(context); + }); + } + else { + failedDialog(context); + } + } + + void successDialog(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Tambah Informasi berhasil'), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } + + void failedDialog(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Gagal menambahkan informasi'), + content: Icon(FontAwesomeIcons.exclamationCircle), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } + + void _validateInformationInput() async { + final FormState form = _formKey.currentState; + if(_formKey.currentState.validate()) { + form.save(); + int ratingInt = rating.toInt(); + await addInfo(tag, deskripsiController.text.toString(), ratingInt.toString()); + } + } + + void _resetInput() async{ + deskripsiController.clear(); + rating = 0.0; + await _clearImage(); + await _clearCheckBox(); + Navigator.pop(context); + } + + + +} \ No newline at end of file diff --git a/lib/page/dashboard/dashboard.dart b/lib/page/dashboard/dashboard.dart new file mode 100644 index 0000000000000000000000000000000000000000..adc960b9aa0e94ba8567f538ebd7f82a7bfae6ad --- /dev/null +++ b/lib/page/dashboard/dashboard.dart @@ -0,0 +1,196 @@ +import 'dart:async'; +import 'package:location/location.dart'; +import 'package:flutter/material.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:ppl_disabilitas/component/bisago_appbar.dart'; +import 'package:ppl_disabilitas/component/bisago_drawer.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/page/pencarian/pencarian.dart'; +import 'package:ppl_disabilitas/page/informasi/layananDisabilitas.dart'; + +class Dashboard extends StatefulWidget { + DashboardState createState() => DashboardState(); +} + +class DashboardState extends State { + final Completer _controller = Completer(); + final double cameraZoom = 16; + final LatLng defaultLocation = const LatLng(-6.1753924, 106.8249641); + final String currentLocationIconAsset = "assets/icon/current_loc.png"; + Location location; + Set _markers = Set(); + LocationData currentLocation; + BitmapDescriptor currentLocationIcon; + bool _serviceEnabled; + PermissionStatus _permissionGranted; + Marker contohMarker = Marker( + markerId: MarkerId("contoh1"), + position: LatLng(-6.365474, 106.828157), + infoWindow: const InfoWindow(title: "Fasilkom"), + icon: BitmapDescriptor.defaultMarkerWithHue( + BitmapDescriptor.hueViolet, + ), + ); + + @override + void initState() { + super.initState(); + location = Location(); + enableLocationService(); + location.onLocationChanged().listen((LocationData cLoc) { + currentLocation = cLoc; + updatePinOnMap(); + }); + setSourceAndDestinationIcons(); + setInitialLocation(); + _markers.add(contohMarker); + } + + enableLocationService() async { + await location.changeSettings(accuracy: LocationAccuracy.HIGH); + _serviceEnabled = await location.serviceEnabled(); + if (!_serviceEnabled) { + _serviceEnabled = await location.requestService(); + if (!_serviceEnabled) { + return; + } + } + _permissionGranted = await location.hasPermission(); + if (_permissionGranted == PermissionStatus.DENIED) { + _permissionGranted = await location.requestPermission(); + if (_permissionGranted != PermissionStatus.GRANTED) { + return; + } + } + } + + void _navigateToPencarianPage(BuildContext context) { + final route = MaterialPageRoute(builder: (_) => Pencarian()); + Navigator.of(context).push(route); + } + + void _navigateToInformasiLayananDisabilitasPage(BuildContext context) { + final route = MaterialPageRoute(builder: (_) => LayananDisabilitas()); + Navigator.of(context).push(route); + } + + static const textFieldKey = Key('Text Field Mau Kemana'); + @override + Widget build(BuildContext context) { + return Scaffold( + drawer: BisaGoDrawer(), + body: Stack(key: const Key("Stack"), children: [ + _buildGoogleMap(context), + InkWell( + key: const Key("Navigate to Pencarian"), + onTap: () => _navigateToPencarianPage(context), + child: Container( + key: const Key("Container Text Field"), + margin: EdgeInsets.only( + left: doubleSpace, right: doubleSpace, top: doubleSpace), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: doubleBorderRadius, + boxShadow: regularShadow), + child: TextFormField( + enabled: false, + key: const Key("Text Field Mau Kemana"), + decoration: InputDecoration( + prefixIcon: Icon( + Icons.search, + color: greenPrimary, + size: 25, + ), + border: InputBorder.none, + fillColor: Colors.white, + labelText: 'Kamu mau kemana?', + labelStyle: TextStyle( + color: greenPrimary, + fontSize: 20, + fontFamily: 'Muli', + fontWeight: FontWeight.w700), + suffixIcon: IconButton( + key: const Key("IconButton Text Field"), + icon: Icon( + Icons.mic, + color: greenPrimary, + size: 25, + ), + onPressed: () {})), + onTap: () => _navigateToPencarianPage(context), + ), + ), + ), + ]), + floatingActionButton: FloatingActionButton.extended( + key: const Key("FloatingActionButton"), + onPressed: () { + _navigateToInformasiLayananDisabilitasPage(context); + }, + label: Text('Informasi Layanan Disabilitas'), + icon: Icon(Icons.search), + backgroundColor: greenPrimary, + ), + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + appBar: PreferredSize( + preferredSize: const Size.fromHeight(55), + child: BisaGoAppBar(), + key: const Key("Scaffold Text Field"), + ), + ); + } + + Widget _buildGoogleMap(BuildContext context) { + CameraPosition initialCameraPosition = CameraPosition( + target: defaultLocation, + zoom: cameraZoom, + ); + if (currentLocation != null) { + initialCameraPosition = CameraPosition( + target: LatLng(currentLocation.latitude, currentLocation.longitude), + zoom: cameraZoom, + ); + } + return Container( + key: const Key("Container GoogleMap"), + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + child: GoogleMap( + key: const Key("Google Map"), + markers: _markers, + mapType: MapType.normal, + initialCameraPosition: initialCameraPosition, + onMapCreated: (GoogleMapController controller) { + _controller.complete(controller); + }, + ), + ); + } + + setSourceAndDestinationIcons() async { + currentLocationIcon = await BitmapDescriptor.fromAssetImage( + ImageConfiguration(devicePixelRatio: 5), currentLocationIconAsset); + } + + updatePinOnMap() async { + CameraPosition cPosition = CameraPosition( + zoom: cameraZoom, + target: LatLng(currentLocation.latitude, currentLocation.longitude), + ); + final GoogleMapController controller = await _controller.future; + await controller.animateCamera(CameraUpdate.newCameraPosition(cPosition)); + setState(() { + var pinPosition = + LatLng(currentLocation.latitude, currentLocation.longitude); + _markers.removeWhere((m) => m.markerId.value == 'currentLocationPin'); + _markers.add(Marker( + markerId: MarkerId('currentLocationPin'), + position: pinPosition, + icon: currentLocationIcon)); + }); + } + + setInitialLocation() async { + currentLocation = await location.getLocation(); + } +} diff --git a/lib/page/filter_fasilitas/fasilitas.dart b/lib/page/filter_fasilitas/fasilitas.dart new file mode 100644 index 0000000000000000000000000000000000000000..13a5503725f5dff79b7509e9585eb6bf6f2b59d0 --- /dev/null +++ b/lib/page/filter_fasilitas/fasilitas.dart @@ -0,0 +1,973 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/bloc/KomentarBloc.dart'; +import 'package:ppl_disabilitas/component/ImageHolder.dart'; +import 'package:ppl_disabilitas/component/bisago_appbar.dart'; +import 'package:ppl_disabilitas/component/bisago_drawer.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/page/addInformasi/addInfromasi.dart'; +import 'package:ppl_disabilitas/page/filter_fasilitas/komentar.dart'; +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/page/login/login.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + + +class Fasilitas extends StatefulWidget { + final String nama; + final String alamat; + final String url; + final String telpon; + final int id; + Fasilitas({this.nama, this.alamat, this.url, this.telpon, this.id}); + @override + _FasilitasState createState() => _FasilitasState(); +} + +class _FasilitasState extends State { + var kursiRodaVal = true; + var liftVal = true; + var toiletDisabilitasVal = true; + var tempatIbadahVal = true; + var bidangMiringVal = true; + var parkirUmumVal = true; + var parkirDisabilitasVal = true; + var guidingBlockVal = true; + var temanDisabilitasVal = true; + var juruIsyaratVal = true; + var tongkatVal = true; + var kursiDisabilitasVal = true; + var runningTextVal = true; + var sortKomentar = -1; + var showUrutan = true; + var komentarStream; + List allKomentarFromApi; + KomentarBloc _bloc; + + @override + void initState() { + allKomentarFromApi = []; + _bloc = KomentarBloc(widget.nama); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + drawer: BisaGoDrawer(), + body: SingleChildScrollView( + child: Column(children: [ + SizedBox(height: 160, child: ImageHolder(url: widget.url)), + Container( + padding: EdgeInsets.all(doubleSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.nama, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + Container( + margin: EdgeInsets.only( + top: regularSpace, + bottom: regularSpace, + left: smallSpace), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon(Icons.place, color: Colors.black, size: 20), + Flexible( + key: Key('Alamat'), + child: Text( + widget.alamat, + softWrap: true, + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 15, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + ), + ], + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Icon( + Icons.local_phone, + color: Colors.black, + size: 20, + ), + Flexible( + child: Text( + widget.telpon, + softWrap: true, + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 15, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + ), + ], + ), + Container( + margin: EdgeInsets.only( + top: doubleSpace, bottom: doubleSpace, left: smallSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: SizedBox( + width: double.infinity, + child: FlatButton( + key: Key('Tambah Informasi'), + color: Colors.green[700], + textColor: Colors.white, + disabledColor: Colors.grey, + disabledTextColor: Colors.black, + padding: EdgeInsets.all(8), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.transparent)), + splashColor: Colors.lightGreen, + onPressed: () { + checkLoginStatus(); + }, + child: Text( + "Tambah Informasi", + style: TextStyle(fontSize: 20), + ), + ), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Fasilitas', + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + Container( + decoration: BoxDecoration(boxShadow: regularShadow), + child: FlatButton( + key: Key('FilterButton'), + color: Colors.green[700], + textColor: Colors.white, + disabledColor: Colors.grey, + disabledTextColor: Colors.black, + padding: EdgeInsets.all(8), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.transparent)), + splashColor: Colors.lightGreen, + onPressed: () => showModalBottomSheet( + context: context, + builder: (context) => InsideFilter(), + backgroundColor: Colors.transparent, + isScrollControlled: true), + child: Row( + children: [ + Icon(Icons.filter_list, + color: Colors.white, size: 20), + Text( + "Filter Informasi", + style: TextStyle(fontSize: 13), + ), + ], + ), + ), + ), + ], + ), + ), + StreamBuilder( + stream: _bloc.komentarListStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + switch (snapshot.data.status) { + case Status.LOADING: + return Center( + child: CircularProgressIndicator( + valueColor: + AlwaysStoppedAnimation(greenPrimary), + ), + ); + break; + case Status.COMPLETED: + allKomentarFromApi = snapshot.data.data.allKomentar; + return Column( + children: allKomentarFromApi + .map((k) => Komentar( + komentar: k, + )) + .toList()); + break; + case Status.ERROR: + return Center( + child: Text(snapshot.data.data.toString()), + ); + break; + } + } + return Container(); + }), + ], + ), + ), + ]), + ), + appBar: BisaGoAppBar( + key: Key('Scaffold Text Field'), + ), + ); + } + + InsideFilter() { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setStateModal) => Container( + height: MediaQuery.of(context).size.height / 2, + decoration: BoxDecoration( + boxShadow: regularShadow, + borderRadius: BorderRadius.only( + topLeft: Radius.circular(10), topRight: Radius.circular(10)), + color: Colors.white, + ), + child: Column( + children: [ + Container( + padding: EdgeInsets.all(regularBiggerSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon(Icons.filter_list), + Container( + margin: EdgeInsets.only(left: regularSpace), + child: Text( + 'Filter Pencarian', + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w800, + fontSize: 20.0), + ), + ), + ], + ), + InkWell( + onTap: () => Navigator.pop(context), + child: Text( + 'BATAL', + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w800, + fontSize: 17), + ), + ), + ], + ), + ), + Container( + decoration: BoxDecoration( + border: + Border(top: BorderSide(color: greenPrimary, width: 1.5))), + ), + Expanded( + child: Row( + children: [ + Expanded( + flex: 1, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + ), + child: ListView( + children: [ + InkWell( + + key: Key('Urutan'), + child: Container( + decoration: BoxDecoration( + color: greenPale, + ), + padding: EdgeInsets.only( + left: regularSpace, + right: regularSpace, + top: doubleSpace, + bottom: doubleSpace), + child: Text( + 'Urutan', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + splashColor: Colors.green[400], + highlightColor: Colors.green[400], + onTap: () => setStateModal(() { + showUrutan = true; + })), + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide(color: greenPrimary, width: 1.5), + )), + ), + InkWell( + key: Key('Jenis Fasilitas'), + child: Container( + decoration: BoxDecoration( + color: greenPale, + ), + padding: EdgeInsets.only( + left: regularSpace, + right: regularSpace, + top: doubleSpace, + bottom: doubleSpace), + child: Text( + 'Jenis Fasilitas', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + splashColor: Colors.green[400], + highlightColor: Colors.green[400], + onTap: () => setStateModal(() { + showUrutan = false; + })), + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: greenPrimary, width: 1.5))), + ), + ], + ), + ), + ), + Expanded( + flex: 3, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border( + left: BorderSide(color: greenPrimary, width: 1.5), + ), + ), + child: Stack( + children: [ + Opacity( + opacity: showUrutan ? 1 : 0, + child: ListView( + children: [ + Row( + key: Key('Komentar Terbaru'), + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Radio( + value: 0, + groupValue: sortKomentar, + activeColor: greenPale, + onChanged: (sort) { + _bloc.sortKomentarList( + sort, allKomentarFromApi); + + setStateModal(() { + sortKomentar = sort; + }); + }, + ), + ), + Text( + "Komentar Terbaru", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Komentar Terpopuler'), + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Radio( + value: 1, + groupValue: sortKomentar, + activeColor: greenPale, + onChanged: (sort) { + _bloc.sortKomentarList( + sort, allKomentarFromApi); + + setStateModal(() { + sortKomentar = sort; + }); + }, + ), + ), + Text( + "Komentar Terpopuler", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Container( + key: Key('Komentar dengan Rating Tertinggi'), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Radio( + value: 2, + groupValue: sortKomentar, + activeColor: greenPale, + onChanged: (sort) { + _bloc.sortKomentarList( + sort, allKomentarFromApi); + + setStateModal(() { + sortKomentar = sort; + }); + }, + ), + ), + Flexible( + child: Text( + "Komentar dengan Rating Tertinggi", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ), + ], + ), + ), + ], + ), + ), + IgnorePointer( + ignoring: showUrutan, + child: Opacity( + opacity: showUrutan ? 0 : 1, + child: ListView( + children: [ + Row( + key: Key('Kursi Roda'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: kursiRodaVal, + onChanged: (bool value) { + _bloc.filterKomentarList('KR', + value, allKomentarFromApi); + setStateModal(() { + kursiRodaVal = value; + }); + }, + ), + ), + Text( + "Kursi Roda", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Lift'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: liftVal, + onChanged: (bool value) { + _bloc.filterKomentarList('LF', + value, allKomentarFromApi); + setStateModal(() { + liftVal = value; + }); + }, + ), + ), + Text( + "Lift", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Toilet Disabilitas'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: toiletDisabilitasVal, + onChanged: (bool value) { + _bloc.filterKomentarList('TD', + value, allKomentarFromApi); + setStateModal(() { + toiletDisabilitasVal = value; + }); + }, + ), + ), + Text( + "Toilet Disabilitas", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Tempat Ibadah'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: tempatIbadahVal, + onChanged: (bool value) { + _bloc.filterKomentarList('MM', + value, allKomentarFromApi); + setStateModal(() { + tempatIbadahVal = value; + }); + }, + ), + ), + Text( + "Tempat Ibadah", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Guiding Block'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: guidingBlockVal, + onChanged: (bool value) { + _bloc.filterKomentarList('GB', + value, allKomentarFromApi); + setStateModal(() { + guidingBlockVal = value; + }); + }, + ), + ), + Text( + "Guiding Block", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Bidang Miring (Ramp)'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: bidangMiringVal, + onChanged: (bool value) { + _bloc.filterKomentarList('BM', + value, allKomentarFromApi); + setStateModal(() { + bidangMiringVal = value; + }); + }, + ), + ), + Text( + "Bidang Miring (Ramp)", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Teman Disabilitas'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: temanDisabilitasVal, + onChanged: (bool value) { + _bloc.filterKomentarList('CP', + value, allKomentarFromApi); + setStateModal(() { + temanDisabilitasVal = value; + }); + }, + ), + ), + Text( + "Teman Disabilitas", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Juru Bahasa Isyarat'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: juruIsyaratVal, + onChanged: (bool value) { + _bloc.filterKomentarList('JI', + value, allKomentarFromApi); + setStateModal(() { + juruIsyaratVal = value; + }); + }, + ), + ), + Text( + "Juru Bahasa Isyarat", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ),Row( + key: Key("Tongkat Disabilitas Netra"), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: tongkatVal, + onChanged: (bool value) { + _bloc.filterKomentarList('TN', + value, allKomentarFromApi); + setStateModal(() { + tongkatVal = value; + }); + }, + ), + ), + Text( + "Tongkat Disabilitas Netra", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key("Kursi Umum Disabilitas"), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: kursiDisabilitasVal, + onChanged: (bool value) { + _bloc.filterKomentarList('KD', + value, allKomentarFromApi); + setStateModal(() { + kursiDisabilitasVal = value; + }); + }, + ), + ), + Text( + "Kursi Umum Disabilitas", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key("Parkir Umum"), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: parkirUmumVal, + onChanged: (bool value) { + _bloc.filterKomentarList('TB', + value, allKomentarFromApi); + setStateModal(() { + parkirUmumVal = value; + }); + }, + ), + ), + Text( + "Parkir Umum", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Running Text'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: runningTextVal, + onChanged: (bool value) { + _bloc.filterKomentarList('RT', + value, allKomentarFromApi); + setStateModal(() { + runningTextVal = value; + }); + }, + ), + ), + Text( + "Running Text", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + ], + ), + Row( + key: Key('Parkir Disabilitas'), + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: parkirDisabilitasVal, + onChanged: (bool value) { + _bloc.filterKomentarList('PK', + value, allKomentarFromApi); + setStateModal(() { + parkirDisabilitasVal = value; + }); + }, + ), + ), + Text( + "Parkir Disabilitas", + style: TextStyle( + color: Colors.black, fontSize: 18), + ), + //Container(height: 1.0,), + ], + ), + ], + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + Column( + children: [ + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide(color: greenPrimary, width: 1.5), + )), + ), + Container( + margin: + EdgeInsets.only(left: doubleSpace, right: doubleSpace), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + margin: EdgeInsets.only( + top: regularSpace, bottom: regularSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: FlatButton( + color: redPrimary, + textColor: Colors.white, + padding: EdgeInsets.only( + top: regularBiggerSpace, + bottom: regularBiggerSpace, + left: doubleSpace, + right: doubleSpace), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.transparent)), + splashColor: greenPrimary, + onPressed: () { + setStateModal(() { + kursiRodaVal = true; + liftVal = true; + toiletDisabilitasVal = true; + tempatIbadahVal = true; + bidangMiringVal = true; + parkirUmumVal = true; + parkirDisabilitasVal = true; + guidingBlockVal = true; + temanDisabilitasVal = true; + juruIsyaratVal = true; + tongkatVal = true; + kursiDisabilitasVal = true; + runningTextVal = true; + sortKomentar = -1; + }); + _bloc.resetKomentarList(); + }, + child: Text( + "Hapus Semua", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w400), + ), + ), + ), + + ], + ), + ), + ], + ), + ], + ), + ), + ); + } + + @override + void dispose() { + kursiRodaVal = true; + liftVal = true; + toiletDisabilitasVal = true; + tempatIbadahVal = true; + bidangMiringVal = true; + parkirUmumVal = true; + parkirDisabilitasVal = true; + guidingBlockVal = true; + temanDisabilitasVal = true; + juruIsyaratVal = true; + tongkatVal = true; + kursiDisabilitasVal = true; + runningTextVal = true; + sortKomentar = -1; + super.dispose(); + } + + checkLoginStatus() async { + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + if(sharedPreferences.getString("token") == null) { + await Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => Login()), (Route route) => false); + } + else { + await Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => AddInformasi( + nama: widget.nama, + ))).then((value) => _bloc.fetchKomentarList(widget.nama)); + } + } + + +} diff --git a/lib/page/filter_fasilitas/komentar.dart b/lib/page/filter_fasilitas/komentar.dart new file mode 100644 index 0000000000000000000000000000000000000000..0f35d90c667d6a184bd57b1969a3a52b58617813 --- /dev/null +++ b/lib/page/filter_fasilitas/komentar.dart @@ -0,0 +1,249 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/component/ImageHolder.dart'; +import 'package:ppl_disabilitas/config/strings.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/page/filter_fasilitas/postingan/detailpost.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; +import 'package:ppl_disabilitas/page/login/login.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +class Komentar extends StatefulWidget { + final KomentarModel komentar; + + Komentar({@required this.komentar}); + @override + _KomentarState createState() => _KomentarState(); +} + +class _KomentarState extends State { + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => DetailPostPage( + komentar: widget.komentar, + ))); + }, + child: Container( + margin: EdgeInsets.only(bottom: regularSpace), + padding: EdgeInsets.all(doubleSpace), + decoration: BoxDecoration( + boxShadow: regularShadow, + border: Border.all(width: 2, color: greenPrimary.withOpacity(0.4)), + borderRadius: BorderRadius.all( + Radius.circular(10) // <--- border radius here + ), + color: Colors.white, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(bottom: regularSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.komentar.creator, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + Row( + children: [ + Container( + margin: EdgeInsets.only(right: regularSpace), + child: InkWell( + onTap: () => checkLoginStatus("like"), + child: Row( + children: [ + Icon(Icons.thumb_up, + color: Colors.green[800], size: 20), + Text( + '${widget.komentar.like} suka', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Colors.green[800], + ), + ), + ], + ), + ), + ), + Container( + margin: EdgeInsets.only(right: regularSpace), + child: InkWell( + onTap: () => checkLoginStatus("dislike"), + child: Row( + children: [ + Icon(Icons.thumb_down, + color: redPrimary, size: 20), + Text( + '${widget.komentar.dislike} tidak suka', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: redPrimary, + ), + ), + ], + ), + ), + ), + ], + ) + ], + ), + ), + Container( + margin: EdgeInsets.only(bottom: regularSpace), + child: ImageHolder(url: widget.komentar.image)), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: Text( + widget.komentar.deskripsi, + softWrap: true, + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 15, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + ), + ], + ), + Wrap( + children: [ + ...widget.komentar.tag.map((tag) { + return _tag(tag); + }).toList() + ], + ), + ], + )), + ); + } + + Widget _tag(String tag) { + return Container( + margin: EdgeInsets.only(top: regularSpace, right: regularSpace), + padding: EdgeInsets.all(6), + decoration: BoxDecoration( + boxShadow: smallShadow, + border: Border.all(width: 2, color: greenPrimary.withOpacity(0.4)), + borderRadius: BorderRadius.all( + Radius.circular(10) // <--- border radius here + ), + color: Colors.white, + ), + child: Text( + '#${getTag(tag)}', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + color: greenPrimary, + fontFamily: 'Muli', + ), + ), + ); + } + + saveLikeDislike(String operation) async { + String namaTempat = widget.komentar.nama_lokasi.replaceAll(" ", "%20"); + String idString = widget.komentar.id.toString(); + print('http://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/like-fasilitas/$namaTempat/$idString/$operation/'); + var response = await NetworkInterface().put( + url: + 'https://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/like-fasilitas/$namaTempat/$idString/$operation/', + ); + if (response['response'] == "You have successfuly like this facility") { + likeSuccess(context); + } else if (response['response'] == + "You have successfuly dislike this facility") { + dislikeSuccess(context); + } else { + likeDislikeFailed(context); + } + } + + void likeSuccess(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: greenPrimary, + title: Text( + 'Like komentar berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + void dislikeSuccess(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: greenPrimary, + title: Text( + 'Dislike komentar berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + void likeDislikeFailed(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: redPrimary, + title: Text( + 'Like atau dislike komentar tidak berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(Icons.close), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + checkLoginStatus(String operation) async { + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + if (sharedPreferences.getString("token") == null) { + await Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (BuildContext context) => Login()), + (Route route) => false); + } else { + saveLikeDislike(operation); + } + } +} diff --git a/lib/page/filter_fasilitas/postingan/addKomentar.dart b/lib/page/filter_fasilitas/postingan/addKomentar.dart new file mode 100644 index 0000000000000000000000000000000000000000..791fc0b16e6f21cb65f5774e6f7f5a9d96f461aa --- /dev/null +++ b/lib/page/filter_fasilitas/postingan/addKomentar.dart @@ -0,0 +1,173 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:ppl_disabilitas/component/tambah_komentar_appbar.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; +import 'package:ppl_disabilitas/utils/customButton.dart'; +import 'package:ppl_disabilitas/utils/customKomentarField.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; + +class AddKomentar extends StatefulWidget { + final KomentarModel komentar; + AddKomentar(this.komentar); + @override + AddKomentarState createState() => AddKomentarState(); +} + +class AddKomentarState extends State { + TextEditingController textFieldController = TextEditingController(); + GlobalKey _formKey = GlobalKey(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: PreferredSize( + preferredSize: Size.fromHeight(55), + child: TambahKomentarAppBar(), + ), + body: ListView(children: [ + Container( + padding: EdgeInsets.only( + top: tripleSpace, + bottom: regularSpace, + right: doubleSpace, + left: doubleSpace), + child: Text( + widget.komentar.nama_lokasi, + style: TextStyle( + fontSize: 30, + fontWeight: FontWeight.w600, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.only( + bottom: doubleSpace, + right: regularSpace, + left: doubleSpace), + child: Text("Postingan oleh", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: Colors.black, + fontFamily: 'Muli', + )), + ), + Container( + padding: + EdgeInsets.only(bottom: doubleSpace, right: regularSpace), + child: Text(widget.komentar.creator, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: Colors.black, + fontFamily: 'Muli', + ))), + ], + ), + Form( + key: _formKey, + child: Column( + children: [ + Container( + padding: EdgeInsets.only( + bottom: tripleSpace, + right: doubleSpace, + left: doubleSpace), + child: CustomKomentarField( + title: "Komentar Informasi", + hint: "Tulis disini...", + validator: FieldValidator.validateInfo, + controller: textFieldController, + ), + ), + Container( + padding: EdgeInsets.only( + bottom: tripleSpace, + right: doubleSpace, + left: doubleSpace), + alignment: Alignment.center, + child: ButtonTheme( + minWidth: double.infinity, + height: 40, + child: submitButton('Kirim', _validateKomentarInput), + )) + ], + )), + ])); + } + + _validateKomentarInput() async { + final FormState form = _formKey.currentState; + if (_formKey.currentState.validate()) { + form.save(); + saveKomentar(textFieldController.text); + } + } + + saveKomentar(String komentar) async { + Map data = {'deskripsi': komentar}; + String namaTempat = widget.komentar.nama_lokasi; + String idString = widget.komentar.id.toString(); + var response = await NetworkInterface().post( + url: + 'http://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/add-komentar/$namaTempat/$idString/', + bodyParams: data, formData: true); + if (response['response'] == "komentar added") { + inputData(context); + } else { + inputDataFail(context); + } + } + + void inputData(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: greenPrimary, + title: Text( + 'Tambah Komentar berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + void inputDataFail(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: greenPrimary, + title: Text( + 'Tambah Komentar tidak Berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(FontAwesomeIcons.cross), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } +} diff --git a/lib/page/filter_fasilitas/postingan/detailpost.dart b/lib/page/filter_fasilitas/postingan/detailpost.dart new file mode 100644 index 0000000000000000000000000000000000000000..70ef012372e22f5c55094448f372dcaa00667afc --- /dev/null +++ b/lib/page/filter_fasilitas/postingan/detailpost.dart @@ -0,0 +1,479 @@ +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:intl/intl.dart'; +import 'package:ppl_disabilitas/bloc/KomentarPostingBloc.dart'; +import 'package:ppl_disabilitas/component/ImageHolder.dart'; +import 'package:ppl_disabilitas/component/bisago_appbar.dart'; +import 'package:ppl_disabilitas/config/strings.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/model/komentarPosting.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; +import 'package:ppl_disabilitas/page/filter_fasilitas/postingan/addKomentar.dart'; +import 'package:ppl_disabilitas/page/login/login.dart'; +import 'package:ppl_disabilitas/page/updateInformasi/updateInformasi.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class DetailPostPage extends StatefulWidget { + final KomentarModel komentar; + DetailPostPage({@required this.komentar}); + @override + _DetailPostPageState createState() => _DetailPostPageState(); +} + +class _DetailPostPageState extends State { + KomentarPostingBloc _bloc; + List allKomentarPostingFromApi; + + @override + void initState() { + allKomentarPostingFromApi = []; + _bloc = + KomentarPostingBloc(widget.komentar.nama_lokasi, widget.komentar.id); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: BisaGoAppBar( + title: widget.komentar.nama_lokasi, + key: Key('appbar-text-${widget.komentar.nama_lokasi}'), + + ), + body: Container( + margin: EdgeInsets.all(doubleSpace), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ImageHolder(url: widget.komentar.image), + Wrap( + alignment: WrapAlignment.start, + direction: Axis.horizontal, + crossAxisAlignment: WrapCrossAlignment.start, + children: widget.komentar.tag + .map((tag) => _createTagContainer(getTag(tag))) + .toList(), + ), + Container( + key: Key('desc'), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: regularShadow, + border: Border.all(color: greenPale), + borderRadius: regularBorderRadius), + padding: EdgeInsets.all(doubleSpace), + margin: EdgeInsets.symmetric(vertical: regularSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: Text( + 'Informasi', + style: + TextStyle(fontSize: 20, fontWeight: FontWeight.w800), + ), + ), + Expanded( + child: ButtonTheme( + height: 15, + minWidth: 10, + child: RaisedButton( + child: Text( + 'Ubah Informasi', + style: TextStyle(fontSize: 15) + ), + onPressed: updateInformasi, + padding: EdgeInsets.symmetric(vertical: 5,horizontal: 5,), + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + side: BorderSide(color: Color(0xff3A903A)) + ), + ), + ), + ), + ], + + ), + + Container( + margin: EdgeInsets.symmetric(vertical: regularSpace), + child: Text( + widget.komentar.deskripsi, + style: TextStyle(fontSize: 18), + ), + ), + Container( + margin: EdgeInsets.symmetric(vertical: regularSpace), + child: Text( + 'Diposting oleh', + style: TextStyle(fontSize: 18), + ), + ), + Text( + '${widget.komentar.creator}', + style: TextStyle(fontSize: 18), + key: Key('creator-${widget.komentar.creator}'), + ), + Text( + '${DateFormat('dd MMMM yyy hh:mm').format(widget.komentar.date_time)}', + style: TextStyle(color: grayPrimary, fontSize: 16), + key: Key('timestamp'), + ), + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: InkWell( + onTap: () => updateLike('like'), + child: Container( + key: Key('like'), + decoration: BoxDecoration( + color: greenPrimary, + borderRadius: regularBorderRadius, + boxShadow: regularShadow), + padding: EdgeInsets.all(smallSpace), + margin: + EdgeInsets.symmetric(horizontal: smallSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.thumb_up, + color: Colors.white, + ), + Text( + '${widget.komentar.like} Suka', + style: TextStyle( + fontWeight: FontWeight.w700, + color: Colors.white, + fontSize: 16), + ), + ], + ), + ), + ), + ), + Expanded( + child: InkWell( + onTap: () => updateLike('dislike'), + child: Container( + key: Key('dislike'), + decoration: BoxDecoration( + color: redPrimary, + borderRadius: regularBorderRadius, + boxShadow: regularShadow), + padding: EdgeInsets.all(smallSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.thumb_down, + color: Colors.white, + ), + Text( + '${widget.komentar.dislike} Tidak Suka', + style: TextStyle( + fontWeight: FontWeight.w700, + color: Colors.white, + fontSize: 16), + ), + ], + ), + ), + ), + ) + ], + ) + ], + ), + ), + Container( + key: Key('rating'), + decoration: BoxDecoration( + color: Colors.white, + boxShadow: regularShadow, + border: Border.all(color: greenPale), + borderRadius: regularBorderRadius), + padding: EdgeInsets.all(doubleSpace), + child: Column( + children: [ + Text( + 'Rating', + style: TextStyle( + fontWeight: FontWeight.w800, + ), + ), + Row( + children: [ + Text('${widget.komentar.rating}/5'), + ...List.generate( + widget.komentar.rating, + (number) => Icon( + Icons.star, + color: Colors.yellow, + )) + ], + ) + ], + ), + ), + Container( + key: Key('Komentar'), + padding: EdgeInsets.symmetric(vertical: regularSpace), + child: Text( + 'Komentar', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.w800), + )), + StreamBuilder( + stream: _bloc.komentarPostingListStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + switch (snapshot.data.status) { + case Status.LOADING: + return Center( + child: CircularProgressIndicator( + valueColor: + AlwaysStoppedAnimation(greenPrimary), + ), + ); + break; + case Status.COMPLETED: + allKomentarPostingFromApi = + snapshot.data.data.allKomentar; + if (allKomentarPostingFromApi.isEmpty) { + return Center(child: Text('Tidak ada Komentar')); + } else { + return Column( + children: allKomentarPostingFromApi + .map((k) => komentarPlaceHolder( + k.creator, k.date_time, k.deskripsi)) + .toList()); + } + break; + case Status.ERROR: + return Center( + child: Text(snapshot.data.data.toString()), + ); + break; + } + } + return Container(); + }), + Container( + key: Key("tambah komentar"), + padding: EdgeInsets.only(top: doubleSpace), + alignment: Alignment.center, + child: ButtonTheme( + minWidth: double.infinity, + height: 40, + child: RaisedButton( + padding: EdgeInsets.symmetric(vertical: 15), + highlightElevation: 0.0, + splashColor: greenPrimary, + highlightColor: Colors.white, + elevation: 0.0, + color: greenPrimary, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + child: Text( + "Tambah Komentar", + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontWeight: FontWeight.bold), + ), + onPressed: () { + checkLoginStatus(); + }, + ), + )), + ], + ), + ), + ), + ); + } + + _createTagContainer(String tag) { + return Container( + key: Key('tag-$tag'), + padding: EdgeInsets.all(smallSpace), + margin: EdgeInsets.all(smallSpace), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: regularBorderRadius, + border: Border.all(color: greenPale), + boxShadow: regularShadow), + child: Text( + '#$tag', + style: TextStyle( + fontWeight: FontWeight.w800, fontSize: 16, color: greenPrimary), + ), + ); + } + + checkLoginStatus() async { + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + if (sharedPreferences.getString("token") == null) { + await Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (BuildContext context) => Login()), + (Route route) => false); + } else { + await Navigator.of(context) + .push(MaterialPageRoute( + builder: (BuildContext context) => AddKomentar(widget.komentar))) + .then(_bloc.fetchKomentarPostingList( + widget.komentar.nama_lokasi, widget.komentar.id)); + } + } + + komentarPlaceHolder(String nama, DateTime date, String description) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + CircleAvatar( + backgroundColor: greenPrimary, + child: Text('Test'), + ), + Padding( + padding: const EdgeInsets.all(regularSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + nama, + style: TextStyle(fontSize: 18), + ), + Text('${DateFormat('dd MMMM yyy hh:mm').format(date)}', + style: TextStyle(color: grayPrimary, fontSize: 16)) + ], + ), + ) + ], + ), + Container( + margin: EdgeInsets.only(bottom: regularSpace), + child: Text(description)), + Divider( + color: grayPrimary, + ) + ], + ); + } + + saveLikeDislike(String operation) async { + String namaTempat = widget.komentar.nama_lokasi.replaceAll(" ", "%20"); + String idString = widget.komentar.id.toString(); + print( + 'http://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/like-fasilitas/$namaTempat/$idString/$operation/'); + var response = await NetworkInterface().put( + url: + 'https://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/like-fasilitas/$namaTempat/$idString/$operation/', + ); + if (response['response'] == "You have successfuly like this facility") { + likeSuccess(context); + } else if (response['response'] == + "You have successfuly dislike this facility") { + dislikeSuccess(context); + } else { + likeDislikeFailed(context); + } + } + + void likeSuccess(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: greenPrimary, + title: Text( + 'Like komentar berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + void dislikeSuccess(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: greenPrimary, + title: Text( + 'Dislike komentar berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + void likeDislikeFailed(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: redPrimary, + title: Text( + 'Like atau dislike komentar tidak berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(Icons.close), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + updateLike(String operation) async { + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + if (sharedPreferences.getString("token") == null) { + await Navigator.of(context).pushAndRemoveUntil( + MaterialPageRoute(builder: (BuildContext context) => Login()), + (Route route) => false); + } else { + saveLikeDislike(operation); + } + } + + updateInformasi() async { + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + if(sharedPreferences.getString("token") == null) { + await Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (BuildContext context) => Login()), (Route route) => false); + } + else { + await Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => UpdateInformasi( + komentar: widget.komentar + ))); + } + } + +} + diff --git a/lib/page/informasi/detailSekolah.dart b/lib/page/informasi/detailSekolah.dart new file mode 100644 index 0000000000000000000000000000000000000000..747c24dca85ab83b8d18a9cd8d6f78a96f753148 --- /dev/null +++ b/lib/page/informasi/detailSekolah.dart @@ -0,0 +1,268 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/component/bisago_drawer.dart'; +import 'package:ppl_disabilitas/component/informasi_sekolah_appbar.dart'; +import 'package:ppl_disabilitas/config/strings.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:share/share.dart'; + +class DetailSekolah extends StatefulWidget { + final String namaSekolah; + final String alamat; + final String nomerTelpon; + final String website; + final String jumlahSiswa; + final String status; + final String jenisSekolah; + final String akreditasi; + + DetailSekolah(this.namaSekolah, this.alamat, this.nomerTelpon, this.website, + this.jumlahSiswa, this.status, this.jenisSekolah, this.akreditasi); + + @override + DetailSekolahState createState() => DetailSekolahState(); +} + +class DetailSekolahState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + drawer: BisaGoDrawer(), + appBar: PreferredSize( + preferredSize: Size.fromHeight(55), + child: InformasiSekolahAppBar(), + ), + body: ListView( + children: [ + Container( + padding: EdgeInsets.only( + top: tripleSpace, + bottom: tripleSpace, + right: doubleSpace, + left: doubleSpace), + child: Text(widget.namaSekolah, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + )), + ), + Container( + padding: EdgeInsets.all(doubleSpace), + margin: EdgeInsets.only( + bottom: doubleSpace, left: doubleSpace, right: doubleSpace), + decoration: BoxDecoration( + border: + Border.all(width: 2, color: greenPrimary.withOpacity(0.4)), + borderRadius: regularBorderRadius, + color: Colors.white, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.only(bottom: regularSpace), + child: Text( + "Alamat", + style: TextStyle( + fontSize: 22, + color: greenPrimary, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + child: Text( + widget.alamat, + style: TextStyle( + fontSize: 18, + color: Colors.black, + fontFamily: 'Muli'), + ), + ), + Divider( + color: greenPrimary.withOpacity(0.4), + thickness: 2, + ), + Container( + margin: EdgeInsets.only( + bottom: regularSpace, top: regularSpace), + child: Text( + "Nomor Telepon", + style: TextStyle( + fontSize: 22, + color: greenPrimary, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + child: Text( + widget.nomerTelpon, + style: TextStyle( + fontSize: 18, + color: Colors.black, + fontFamily: 'Muli'), + ), + ), + Divider( + color: greenPrimary.withOpacity(0.4), + thickness: 2, + ), + Container( + margin: EdgeInsets.only( + bottom: regularSpace, top: regularSpace), + child: Text( + "Website", + style: TextStyle( + fontSize: 22, + color: greenPrimary, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + child: Text( + widget.website, + style: TextStyle( + fontSize: 18, + color: Colors.black, + fontFamily: 'Muli'), + ), + ), + Divider( + color: greenPrimary.withOpacity(0.4), + thickness: 2, + ), + Container( + margin: EdgeInsets.only( + bottom: regularSpace, top: regularSpace), + child: Text( + "Jumlah Siswa", + style: TextStyle( + fontSize: 22, + color: greenPrimary, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + child: Text( + widget.jumlahSiswa, + style: TextStyle( + fontSize: 18, + color: Colors.black, + fontFamily: 'Muli'), + ), + ), + Divider( + color: greenPrimary.withOpacity(0.4), + thickness: 2, + ), + Container( + margin: EdgeInsets.only( + bottom: regularSpace, top: regularSpace), + child: Text( + "Status", + style: TextStyle( + fontSize: 22, + color: greenPrimary, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + child: Text( + STATUS_SEKOLAH_REVERSED[widget.status], + style: TextStyle( + fontSize: 18, + color: Colors.black, + fontFamily: 'Muli'), + ), + ), + Divider( + color: greenPrimary.withOpacity(0.4), + thickness: 2, + ), + Container( + margin: EdgeInsets.only( + bottom: regularSpace, top: regularSpace), + child: Text( + "Jenis Sekolah", + style: TextStyle( + fontSize: 22, + color: greenPrimary, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + child: Text( + JENIS_REVERSED[widget.jenisSekolah], + style: TextStyle( + fontSize: 18, + color: Colors.black, + fontFamily: 'Muli'), + ), + ), + Divider( + color: greenPrimary.withOpacity(0.4), + thickness: 2, + ), + Container( + margin: EdgeInsets.only( + bottom: regularSpace, top: regularSpace), + child: Text( + "Akreditasi", + style: TextStyle( + fontSize: 22, + color: greenPrimary, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + Container( + margin: EdgeInsets.only(bottom: smallSpace), + child: Text( + widget.akreditasi, + style: TextStyle( + fontSize: 18, + color: Colors.black, + fontFamily: 'Muli'), + ), + ), + ], + ), + ), + InkWell( + onTap: () { + Share.share( + '${widget.namaSekolah} \n\n${widget.alamat} \n${widget.nomerTelpon} \n${widget.website} \nDibagikan dari bisaGo'); + }, + child: Container( + margin: EdgeInsets.all(regularSpace), + padding: EdgeInsets.symmetric(vertical: doubleSpace), + decoration: BoxDecoration( + boxShadow: regularShadow, + borderRadius: regularBorderRadius, + color: greenPrimary), + child: Center( + child: Text( + 'Bagikan', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w800, + fontSize: 18), + )), + ), + ) + ], + )); + } +} diff --git a/lib/page/informasi/layananDisabilitas.dart b/lib/page/informasi/layananDisabilitas.dart new file mode 100644 index 0000000000000000000000000000000000000000..4e828881a2a13adfd3cb6972faaff0147500453b --- /dev/null +++ b/lib/page/informasi/layananDisabilitas.dart @@ -0,0 +1,133 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/component/bisago_appbar.dart'; +import 'package:ppl_disabilitas/component/bisago_drawer.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/page/informasi/list_sekolah.dart'; +import 'package:ppl_disabilitas/page/registrasi_penyandang_disabilitas/registrasiInformasiLayananDisabilitas.dart'; + +class LayananDisabilitas extends StatefulWidget { + @override + _LayananDisabilitasState createState() => _LayananDisabilitasState(); +} + +class _LayananDisabilitasState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: PreferredSize( + preferredSize: Size.fromHeight(55), + child: BisaGoAppBar(), + key: Key("Scaffold Text Field"), + ), + drawer: BisaGoDrawer(), + body: Container( + padding: EdgeInsets.only( + top: tripleSpace, right: doubleSpace, left: doubleSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Flexible( + child: Text( + 'Informasi Layanan Disabilitas', + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + ), + ), + Container( + margin: EdgeInsets.only(top: tripleSpace, bottom: doubleSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: SizedBox( + width: double.infinity, + child: FlatButton( + color: Colors.white, + textColor: Colors.black, + disabledColor: Colors.grey, + disabledTextColor: Colors.black, + padding: EdgeInsets.all(regularBiggerSpace), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide( + width: 2, color: greenPrimary.withOpacity(0.4))), + //splashColor: Colors.lightGreen, + onPressed: () { + _navigateToRegistrasiDisabilitasPage(context); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + padding: EdgeInsets.only(right: regularSpace), + child: Icon(Icons.add_box, + color: greenPrimary, size: 30)), + Flexible( + child: Text( + "Registrasi Penyandang Disabilitas", + style: TextStyle(fontSize: 20), + ), + ), + Icon(Icons.chevron_right, color: greenPrimary, size: 30), + ], + ), + ), + ), + ), + Container( + margin: EdgeInsets.only(bottom: doubleSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: SizedBox( + width: double.infinity, + child: FlatButton( + color: Colors.white, + textColor: Colors.black, + disabledColor: Colors.grey, + disabledTextColor: Colors.black, + padding: EdgeInsets.all(regularBiggerSpace), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide( + width: 2, color: greenPrimary.withOpacity(0.4))), + //splashColor: Colors.lightGreen, + onPressed: () { + _navigateToListSekolahPage(context); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Container( + padding: EdgeInsets.only(right: regularSpace), + child: + Icon(Icons.info, color: greenPrimary, size: 30)), + Flexible( + child: Text( + "Informasi Sekolah dengan Dukungan Disabilitas", + style: TextStyle(fontSize: 20), + ), + ), + Icon(Icons.chevron_right, color: greenPrimary, size: 30), + ], + ), + ), + ), + ), + ], + ), + ), + ); + } + + void _navigateToListSekolahPage(BuildContext context) { + final route = MaterialPageRoute(builder: (_) => ListSekolah()); + Navigator.of(context).push(route); + } + + void _navigateToRegistrasiDisabilitasPage(BuildContext context) { + final route = MaterialPageRoute(builder: (_) => RegistrasiInformasiLayananDisabilitas()); + Navigator.of(context).push(route); + } +} diff --git a/lib/page/informasi/list_sekolah.dart b/lib/page/informasi/list_sekolah.dart new file mode 100644 index 0000000000000000000000000000000000000000..7f3c8a85039e21f71866a8e48a9ae4d12ba06168 --- /dev/null +++ b/lib/page/informasi/list_sekolah.dart @@ -0,0 +1,654 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/bloc/SekolahBloc.dart'; +import 'package:ppl_disabilitas/component/bisago_drawer.dart'; +import 'package:flutter/widgets.dart'; +import 'package:ppl_disabilitas/config/strings.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/model/sekolah.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/page/informasi/detailSekolah.dart'; + +class ListSekolah extends StatefulWidget { + @override + _ListSekolahState createState() => _ListSekolahState(); +} + +class _ListSekolahState extends State { + var showKecamatan = true; + var showKategoriSekolah = false; + var showTingkatSekolah = false; + + List kecamatan = [ + 'Beji', + 'Bojongsari', + 'Cilodong', + 'Cimanggis', + 'Cinere', + 'Cipayung', + 'Limo', + 'Pancoran Mas', + 'Sawangan', + 'Sukmajaya', + 'Tapos', + 'Jagakarsa' + ]; + Map kecamatanValues = { + 'Beji': true, + 'Bojongsari': true, + 'Cilodong': true, + 'Cimanggis': true, + 'Cinere': true, + 'Cipayung': true, + 'Limo': true, + 'Pancoran Mas': true, + 'Sawangan': true, + 'Sukmajaya': true, + 'Tapos': true, + 'Jagakarsa': true + }; + List tingkatSekolah = [ + 'SD', + 'SMP/SLTP', + 'SMA/SLTA', + 'Perguruan Tinggi', + ]; + Map tingkatSekolahValues = { + 'SD': true, + 'SMP/SLTP': true, + 'SMA/SLTA': true, + 'Perguruan Tinggi': true, + }; + List kategoriSekolah = [ + 'Inklusi', + 'Segregasi' + ]; + Map kategoriSekolahValues = { + 'Inklusi': true, + 'Segregasi': true + }; + + + List sekolah = []; + + /// BLoC for sekolah + SekolahBloc _bloc = SekolahBloc(); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.white, + drawer: BisaGoDrawer(), + body: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Padding( + padding: EdgeInsets.only( + top: tripleSpace, left: doubleSpace, right: doubleSpace), + child: Text( + "Sekolah dengan Dukungan Disabilitas", + style: TextStyle( + fontSize: 25, + fontFamily: 'Muli', + fontWeight: FontWeight.w800), + ), + ), + ), + Container( + padding: EdgeInsets.only(bottom: smallSpace), + margin: EdgeInsets.only(left: doubleSpace, right: doubleSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: FlatButton( + key: Key('FilterButton'), + color: Colors.green[700], + textColor: Colors.white, + disabledColor: Colors.grey, + disabledTextColor: Colors.black, + padding: EdgeInsets.all(8), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.transparent)), + splashColor: Colors.lightGreen, + onPressed: () => { + showModalBottomSheet( + context: context, + builder: (context) => InsideFilter(), + backgroundColor: Colors.transparent, + isScrollControlled: true), + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.filter_list, color: Colors.white, size: 20), + Text( + "Filter Pencarian", + style: TextStyle(fontSize: 13), + ), + ], + ), + ), + ), + StreamBuilder>( + stream: _bloc.sekolahListStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + switch (snapshot.data.status) { + case Status.LOADING: + return Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(greenPrimary), + ), + ); + break; + case Status.COMPLETED: + sekolah = snapshot.data.data.allSekolah; + return makeLokasiWidget("api", sekolah); + break; + case Status.ERROR: + return Center( + child: Text(snapshot.data.data.toString()), + ); + break; + } + } + return Container(); + }, + ), + ], + ), + ), + appBar: AppBar( + elevation: 15, + key: Key("appbar-text-informasi-sekolah"), + backgroundColor: greenPrimary, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, size: 20), + key: Key('Back Icon Key'), + onPressed: () => Navigator.pop(context, 'Take me back')), + centerTitle: true, + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.all(doubleSpace), + child: Text( + "Informasi Sekolah", + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), + ), + ) + ], + ), + ), + ); + } + + Widget makeLokasiWidget( + String key, List sekolah) { + return ListView.builder( + shrinkWrap: true, + itemCount: sekolah.length, + itemBuilder: (context, index) { + return InkWell( + key: Key("$key-${sekolah[index].name}"), + onTap: () {_navigateToDetailSekolahPage(context, sekolah[index]);}, + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + border: Border(bottom: BorderSide(color: Colors.grey[400]))), + margin: EdgeInsets.only(left: doubleSpace, right: doubleSpace), + height: 90, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + + CircleAvatar( + backgroundColor: greenPrimary, + child: Text('Test'), + ), + Expanded( + child: Container( + padding: EdgeInsets.all(doubleSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + sekolah[index].name, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + Text( + sekolah[index].alamat, + overflow: TextOverflow.ellipsis, + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 15, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + + ], + ), + ), + ), + Icon( + Icons.arrow_forward_ios, + color: Colors.grey[400], + size: 20, + ) + ], + ), + ), + ); + }); + + } + + InsideFilter() { + return StatefulBuilder( + builder: (context, setStateModal) => Container( + height: MediaQuery.of(context).size.height / 2, + decoration: BoxDecoration( + boxShadow: regularShadow, + borderRadius: BorderRadius.all( + Radius.circular(10) // <--- border radius here + ), + color: Colors.white, + ), + child: Container( + child: Column( + children: [ + Container( + padding: EdgeInsets.all(regularBiggerSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + Icon(Icons.filter_list), + Container( + margin: EdgeInsets.only(left: regularSpace), + child: Text( + 'Filter Pencarian', + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w800, + fontSize: 20.0), + ), + ), + ], + ), + Row( + children: [ + Text( + 'BATAL', + style: TextStyle( + color: Colors.black, + fontWeight: FontWeight.w800, + fontSize: 17), + ), + ], + ), + ], + ), + ), + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide(color: greenPrimary, width: 1.5))), + ), + Expanded( + child: Container( + child: Row( + children: [ + Expanded( + flex: 1, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + ), + child: ListView( + children: [ + InkWell( + child: Container( + decoration: BoxDecoration( + color: greenPale, + ), + padding: EdgeInsets.only( + left: regularSpace, + right: regularSpace, + top: doubleSpace, + bottom: doubleSpace), + child: Text( + 'Kecamatan', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + splashColor: Colors.green[400], + highlightColor: Colors.green[400], + onTap: () => setStateModal(() { + showKecamatan = true; + showKategoriSekolah = false; + showTingkatSekolah = false; + })), + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: greenPrimary, width: 1.5))), + ), + InkWell( + child: Container( + decoration: BoxDecoration( + color: greenPale, + ), + padding: EdgeInsets.only( + left: regularSpace, + right: regularSpace, + top: doubleSpace, + bottom: doubleSpace), + child: Text( + 'Kategori Sekolah', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + splashColor: Colors.green[400], + highlightColor: Colors.green[400], + onTap: () => setStateModal(() { + showKecamatan = false; + showKategoriSekolah = true; + showTingkatSekolah = false; + })), + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: greenPrimary, width: 1.5))), + ), + InkWell( + child: Container( + decoration: BoxDecoration( + color: greenPale, + ), + padding: EdgeInsets.only( + left: regularSpace, + right: regularSpace, + top: doubleSpace, + bottom: doubleSpace), + child: Text( + 'Tingkat Sekolah', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + splashColor: Colors.green[400], + highlightColor: Colors.green[400], + onTap: () => setStateModal(() { + showKecamatan = false; + showKategoriSekolah = false; + showTingkatSekolah = true; + })), + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide( + color: greenPrimary, width: 1.5))), + ), + ], + ), + ), + ), + Expanded( + flex: 3, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + border: Border( + left: BorderSide(color: greenPrimary, width: 1.5), + ), + ), + child: Stack( + children: [ + IgnorePointer( + ignoring: !showKecamatan, + child: Opacity( + opacity: showKecamatan ? 1 : 0, + child: ListView.builder( + itemCount: kecamatan.length, + itemBuilder: (builder, index) => Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: + greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: kecamatanValues[kecamatan[index]], + onChanged: (bool value) { + _bloc.filterbyKecamatan(kecamatan[index], + value, sekolah); + setStateModal(() { + kecamatanValues[kecamatan[index]] = value; + }); + }, + ), + ), + Text( + kecamatan[index], + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + )), + ), + ), + IgnorePointer( + ignoring: !showKategoriSekolah, + child: Opacity( + opacity: showKategoriSekolah ? 1 : 0, + child: ListView.builder( + itemCount: kategoriSekolah.length, + itemBuilder: (builder, index) => Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: + greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: kategoriSekolahValues[kategoriSekolah[index]], + onChanged: (bool value) { + setStateModal(() { + kategoriSekolahValues[kategoriSekolah[index]] = value; + }); + _bloc.filterbyKategoriSekolah(JENIS[kategoriSekolah[index]], + value, sekolah); + + }, + ), + ), + Text( + kategoriSekolah[index], + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + )), + ), + ), + IgnorePointer( + ignoring: !showTingkatSekolah, + child: Opacity( + opacity: showTingkatSekolah ? 1 : 0, + child: ListView.builder( + itemCount: tingkatSekolah.length, + itemBuilder: (builder, index) => Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: + greenPrimary, + ), + child: Checkbox( + checkColor: greenPrimary, + activeColor: greenPale, + value: tingkatSekolahValues[tingkatSekolah[index]], + onChanged: (bool value) { + _bloc.filterbyKategoriSekolah(tingkatSekolah[index], + value, sekolah); + setStateModal(() { + tingkatSekolahValues[tingkatSekolah[index]] = value; + }); + }, + ), + ), + Text( + tingkatSekolah[index], + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + )), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + Column( + children: [ + Container( + decoration: BoxDecoration( + border: Border( + top: BorderSide(color: greenPrimary, width: 1.5), + )), + ), + Container( + margin: + EdgeInsets.only(left: doubleSpace, right: doubleSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + margin: EdgeInsets.only( + top: regularSpace, bottom: regularSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: SizedBox( + child: FlatButton( + color: redPrimary, + textColor: Colors.white, + padding: EdgeInsets.only( + top: regularBiggerSpace, + bottom: regularBiggerSpace, + left: doubleSpace, + right: doubleSpace), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.transparent)), + splashColor: greenPrimary, + onPressed: () { + /*...*/ + }, + child: Text( + "Hapus Semua", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w400), + ), + ), + ), + ), + Container( + margin: EdgeInsets.only( + top: regularSpace, bottom: regularSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: SizedBox( + child: FlatButton( + color: greenPrimary, + textColor: Colors.white, + padding: EdgeInsets.only( + top: regularBiggerSpace, + bottom: regularBiggerSpace, + left: spaceFourty, + right: spaceFourty), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.transparent)), + splashColor: greenPrimary, + onPressed: () { + /*...*/ + }, + child: Text( + "Terapkan", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w400), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ); + } + + + void _navigateToDetailSekolahPage(BuildContext context, SekolahModel sekolah) { + final route = MaterialPageRoute(builder: (_) => DetailSekolah( + sekolah.name, + sekolah.alamat, + sekolah.no_telp, + sekolah.website, + (sekolah.jumlah_siswa).toString(), + sekolah.status , + sekolah.jenis_sekolah, + sekolah.akreditasi)); + Navigator.of(context).push(route); + } +} diff --git a/lib/page/login/login.dart b/lib/page/login/login.dart new file mode 100644 index 0000000000000000000000000000000000000000..027b3f213c0b3000f91c972d5cc7389a52fc055e --- /dev/null +++ b/lib/page/login/login.dart @@ -0,0 +1,179 @@ +import 'dart:convert'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/page/registrasi/registrasi.dart'; +import 'package:ppl_disabilitas/utils/customButton.dart'; +import 'package:ppl_disabilitas/utils/customTextField.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:http/http.dart' as http; +import 'package:shared_preferences/shared_preferences.dart'; + +class Login extends StatefulWidget { + LoginState createState() => LoginState(); +} + +class LoginState extends State { + final GlobalKey _formKey = GlobalKey(); + + SharedPreferences sharedPreferences; + + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 15, + centerTitle: true, + backgroundColor: greenPrimary, + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.all(doubleSpace), + child: Text( + "bisaGo", + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), + ), + ) + ], + ), + actions: [ + Padding( + padding: EdgeInsets.all(doubleSpace), + child: InkWell( + child: Text( + 'Daftar', + style: TextStyle(fontSize: 15), + ), + onTap: () { + _navigateToRegistrasiPage(context); + }, + ), + ) + ], + ), + body: SingleChildScrollView( + child: Form( + key: _formKey, + child: Center( + child: Container( + margin: EdgeInsets.symmetric(horizontal: doubleSpace), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: doubleSpace), + Text('Masuk ke Akun', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25, + ), + ), + SizedBox(height: doubleSpace), + CustomTextField( + title: 'Nomor Telepon atau Email', + key: Key('Text Field Akun'), + validator: FieldValidator.validateEmail, + controller: emailController, + ), + CustomTextField( + title: 'Password', + key: Key('Text Field Password'), + obsecure: true, + validator: FieldValidator.validatePassword, + controller: passwordController, + ), + Container( + margin: EdgeInsets.fromLTRB(0, tripleSpace, 0, regularSpace), + alignment: Alignment.center, + child: ButtonTheme( + minWidth: double.infinity, + height: 40, + child: submitButton( + 'Masuk', _validateLoginInput), + ) + ), + Container( + child: separator('Atau masuk dengan', 1), + ), + Container( + margin: EdgeInsets.fromLTRB(0, regularSpace, 0, tripleSpace), + alignment: Alignment.center, + child: googleButton(), + ), + ], + ), + ), + )))); + } + + void _validateLoginInput() async { + final FormState form = _formKey.currentState; + if (_formKey.currentState.validate()) { + form.save(); + login(emailController.text, passwordController.text); + } + } + + TextEditingController emailController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + + login(String email, String password) async { + Map data = {'username': email, 'password': password}; + + sharedPreferences = await SharedPreferences.getInstance(); + var response = await http.post('http://poipole-staging.herokuapp.com/api-token-auth/', body: data); + if(response.statusCode == 200) { + successDialog(context); + + Map tokenMap = jsonDecode(response.body); + setState(() { + sharedPreferences.setString("token", tokenMap['token']); + + sharedPreferences.setString("email", email); + + Navigator.pushNamed(context, '/'); + }); + } + else { + failedDialog(context); + print(response.body); + } + } + + void _navigateToRegistrasiPage(BuildContext context) { + final route = MaterialPageRoute(builder: (_) => Registrasi()); + Navigator.of(context).push(route); + } + + void successDialog(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Login berhasil!'), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } + + void failedDialog(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Password atau kata sandi anda salah'), + content: Icon(FontAwesomeIcons.exclamationCircle), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } +} \ No newline at end of file diff --git a/lib/page/pencarian/pencarian.dart b/lib/page/pencarian/pencarian.dart new file mode 100644 index 0000000000000000000000000000000000000000..01b4a268f7aa29b9f4b85c6523a07d7874a6f9c8 --- /dev/null +++ b/lib/page/pencarian/pencarian.dart @@ -0,0 +1,281 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/bloc/LokasiResponseBloc.dart'; +import 'package:ppl_disabilitas/component/ImageHolder.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/model/lokasi.dart'; +import 'package:ppl_disabilitas/network/data/network_model.dart'; +import 'package:ppl_disabilitas/page/filter_fasilitas/fasilitas.dart'; + +/// Create Pencarian page widget with a state +class Pencarian extends StatefulWidget { + @override + PencarianState createState() => PencarianState(); +} + +/// State of Pencacrian page +class PencarianState extends State { + /// Controller for textFormField + TextEditingController myController = TextEditingController(); + + /// Search Icon for textFormField + Icon searchIcon = Icon(Icons.search); + + /// Text for appbar + Widget appBarText = Text('Pencarian Lokasi'); + + /// List of places currently searched on the textFormField + List currentSearch = []; + + /// List for places from API + List places = []; + + /// BLoC for pencarian + LokasiResponseBloc _bloc = LokasiResponseBloc(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('places', places)) + ..add(DiagnosticsProperty('currentSearch', currentSearch)); + } + + @override + void initState() { + myController.addListener(() { + List tempList = []; + for (int i = 0; i < places.length; i++) { + if (myController.text.isNotEmpty) { + if (places[i] + .name + .toLowerCase() + .contains(myController.text.toLowerCase())) { + tempList.add(places[i]); + } + } + } + setState(() { + // print(places); + // print(places[0].nama); + currentSearch = tempList; + }); + }); + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: greenPrimary, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, size: 25), + key: Key('Back Icon Key'), + onPressed: () => Navigator.pop(context, 'Take me back')), + title: Container( + margin: EdgeInsets.only(top: doubleSpace, bottom: doubleSpace), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: doubleBorderRadius, + boxShadow: regularShadow), + child: TextFormField( + controller: myController, + key: Key('Text Field Mau Kemana'), + decoration: InputDecoration( + contentPadding: EdgeInsets.all(0), + isDense: false, + prefixIcon: Icon( + Icons.search, + color: greenPrimary, + size: 25, + ), + border: InputBorder.none, + fillColor: Colors.white, + labelText: 'Kamu mau kemana?', + labelStyle: TextStyle( + color: greenPrimary, + fontSize: 18, + fontFamily: 'Muli', + fontWeight: FontWeight.w700), + suffixIcon: IconButton( + icon: Icon( + Icons.mic, + color: greenPrimary, + size: 25, + ), + onPressed: () {}, + )), + ), + ), + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StreamBuilder>( + stream: _bloc.recentSearchStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + switch (snapshot.data.status) { + case Status.LOADING: + return Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(greenPrimary), + ), + ); + break; + case Status.COMPLETED: + final recentSearch = snapshot.data.data; + Widget displayWidget; + if (recentSearch.listLokasi.isEmpty) { + displayWidget = Center( + child: Text("Anda belum pernah melakukan pencarian")); + } else { + displayWidget = makeLokasiWidget( + "history", recentSearch.listLokasi.take(3).toList()); + } + return Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + margin: EdgeInsets.all(doubleSpace), + child: Text( + "Pencarian terdahulu", + style: + TextStyle(fontFamily: 'Muli', fontSize: 15), + )), + Flexible(child: displayWidget), + ], + )); + break; + case Status.ERROR: + return Center( + child: Text("${snapshot.data.status}"), + ); + break; + } + } + return Container(); + }, + ), + Container( + margin: EdgeInsets.only( + left: doubleSpace, top: regularSpace, bottom: smallSpace), + child: Text("Hasil Pencarian"), + ), + StreamBuilder>( + stream: _bloc.lokasiListStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + switch (snapshot.data.status) { + case Status.LOADING: + return Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(greenPrimary), + ), + ); + break; + case Status.COMPLETED: + places = snapshot.data.data.listLokasi; + return Expanded( + flex: 2, + child: currentSearch.isEmpty + ? Center(child: Text('Cari lokasi')) + : makeLokasiWidget("api", currentSearch)); + break; + case Status.ERROR: + return Center( + child: Text(snapshot.data.data.toString()), + ); + break; + } + } + return Container(); + }, + ), + ], + ), + ); + } + + Widget makeLokasiWidget(String key, List places) { + return ListView.builder( + shrinkWrap: true, + itemCount: places.length, + itemBuilder: (context, index) { + return InkWell( + key: Key("$key-${places[index].name}"), + onTap: () { + _bloc.saveRecentSearch(places[index]); + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => Fasilitas( + alamat: places[index].alamat, + nama: places[index].name, + telpon: places[index].no_telp, + url: places[index].image, + id: places[index].id, + ))).then((value) => _bloc.fetchRecentSearch()); + }, + child: Container( + decoration: BoxDecoration( + color: Colors.transparent, + border: Border(bottom: BorderSide(color: Colors.grey[400]))), + margin: EdgeInsets.only(left: doubleSpace, right: doubleSpace), + height: 90, + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + children: [ + CircleAvatar( + backgroundColor: greenPrimary, + child: ImageHolder(url: places[index].image,), + ), + Expanded( + child: Container( + padding: EdgeInsets.all(doubleSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + places[index].name, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + overflow: TextOverflow.ellipsis, + ), + Text( + places[index].alamat, + style: TextStyle( + fontSize: 15, + color: Colors.black, + fontFamily: 'Muli', + ), + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + ), + ], + ), + ), + Icon( + Icons.arrow_forward_ios, + color: Colors.grey[400], + size: 20, + ) + ], + ), + ), + ); + }); + } +} diff --git a/lib/page/registrasi/registrasi.dart b/lib/page/registrasi/registrasi.dart new file mode 100644 index 0000000000000000000000000000000000000000..6e209fde698e712c5c12f74676063c5bf7ca7189 --- /dev/null +++ b/lib/page/registrasi/registrasi.dart @@ -0,0 +1,205 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; +import 'package:ppl_disabilitas/utils/customButton.dart'; +import 'package:ppl_disabilitas/utils/customTextField.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:http/http.dart' as http; + +class Registrasi extends StatefulWidget { + RegistrasiState createState() => RegistrasiState(); +} + +class RegistrasiState extends State { + final GlobalKey _formKey = GlobalKey(); + + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 15, + centerTitle: true, + backgroundColor: greenPrimary, + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding(padding: EdgeInsets.all(doubleSpace), + child: Text( + "bisaGo", + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), + ), + ) + ], + ), + actions: [ + Padding( + padding: EdgeInsets.all(doubleSpace), + child: InkWell( + child: Text( + 'Login', + style: TextStyle(fontSize: 15), + ), + onTap: () { + Navigator.pop(context); + }, + ), + ) + ], + ), + body: SingleChildScrollView( + child: Form( + key: _formKey, + child: Center( + child: Container( + margin: EdgeInsets.symmetric(horizontal: doubleSpace), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: doubleSpace), + Text('Daftar Akun Baru', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25, + ), + ), + SizedBox(height: doubleSpace), + CustomTextField( + title: 'Nama Lengkap', + key: Key('Text Field Nama'), + validator: FieldValidator.validateName, + controller: nameController, + ), + CustomTextField( + title: 'Nomor Telepon', + key: Key('Text Field Nomor Telepon'), + validator: FieldValidator.validatePhoneNumber, + controller: phoneController, + ), + CustomTextField( + title: 'Email', + key: Key('Text Field Email'), + controller: emailController, + validator: FieldValidator.validateEmail, + ), + CustomTextField( + title: 'Password', + key: Key('Text Field Password'), + obsecure: true, + validator: FieldValidator.validatePassword, + controller: passwordController, + ), + CustomTextField( + title: 'Konfirmasi Password', + key: Key('Text Field Konfirmasi Password'), + obsecure: true, + validator: (input) { + if (input != passwordController.text) { + return '*Password tidak sesuai. Coba lagi'; + } + return null; + }, + ), + Container( + margin: EdgeInsets.fromLTRB(0, tripleSpace, 0, regularSpace), + alignment: Alignment.center, + child: ButtonTheme( + minWidth: double.infinity, + height: 40, + child: submitButton('Daftar', _validateLoginInput), + ) + ), + Container( + child: separator('Atau daftar dengan', 1), + ), + Container( + margin: EdgeInsets.fromLTRB(0, regularSpace, 0, tripleSpace), + alignment: Alignment.center, + child: googleButton(), + ), + ], + ), + ), + ), + ), + ), + ); + } + + void _validateLoginInput() async { + final FormState form = _formKey.currentState; + if (_formKey.currentState.validate()) { + form.save(); + await createUser(nameController.text.toString(), phoneController.text.toString(), + emailController.text.toString(), passwordController.text.toString()); + } + } + + TextEditingController nameController = TextEditingController(); + TextEditingController phoneController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + + createUser(String name, String phone_number, String email, String password) async { + Map data = { + 'name' : name, + 'phone_number' : phone_number, + 'email' : email, + 'password' : password, + }; + final response = await http.post( + "http://poipole-staging.herokuapp.com/api/register/", +// headers: {"Content-Type": "application/json"}, + body: data, + ); + print(response.statusCode); + if (response.statusCode == 201) { + successDialog(context); + Timer(Duration(seconds: 2), () { + _navigateToDashboard(context); + }); + } else { + failedDialog(context); + } + } + + void successDialog(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Registrasi berhasil! \nCek email anda untuk konfirmasi.'), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } + + void _navigateToDashboard(BuildContext context) { + final route = MaterialPageRoute(builder: (_) => Dashboard()); + Navigator.of(context).push(route); + } + + void failedDialog(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Pengguna sudah terdaftar!'), + content: Icon(FontAwesomeIcons.exclamationCircle), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } +} + diff --git a/lib/page/registrasi_penyandang_disabilitas/registrasiInformasiLayananDisabilitas.dart b/lib/page/registrasi_penyandang_disabilitas/registrasiInformasiLayananDisabilitas.dart new file mode 100644 index 0000000000000000000000000000000000000000..8eeed7ff20aa5a516d712a27e049ad67332f2416 --- /dev/null +++ b/lib/page/registrasi_penyandang_disabilitas/registrasiInformasiLayananDisabilitas.dart @@ -0,0 +1,571 @@ + +import 'dart:io'; + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_datetime_picker/flutter_datetime_picker.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:intl/intl.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; +import 'package:ppl_disabilitas/utils/customTextField.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; + + +class RegistrasiInformasiLayananDisabilitas extends StatefulWidget { + @override + _RegistrasiInformasiLayananDisabilitasState createState() => + _RegistrasiInformasiLayananDisabilitasState(); +} + +class _RegistrasiInformasiLayananDisabilitasState + extends State { + _RegistrasiInformasiLayananDisabilitasState(); + Map data = { + 'name':'', + 'alamat':'', + 'tempat_lahir': '', + 'jenis_kelamin': '', + 'pendidikan':'', + 'pekerjaan':'', + 'kategori': '', + 'no_telp': '', + 'email': '', + 'nama_wali': '', + 'alamat_wali': '', + 'telp_wali': '' + }; + //get isSelected => null; + final GlobalKey _formKey = GlobalKey(); + final List _dropdownValues = [ + "Laki - Laki", + "Perempuan" + ]; + final sexInitial = [ + "LAKI-LAKI", + 'PEREMPUAN' + ]; + String showSex = 'Pilih salah satu'; + String showPendidikan = 'Pilih salah satu'; + String showPekerjaan = 'Pilih salah satu'; + String showKategori = 'Pilih salah satu'; + final List _dropdownValues2 = [ + "SD", + "SMP/SLTP", + "SMA/SLTA", + "D1", + "D2", + "D3", + "S1", + "S2", + "S3", + "Non Formal", + "Tidak Sekolah" + ]; + final List pendidikanInitial = [ + "SD", + "MP", + "MA", + "D1", + "D2", + "D3", + "S1", + "S2", + "S3", + "NF", + "NA" + ]; + final List _dropdownValues3 = [ + "Fisik", + "Intelektual", + "Mental", + "Sensorik" + ]; + final List kategoriInitial = [ + 'FS', + 'IN', + 'MN', + 'SN' + ]; + final pekerjaanList = [ + 'Petani', + 'Buruh', + 'Pedagang/Wiraswasta', + 'Jasa', + 'PNS/TNI/POLRI', + 'Pensiunan', + 'Ibu Rumah Tangga', + 'Pelajar', + 'Lainnya', + 'Tidak Bekerja' + ]; + final List pekerjaanInitial = [ + 'PT', + 'BR', + 'WS', + 'JS', + 'PN', + 'SN', + 'IR', + 'PL', + 'LA', + 'NA' + ]; + String tanggalLahir = 'Pilih tanggal lahir'; + + @override + Widget build(BuildContext context) { + //final List isSelected; + + return Scaffold( + appBar: AppBar( + elevation: 15, + backgroundColor: greenPrimary, + leading: IconButton( + icon: Icon(Icons.arrow_back_ios, size: 20), + key: Key('Back Icon Key'), + onPressed: () => Navigator.pop(context, 'Take me back')), + centerTitle: true, + key: _formKey, + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: EdgeInsets.only( + top: regularBiggerSpace, + bottom: regularBiggerSpace, + left: spaceFourty, + right: spaceFourty), + child: Text( + "bisaGo", + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), + ), + ) + ], + ), + ), + body: SingleChildScrollView( + child: Form( + child: Center( + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 25), + Text( + 'Registrasi Penyandang Disabilitas', + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 25, + ), + ), + SizedBox(height: 20), + CustomTextField( + title: 'Nama Lengkap Penyandang', +// key: Key('Text Field Nomor Telepon'), + controller: namaPenyandangController, + ), + CustomTextField( + title: 'Alamat penyandang', +// key: Key('Text Field Nomor Telepon'), + controller: alamatController, + ), + CustomTextField( + title: 'Tempat Lahir', + //key: Key('Text Field Email'), + controller: ttlController, + validator: FieldValidator.validateTtl, + ), + InkWell( + child: Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('Tanggal Lahir'), + FlatButton( + onPressed: () { + DatePicker.showDatePicker(context, + showTitleActions: true, + maxTime: DateTime.now(), + onChanged: (date) { + setState(() { + tanggalLahir = '${DateFormat('yyyy-MM-dd').format(date)}'; + }); + + }); + }, + child: Text( + tanggalLahir, + style: TextStyle(color: Colors.white), + ), + color: greenPrimary, + ) + ], + )), + Container(height: 5), + Text( + "Jenis Kelamin", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 18, + ), + ), + FormField( + builder: (FormFieldState state) { + return InputDecorator( + decoration: InputDecoration( + contentPadding: EdgeInsets.only( + top: smallSpace, + bottom: smallSpace, + left: smallSpace, + right: smallSpace), + hintText: "pilih salah satu", + //errorStyle: TextStyle(color: Colors.redAccent, fontSize: 16.0), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.0), + ), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + items: _dropdownValues + .map((value) => DropdownMenuItem( + child: Text(value), + value: value, + )) + .toList(), + onChanged: (String value) { + setState(() { + showSex = value; + data['jenis_kelamin'] = sexInitial[_dropdownValues.indexOf(value)]; + print(data); + }); + }, + isExpanded: false, + hint: Text(showSex), + ), + ), + ); + }, + ), + Text( + "Pendidikan Terakhir", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 18, + ), + ), + FormField( + builder: (FormFieldState state) { + return InputDecorator( + decoration: InputDecoration( + contentPadding: EdgeInsets.only( + top: smallSpace, + bottom: smallSpace, + left: smallSpace, + right: smallSpace), + hintText: "pilih salah satu", + //errorStyle: TextStyle(color: Colors.redAccent, fontSize: 16.0), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.0), + ), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + items: _dropdownValues2 + .map((value) => DropdownMenuItem( + child: Text(value), + value: value, + )) + .toList(), + onChanged: (String value) { + setState(() { + showPendidikan = value; + data['pendidikan'] = pendidikanInitial[_dropdownValues2.indexOf(value)]; + print(data); + }); + }, + isExpanded: false, + hint: Text(showPendidikan), + ), + ), + ); + }, + ), + Text( + "Pekerjaan", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 18, + ), + ), + FormField( + builder: (FormFieldState state) { + return InputDecorator( + decoration: InputDecoration( + contentPadding: EdgeInsets.only( + top: smallSpace, + bottom: smallSpace, + left: smallSpace, + right: smallSpace), + hintText: "pilih salah satu", + //errorStyle: TextStyle(color: Colors.redAccent, fontSize: 16.0), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.0), + ), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + items: pekerjaanList + .map((value) => DropdownMenuItem( + child: Text(value), + value: value, + )) + .toList(), + onChanged: (String value) { + setState(() { + showPekerjaan = value; + data['pekerjaan'] = pekerjaanInitial[pekerjaanList.indexOf(value)]; + print(data); + }); + }, + isExpanded: false, + hint: Text(showPekerjaan), + ), + ), + ); + }, + ), + Container(height: 10), + Text( + "Kategori Disabilitas", + textAlign: TextAlign.center, + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 18, + ), + ), + FormField( + builder: (FormFieldState state) { + return InputDecorator( + decoration: InputDecoration( + contentPadding: EdgeInsets.only( + top: smallSpace, + bottom: smallSpace, + left: smallSpace, + right: smallSpace), + hintText: "pilih salah satu", + //errorStyle: TextStyle(color: Colors.redAccent, fontSize: 16.0), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5.0), + ), + ), + child: DropdownButtonHideUnderline( + child: DropdownButton( + items: _dropdownValues3 + .map((value) => DropdownMenuItem( + child: Text(value), + value: value, + )) + .toList(), + onChanged: (String value) { + setState(() { + showKategori = value; + data['kategori'] = kategoriInitial[_dropdownValues3.indexOf(value)]; + print(data); + }); + }, + isExpanded: false, + hint: Text(showKategori), + ), + ), + ); + }, + ), + CustomTextField( + title: 'Nomor Telepon', + controller: phoneController, + ),CustomTextField( + title: 'Email', + controller: emailController, + ), + CustomTextField( + title: 'Nama lengkap orang tua/wali', +// key: Key('Text Field Nama'), + validator: FieldValidator.validateNamaPengisiData, + controller: namaWaliController, + ), + CustomTextField( + title: 'Alamat lengkap orang tua/wali', +// key: Key('Text Field Nama'), +// validator: FieldValidator.validateName, + controller: alamatWaliController, + ), + CustomTextField( + title: 'No. hp orang tua/wali', +// key: Key('Text Field Nama'), + validator: FieldValidator.validateAlamat, + controller: phoneNumbOrtuController, + ), + Container(height: 10), + Container( + margin: + EdgeInsets.only(left: doubleSpace, right: doubleSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + margin: EdgeInsets.only( + top: regularSpace, bottom: regularSpace), + decoration: BoxDecoration(), + child: SizedBox( + child: FlatButton( + color: Colors.transparent, + textColor: Colors.black, + padding: EdgeInsets.only( + top: regularBiggerSpace, + bottom: regularBiggerSpace, + left: doubleSpace, + right: doubleSpace), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.grey)), + splashColor: white, + onPressed: () { + /*...*/ + }, + child: Text( + "Batal", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w400), + ), + ), + ), + ), + Container( + margin: EdgeInsets.only( + top: regularSpace, bottom: regularSpace), + decoration: BoxDecoration(boxShadow: regularShadow), + child: SizedBox( + child: FlatButton( + color: greenPrimary, + textColor: Colors.white, + padding: EdgeInsets.only( + top: regularBiggerSpace, + bottom: regularBiggerSpace, + left: spaceFourty, + right: spaceFourty), + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + side: BorderSide(color: Colors.transparent)), + splashColor: greenPrimary, + onPressed: () { + _validateRegisInput(); + }, + child: Text( + "Simpan", + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w400), + ), + ), + ), + ), + ], + ), + ), + ], + ), + )), + ), + ), + ); + } + + void _validateRegisInput() async { + + await createPenyandang(); + //_showDialog(); + + } + + TextEditingController alamatController = TextEditingController(); + TextEditingController namaPenyandangController = TextEditingController(); + TextEditingController phoneNumbOrtuController = TextEditingController(); + TextEditingController ttlController = TextEditingController(); + TextEditingController phoneController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + TextEditingController namaWaliController = TextEditingController(); + TextEditingController alamatWaliController = TextEditingController(); + + createPenyandang() async { + data['name'] = namaPenyandangController.text; + data['alamat'] = alamatController.text; + data['tempat_lahir'] = ttlController.text; + data['tanggal_lahir'] = tanggalLahir; + data['no_telp'] = phoneController.text; + data['email'] = emailController.text; + data['nama_wali'] = namaWaliController.text; + data['alamat_wali'] = alamatWaliController.text; + data['telp_wali'] = phoneNumbOrtuController.text; + print('data $data'); + final response = await NetworkInterface().post( + url: "https://poipole-staging.herokuapp.com/layanan-khusus/penyandang/register/", + bodyParams: data, + ); + if (response != null) { + inputData(context); + } else { + inputDataFail(context); + } + } + void inputData(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: greenPrimary, + title: Text( + 'Registrasi penyandang disabilitas berhasil', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + + void inputDataFail(BuildContext context) { + var alertDialog = AlertDialog( + backgroundColor: redPrimary, + title: Text( + 'Registrasi tidak berhasil, coba lagi', + style: TextStyle( + color: Colors.white, + fontFamily: 'Muli', + fontWeight: FontWeight.w600, + ), + ), + content: Icon(Icons.close), + ); + showDialog( + context: context, + builder: (BuildContext context) { + return alertDialog; + }); + } + +} diff --git a/lib/page/updateInformasi/updateInformasi.dart b/lib/page/updateInformasi/updateInformasi.dart new file mode 100644 index 0000000000000000000000000000000000000000..e17144562f44820f565451715e65864d2bfb6860 --- /dev/null +++ b/lib/page/updateInformasi/updateInformasi.dart @@ -0,0 +1,319 @@ + import 'dart:io'; +import 'package:http/http.dart' as http; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/utils/customDeskripsiField.dart'; +import 'package:ppl_disabilitas/utils/customButton.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:smooth_star_rating/smooth_star_rating.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + + +class UpdateInformasi extends StatefulWidget{ + final KomentarModel komentar; + UpdateInformasiState createState() => UpdateInformasiState(); + UpdateInformasi({this.komentar}); +} + +class UpdateInformasiState extends State { + var rating = 0.0; + var tag = ''; + TextEditingController deskripsiController = TextEditingController(); + void initState() { + super.initState(); + rating = widget.komentar.rating.toDouble(); + deskripsiController = TextEditingController(text: widget.komentar.deskripsi); + } + File _image; + final GlobalKey _formKey = GlobalKey(); + Map fasilitas = { + 'Kursi Roda': false, + 'Lift Disabilitas': false, + 'Toilet Disabilitas': false, + 'Masjid/Mushola': false, + 'Guiding Block': false, + 'Bidang Miring': false, + 'Teman Disabilitas': false, + 'Juru Bahasa Isyarat': false, + 'Tongkat Disabilitas Netra':false, + 'Kursi Umum Disabilitas': false, + 'Tempat Parkir Disabilitas': false, + 'Running Text': false, + 'Tempat Parkir Biasa' : false, + }; + + + Map tags = { + 'Kursi Roda': 'KD', + 'Lift Disabilitas': 'LF', + 'Toilet Disabilitas': 'TD', + 'Masjid/Mushola': 'MM', + 'Guiding Block': 'GB', + 'Bidang Miring': 'BM', + 'Teman Disabilitas': 'CP', + 'Juru Bahasa Isyarat': 'JI', + 'Tongkat Disabilitas Netra':'TN', + 'Kursi Umum Disabilitas': 'KD', + 'Tempat Parkir Disabilitas': 'PK', + 'Running Text': 'RT', + 'Tempat Parkir Biasa' : 'TB', + }; + + Future _getImage() async { + var image = await ImagePicker.pickImage(source: ImageSource.gallery); + + setState(() { + _image = image; + print('_image : $_image'); + }); + } + Future _clearImage() async { + + setState(() { + _image = null; + print('_image : $_image'); + }); + } + + Future _clearCheckBox() async{ + fasilitas.forEach((k, v) { + var key = k; + fasilitas[key]=false; + }); + } + + + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Ubah Informasi'), + centerTitle: true, + backgroundColor: Color(0xff3A903A), + ), + body: SingleChildScrollView( + child: Form( + key: _formKey, + child: Container( + margin: EdgeInsets.symmetric(horizontal: 20.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 20), + Text("Foto Fasilitas",style: TextStyle(fontSize: 18),textAlign: TextAlign.left,), + GridView.count( + key: Key('Input Gambar'), + shrinkWrap: true, + primary: false, + padding: const EdgeInsets.all(10), + crossAxisSpacing: 10, + crossAxisCount: 2, + children: [ + GestureDetector( + onTap: _getImage, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 2.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20.0), + topRight: Radius.circular(20.0), + bottomLeft: Radius.circular(20.0), + bottomRight: Radius.circular(20.0), + ), + color: Colors.black12, + ), + child: _image == null ? Icon(FontAwesomeIcons.plus) : Image.file(_image), + ), + ) + ], + ), + CustomDeskripsiField( + title: 'Informasi Fasilitas', + key: Key('Text Field Informasi'), + onSaved: (input) { + }, + validator: FieldValidator.validateInfo, + controller: deskripsiController, + ), + SizedBox(height: 20), + Text("Tag Pencarian",style: TextStyle(fontSize: 18),textAlign: TextAlign.left,), + ListView( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + key: Key('Checkbox Fasilitas'), + children: fasilitas.keys.map((String key) { + return CheckboxListTile( + title: Text(key), + value: fasilitas[key], + onChanged: (bool value) { + setState(() { + fasilitas[key] = value; + }); + }, + ); + }).toList(), + ), + SizedBox(height: 20), + Container( + alignment: Alignment.center, + key: Key('Star Rating'), + child: SmoothStarRating( + allowHalfRating: false, + onRatingChanged: (v) { + rating = v; + setState(() {}); + }, + starCount: 5, + rating: rating, + size: 40.0, + filledIconData: Icons.star, + halfFilledIconData: Icons.star_half, + color: Colors.green, + borderColor: Colors.green, + spacing:0.0, + ), + ), + Container( + margin: EdgeInsets.fromLTRB(0, 30, 0, 10), + alignment: Alignment.center, + child: Row( + children: [ + Expanded( + child: ButtonTheme( + key: Key("Batal Button"), + minWidth: double.infinity, + height: 40, + child: RaisedButton( + padding: EdgeInsets.symmetric(vertical: 15), + highlightElevation: 0.0, + splashColor: Color(0xff3A903A), + highlightColor: Color(0xff3A903A), + elevation: 0.0, + color: Colors.white70, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(10)), + side: BorderSide(color: Color(0xff3A903A)) + ), + + child: Text( + 'Batal', + style: TextStyle(fontSize: 20, color: Colors.black, fontWeight: FontWeight.bold), + ), + onPressed: (){ + _resetInput(); + } + + ), + + ), + ), + + SizedBox(width: 5,), + Expanded( + child : ButtonTheme( + key: Key("Simpan Button"), + minWidth: double.infinity, + height: 40, + child: submitButton( + 'Simpan', _validateInformationInput), + ), + + ), + + ], + ), + ), + + ], + ), + ), + + ) + + ) + + + ); + + } + + addInfo(String tag, String deskripsi, String rating) async { + for(MapEntry me in fasilitas.entries) { + if(me.value == true) tag = tag + tags[me.key] + ' '; + } + Map data = { + 'tag': tag, + 'deskripsi': deskripsi, + }; + + SharedPreferences sharedPreferences = await SharedPreferences.getInstance(); + print(data.values); + + String namaTempat = widget.komentar.nama_lokasi.replaceAll(" ", "%20"); + int idFasilitas = widget.komentar.id; + print('http://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/update-fasilitas/$namaTempat/$idFasilitas/'); + var response = await http.put( + 'http://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/update-fasilitas/$namaTempat/$idFasilitas/', + headers: {"Authorization" : "token " + sharedPreferences.getString("token")}, + body: data); + if (response.statusCode == 201 || response.statusCode == 202) { + print(response.body); + inputData(context); + } + else { + print(sharedPreferences.getString("token")); + print(namaTempat); + print(response.statusCode); + print(data); + gagalInputData(context); + } + } + + void inputData(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Update Informasi berhasil'), + content: Icon(FontAwesomeIcons.checkCircle), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } + void gagalInputData(BuildContext context){ + var alertDialog = AlertDialog( + title: Text('Update informasi gagal, pastikan ini adalah info buatan anda'), + ); + showDialog( + context: context, + builder: (BuildContext context){ + return alertDialog; + } + ); + } + + void _validateInformationInput() async { + final FormState form = _formKey.currentState; + if(_formKey.currentState.validate()) { + form.save(); + int ratingInt = rating.toInt(); + await addInfo(tag, deskripsiController.text.toString(), ratingInt.toString()); + } + } + + void _resetInput() async{ + deskripsiController.clear(); + rating = 0.0; + await _clearImage(); + await _clearCheckBox(); + + + } + + + +} \ No newline at end of file diff --git a/lib/repository/KomentarPostingRepository.dart b/lib/repository/KomentarPostingRepository.dart new file mode 100644 index 0000000000000000000000000000000000000000..e00b1cda524bf0d7ad9391d6a3fea7e419629782 --- /dev/null +++ b/lib/repository/KomentarPostingRepository.dart @@ -0,0 +1,30 @@ +import 'package:ppl_disabilitas/model/komentarPosting.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; +class KomentarPostingRepository { + NetworkInterface _network = NetworkInterface(); + + Future fetchKomentarPosting(String namaLokasi, int id) async { + String nama = namaLokasi.replaceAll(" ", "%20"); + String url = "https://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/list-komentar/" + nama + "/" + id.toString(); + print(url); + final response = await _network.get( + url: url, + isLogin: false); + final data = response.values.toList(); + print(data); + return KomentarPostingList( + data.map((komentarPosting) => KomentarPostingModel.fromJson(komentarPosting)).toList()); + } + + addKomentarPosting(String namaLokasi, int id, Map data) async{ + // String nama = namaLokasi.replaceAll(" ", "%20"); + // String idString = id.toString(); + // String url = "https://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/add-komentar/$nama/$idString/"; + // print(url); + // final response = await _network.post(url: url, bodyParams: data, isLogin: true); + // print(response.data); + // return response.data; + } + + +} \ No newline at end of file diff --git a/lib/repository/KomentarRepository.dart b/lib/repository/KomentarRepository.dart new file mode 100644 index 0000000000000000000000000000000000000000..61fb57d7d31f549cf0a793bf57e9277dd87b2549 --- /dev/null +++ b/lib/repository/KomentarRepository.dart @@ -0,0 +1,18 @@ +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; + +class KomentarRepository { + NetworkInterface _network = NetworkInterface(); + + Future fetchKomentar(String namaLokasi) async { + String nama = namaLokasi.replaceAll(" ", "%20"); + String url = + "https://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/list-fasilitas/" + + nama; + final response = await _network.get(url: url, isLogin: false); + final data = response.values.toList().reversed.toList(); + return KomentarList(data + .map((komentar) => KomentarModel.fromJson(komentar)) + .toList()); + } +} diff --git a/lib/repository/LokasiRepository.dart b/lib/repository/LokasiRepository.dart new file mode 100644 index 0000000000000000000000000000000000000000..9b488571f418f63e24be22b3f7eaf4e4b3bdbb8f --- /dev/null +++ b/lib/repository/LokasiRepository.dart @@ -0,0 +1,45 @@ +import 'dart:convert'; + +import 'package:ppl_disabilitas/model/lokasi.dart'; +import 'package:ppl_disabilitas/network/cookies_interface.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; + +class LokasiRepository { + final _network = NetworkInterface(); + final _cookie = CookiesInterface(); + Future fetchLokasi() async { + final response = await _network.get( + url: + 'https://poipole-staging.herokuapp.com/informasi-fasilitas/lokasi/list/', + isLogin: false); + + return LokasiListResponse( + response.map((lokasi) => Lokasi.fromJson(lokasi)).toList()); + } + + Future fetchRecentSearch() async { + var response; + await _cookie + .checkCookieFileAvailability(fileName: "searchhistory") + .then((boolean) async { + if (!boolean) { + response = []; + } else { + try { + await _cookie.getCookieFile(fileName: "searchhistory").then((cookie) { + response = json.decode(cookie); + }); + } on Exception { + response = []; + } + } + }); + return LokasiListResponse( + response.map((lokasi) => Lokasi.fromJson(lokasi)).toList()); + } + + Future saveRecentSearch(Lokasi recentSearch) async { + final searchToMap = recentSearch.toJson(); + await _cookie.createSearchHistoryCookie(recentSearch: searchToMap); + } +} diff --git a/lib/repository/SekolahRepository.dart b/lib/repository/SekolahRepository.dart new file mode 100644 index 0000000000000000000000000000000000000000..ffec6a30b7c84c8b1003dc570eb68aa4e2d9c5d9 --- /dev/null +++ b/lib/repository/SekolahRepository.dart @@ -0,0 +1,14 @@ +import 'package:ppl_disabilitas/model/sekolah.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; + +class SekolahRepository { + NetworkInterface _network = NetworkInterface(); + + Future fetchSekolah() async { + final response = await _network.get( + url: 'https://poipole-staging.herokuapp.com/layanan-khusus/sekolah/list/', + isLogin: false); + return SekolahList( + response.map((sekolah) => SekolahModel.fromJson(sekolah)).toList()); + } +} \ No newline at end of file diff --git a/lib/utils/customButton.dart b/lib/utils/customButton.dart new file mode 100644 index 0000000000000000000000000000000000000000..e873ce7cd75efbb3599b2554327b16935e31e7d7 --- /dev/null +++ b/lib/utils/customButton.dart @@ -0,0 +1,102 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; + +Widget submitButton(String text, void function()) { + return Container( + decoration: BoxDecoration(boxShadow: regularShadow), + child: RaisedButton( + padding: EdgeInsets.symmetric(vertical: 15), + highlightElevation: 0.0, + splashColor: greenPale, + disabledColor: grayPrimary, + disabledTextColor: Colors.black, + elevation: 0.0, + color: greenPrimary, + shape: RoundedRectangleBorder( + borderRadius: regularBorderRadius, + ), + child: Text( + text, + style: TextStyle(fontSize: 20, color: white, fontWeight: FontWeight.bold), + ), + onPressed: () => function(), + ), + ); +} + +Widget separator(String text, double thickness) { + return Row( + children: [ + SizedBox( + width: 20, + ), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10), + child: Divider( + thickness: thickness, + color: Colors.black, + ), + ), + ), + Text(text, + style: TextStyle(fontSize: 12, color: Colors.black)), + Expanded( + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10), + child: Divider( + thickness: thickness, + color: Colors.black, + ), + ), + ), + SizedBox( + width: 20, + ), + ], + ); +} + +Widget googleButton() { + return InkWell( + onTap: () { + }, + child: Container( + decoration: BoxDecoration( + borderRadius: regularBorderRadius, + border: Border.all(color: grayPrimary), + boxShadow: regularShadow, + color: Colors.white, + ), + child: Stack( + children: [ + Container( + padding: EdgeInsets.all(15), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(10), + topLeft: Radius.circular(10)), + ), + child: Image( + image: AssetImage('assets/logo/google.png'), + width: 20.0, + ), + ), + Container( + padding: EdgeInsets.symmetric(vertical: 15), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomRight: Radius.circular(10), + topRight: Radius.circular(10)), + ), + alignment: Alignment.center, + child: Text('Akun Google', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold) + ), + ), + ], + ), + ), + ); +} \ No newline at end of file diff --git a/lib/utils/customDeskripsiField.dart b/lib/utils/customDeskripsiField.dart new file mode 100644 index 0000000000000000000000000000000000000000..9976c23ece6ea36ab7ada86046e660b90f246eb4 --- /dev/null +++ b/lib/utils/customDeskripsiField.dart @@ -0,0 +1,71 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class CustomDeskripsiField extends StatelessWidget { + CustomDeskripsiField( + { this.title, + this.hint, + this.obsecure = false, + this.key, + this.validator, + this.controller, + this.onSaved}); + final String title; + final Key key; + final FormFieldSetter onSaved; + final String hint; + final bool obsecure; + final FormFieldValidator validator; + final TextEditingController controller; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(fontSize: 18), + ), + SizedBox( + height: 10, + ), + TextFormField( + keyboardType: TextInputType.multiline, + maxLines: null, + onSaved: onSaved, + validator: validator, + controller: controller, + autofocus: true, + obscureText: obsecure, + style: TextStyle( + fontSize: 15, + ), + decoration: InputDecoration( + hintStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), + hintText: hint, + contentPadding: EdgeInsets.all(8.0), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: Theme.of(context).primaryColor, + width: 1, + ), + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: Theme.of(context).primaryColor, + width: 1, + ), + ), + ), + ), + + ], + ), + ); + } +} diff --git a/lib/utils/customKomentarField.dart b/lib/utils/customKomentarField.dart new file mode 100644 index 0000000000000000000000000000000000000000..aeaa48e9c3a7bb5b0ee7b4ac0f4dd651651d6a2d --- /dev/null +++ b/lib/utils/customKomentarField.dart @@ -0,0 +1,72 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; + +class CustomKomentarField extends StatelessWidget { + CustomKomentarField( + { this.title, + this.hint, + this.obsecure = false, + this.key, + this.validator, + this.controller, + this.onSaved}); + final String title; + final Key key; + final FormFieldSetter onSaved; + final String hint; + final bool obsecure; + final FormFieldValidator validator; + final TextEditingController controller; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(fontSize: 18), + ), + SizedBox( + height: 10, + ), + TextFormField( + keyboardType: TextInputType.multiline, + maxLines: null, + onSaved: onSaved, + validator: validator, + controller: controller, + autofocus: true, + obscureText: obsecure, + style: TextStyle( + fontSize: 15, + ), + decoration: InputDecoration( + hintStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), + hintText: hint, + contentPadding: EdgeInsets.all(40.0), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: greenPrimary, + width: 1, + ), + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: greenPrimary, + width: 1, + ), + ), + ), + ), + + ], + ), + ); + } +} diff --git a/lib/utils/customTextField.dart b/lib/utils/customTextField.dart new file mode 100644 index 0000000000000000000000000000000000000000..ef012dfb1be6d304e8d4b907b038c87e1b722fe1 --- /dev/null +++ b/lib/utils/customTextField.dart @@ -0,0 +1,68 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class CustomTextField extends StatelessWidget { + CustomTextField( + { this.title, + this.hint, + this.obsecure = false, + this.key, + this.validator, + this.controller, + this.onSaved}); + final String title; + final Key key; + final FormFieldSetter onSaved; + final String hint; + final bool obsecure; + final FormFieldValidator validator; + final TextEditingController controller; + + @override + Widget build(BuildContext context) { + return Container( + margin: EdgeInsets.symmetric(vertical: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle(fontSize: 18), + ), + SizedBox( + height: 10, + ), + TextFormField( + onSaved: onSaved, + validator: validator, + controller: controller, + autofocus: true, + obscureText: obsecure, + style: TextStyle( + fontSize: 15, + ), + decoration: InputDecoration( + hintStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 15), + hintText: hint, + contentPadding: EdgeInsets.all(8.0), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: Theme.of(context).primaryColor, + width: 1, + ), + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(10), + borderSide: BorderSide( + color: Theme.of(context).primaryColor, + width: 1, + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/utils/validator.dart b/lib/utils/validator.dart new file mode 100644 index 0000000000000000000000000000000000000000..23f98eab00f82e8395e271b0629774f29c750883 --- /dev/null +++ b/lib/utils/validator.dart @@ -0,0 +1,86 @@ +class FieldValidator { + static String validatePengisiData(String value){ + if (value.isEmpty) { + return '*Wajib diisi'; + } + else { + return null; + } + } + static String validateNamaPengisiData(String value){ + if (value.isEmpty) { + return '*Wajib diisi'; + } + else { + return null; + } + } + static String validateTtl(String value){ + if (value.isEmpty) { + return '*Wajib diisi'; + } + else { + return null; + } + } + static String validateAlamat(String value){ + if (value.isEmpty) { + return '*Wajib diisi'; + } + else { + return null; + } + } + + static String validateEmail(String value) { + Pattern pattern = + r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'; + RegExp regex = RegExp(pattern); + if (value.isEmpty) return '*Wajib diisi'; + if (!regex.hasMatch(value)) { + return '*Masukkan email yang valid'; + } else { + return null; + } + } + + static String validatePassword(String value) { + if (value.isEmpty) return '*Wajib diisi'; + + if (value.length < 7) { + return '*Password harus lebih dari 6 karakter'; + } else { + return null; + } + } + + + static String validatePhoneNumber(String value) { + String pattern = r'(^(?:[+0]9)?[0-9]{11,12}$)'; + RegExp regExp = RegExp(pattern); + if (value.isEmpty) { + return '*Wajib diisi'; + } + else if (!regExp.hasMatch(value)) { + return '*Masukkan nomor telepon yang valid'; + } + return null; + } + + static String validateName(String value) { + if (value.isEmpty) { + return '*Wajib diisi'; + } + else { + return null; + } + } + + static String validateInfo(String value) { + if (value.isEmpty) { + return '*Wajib diisi'; + } else { + return null; + } + } +} \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 1b41f5ac096ca76a352a87fae0127243843e3ef9..5b0e743b9e57bbd6b907f660280f0d73ef98d783 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,24 +14,46 @@ description: Project PPL layanan aplikasi disabilitas version: 1.0.0+1 environment: - sdk: ">=2.1.0 <3.0.0" + sdk: ">=2.6.0 <3.0.0" dependencies: flutter: sdk: flutter http: ^0.12.0+2 - path_provider: ^0.4.1 + mockito: ^4.1.1 intl: - - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. + location: ^2.5.3 + flutter_plugin_android_lifecycle: ^1.0.6 + flutter_polyline_points: ^0.1.0 + path_provider: ^1.6.5 cupertino_icons: ^0.1.2 + google_maps_flutter: ^0.5.24+1 + flutter_dotenv: ^2.1.0 + json_serializable: ^3.2.5 + cached_network_image: ^2.0.0 + shared_preferences: 0.5.6+3 + smooth_star_rating: ^1.0.4+2 + image_picker: ^0.6.5 + font_awesome_flutter: ^8.8.1 + dio: ^3.0.9 + share: ^0.6.4 + flutter_datetime_picker: ^1.3.8 dev_dependencies: flutter_test: sdk: flutter + flutter_launcher_icons: ^0.7.4 + # Linter dependency + pedantic: ^1.8.0 # The default Linter package used in Google + build_runner: ^1.8.0 + rxdart: ^0.23.1 +flutter_icons: + android: "launcher_icon" + ios: true + image_path: "assets/icon/icon_launcher.png" + #mockito: ^4.1.1 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec @@ -44,9 +66,14 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + # - assets/logo/google.png + assets: + - assets/icon/loc.png + - assets/icon/current_loc.png + - assets/icon/icon_launcher.png + - assets/logo/google.png + - assets/images/margocity.jpg + - assets/images/disabletoilet.jpg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. @@ -108,6 +135,5 @@ flutter: weight: 700 - asset: assets/fonts/Comfortaa-Bold.ttf weight: 800 - # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000000000000000000000000000000000000..5847c14108dce8e30f81d40e458b18f3b894f376 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,16 @@ +# SonarScanner properties file +## Server +sonar.host.url=https://pmpl.cs.ui.ac.id/sonarqube + +## Path to sources +sonar.sources=lib +#sonar.exclusions= +#sonar.inclusions= +## Path to tests +sonar.tests=test +sonar.coverage.exclusions = lib/model/*, lib/config/*, lib/flavor/*, lib/main_dev.dart, lib/main.dart +#sonar.test.exclusions= +#sonar.test.inclusions= +## Source encoding +sonar.sourceEncoding=UTF-8 +## Branch analysis diff --git a/test/addInformasi_test.dart b/test/addInformasi_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..041b14b3e846f750d162a1cbb8d9359e124cee86 --- /dev/null +++ b/test/addInformasi_test.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:ppl_disabilitas/page/addInformasi/addInfromasi.dart'; + +void main(){ + testWidgets('Test Input Gambar', (WidgetTester tester) async { + final testInputImage = Key("Input Gambar"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(testInputImage), findsOneWidget); + }); + + testWidgets('Info Text Field Test', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Informasi"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('Checkbox Fasilitas Test', (WidgetTester tester) async { + final checkBoxKey = Key("Checkbox Fasilitas"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(checkBoxKey), findsOneWidget); + }); + + testWidgets('Star Rating Exist Test', (WidgetTester tester) async { + final starKey = Key("Star Rating"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(starKey), findsOneWidget); + }); + + testWidgets('Simpan Button Test', (WidgetTester tester) async { + final simpanKey = Key("Simpan Button"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(simpanKey), findsOneWidget); + }); + + testWidgets('Batal Button Test', (WidgetTester tester) async { + final batalKey = Key("Batal Button"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(batalKey), findsOneWidget); + }); + + test('Empty Info Test', () { + var result = FieldValidator.validateInfo(''); + expect(result, '*Wajib diisi'); + }); + + test('Valid Info Test', () { + var result = FieldValidator.validateInfo('Margo city punya kursi roda'); + expect(result, null); + }); + + test('Star rating start from zero', (){ + var info = AddInformasiState(); + expect(info.rating, 0.0); + }); + +} \ No newline at end of file diff --git a/test/addKomentar_test.dart b/test/addKomentar_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..24bcb9ce128e814d993fd4937226a42381bf77cd --- /dev/null +++ b/test/addKomentar_test.dart @@ -0,0 +1,53 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/page/filter_fasilitas/postingan/addKomentar.dart'; + +void main() { + Widget buildTestableWidget(Widget widget) { + // https://docs.flutter.io/flutter/widgets/MediaQuery-class.html + return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget)); + } + + final detailPostData = { + "nama_lokasi": "Margo City", + "deskripsi": + "Ada toilet khusus disabilitas terletak di lantai 2 dekat kintan, kondisinya bagus dan bersih layak pakai.\r\n\r\nAda kursi roda juga di customer service lantai dasar, saya tidak ingat jumlahnya ada berapa, tapi ada lumayan banyak.", + "creator": "", + "date_time": "12-04-2020 14:33:54", + "like": 20, + "dislike": 1, + "rating": 3, + "tag": ["KR", "TD"], + "image": "static/img/2669211407.jpg", + "is_verified": false + }; + + testWidgets('Widget test for addKomentar page', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget( + AddKomentar(KomentarModel.fromJson(detailPostData)))); + // Search for the childWidget in the tree and verify it exists. + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(ListView), findsOneWidget); + //expect(find.byType(Container), findsNWidgets(7)); + expect(find.byType(Row), findsNWidgets(2)); + expect(find.byType(Text), findsNWidgets(7)); + expect(find.byType(Form), findsOneWidget); + }); + + testWidgets('Widget negative test for addKomentar page', + (WidgetTester tester) async { + await tester.pumpWidget(buildTestableWidget( + AddKomentar(KomentarModel.fromJson(detailPostData)))); + expect(find.byKey(Key('appbar-text')), findsNothing); + expect(find.byKey(Key('creator')), findsNothing); + }); +} diff --git a/test/bisago_drawer_test.dart b/test/bisago_drawer_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..27f3483dcfd71480826336a902ab3c8853e44fdd --- /dev/null +++ b/test/bisago_drawer_test.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/component/bisago_drawer.dart'; + + +void main() { + + group('drawer tests', () { + testWidgets('my drawer test', (WidgetTester tester) async { + final berandaText = "Beranda"; + await tester.pumpWidget(MaterialApp( + home: Scaffold( + drawer: BisaGoDrawer(), + ))); + + await tester.dragFrom(tester.getTopLeft(find.byType(MaterialApp)), Offset(300, 0)); + await tester.pumpAndSettle(); + +// await tester.tap(find.text(loginText)); +// await tester.pumpAndSettle(); +// +// final textFieldLogin = 'Masuk ke Akun'; + + expect(find.text(berandaText), findsOneWidget); + }); + }); +} \ No newline at end of file diff --git a/test/cookie_test.dart b/test/cookie_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..7a35a8c56f354eaaf63900337eba435e49f43118 --- /dev/null +++ b/test/cookie_test.dart @@ -0,0 +1,63 @@ +import 'dart:io'; +import 'package:flutter/services.dart'; +import 'package:mockito/mockito.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/network/cookies_interface.dart'; + +class MockCookiesInterface extends Mock implements CookiesInterface {} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + MethodChannel channel = + const MethodChannel('plugins.flutter.io/path_provider'); + setUpAll(() async { + // Create a temporary directory. + final directory = await Directory.systemTemp.createTemp(); + + // Mock out the MethodChannel for the path_provider plugin. + channel.setMockMethodCallHandler((MethodCall methodCall) async { + // If you're getting the apps documents directory, return the path to the + // temp directory on the test environment instead. + if (methodCall.method == 'getApplicationDocumentsDirectory') { + return directory.path; + } + return null; + }); + }); + CookiesInterface mockHttpClient; + test('Creates cookie file for sign in session', () async { + final responseHeaderFromSignIn = { + "set-cookie": + "csrftoken=v4E6UNpTMUMAoDxMoSZUBVPuAh7mkIb96DfRcakdivghb0d57yvCZxbbya7L3kFv; expires=Fri, 05 Mar 2021 03:33:39 GMT; Max-Age=31449600; Path=/; SameSite=Lax;sessionid=vrarp9pga02bwr97duemf6ym94gjgepn; expires=Fri, 20 Mar 2020 03:33:39 GMT; HttpOnly; Max-Age=1209600; Path=/; SameSite=Lax", + }; + mockHttpClient = MockCookiesInterface(); + String rootDir = + await channel.invokeMethod('getApplicationDocumentsDirectory'); + when(mockHttpClient.createSignInCookie( + responseHeaders: responseHeaderFromSignIn)) + .thenAnswer((_) async { + await Future.delayed(Duration(milliseconds: 50)); + return Future.value(File("$rootDir/usercookies.json")); + }); + // combine with sign in test here + }); + test('Creates cookie file after search', () async { + final recentSearch = { + "nama": "Johnson", + "latitude": -2.9062039, + "longitude": 114.6905436, + "alamat": "2460 Comanche Crossing", + "telepon": "+62 805 612 4225" + }; + String rootDir = + await channel.invokeMethod("getApplicationDocumentsDirectory"); + when(mockHttpClient.createSearchHistoryCookie( + recentSearch: recentSearch + )) + .thenAnswer((_) async { + await Future.delayed(Duration(milliseconds: 50)); + return Future.value(File("$rootDir/usercookies.json")); + }); + // combine with sign in test here + }); +} diff --git a/test/detailSekolah_test.dart b/test/detailSekolah_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..1bc236203a3e82bca83dd8a4dac2ba8dec2cfdd3 --- /dev/null +++ b/test/detailSekolah_test.dart @@ -0,0 +1,39 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/page/informasi/detailSekolah.dart'; + + +void main() { + Widget buildTestableWidget(Widget widget) { + // https://docs.flutter.io/flutter/widgets/MediaQuery-class.html + return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget)); + } + + testWidgets('find fasilitas page', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(DetailSekolah( + "Sekolah Pilar Indonesia", + "Jl. Paso No.84, Jagakarsa, Kec. Jagakarsa, Kota Jakarta Selatan, Daerah Khusus Ibukota Jakarta 12620", + "02149305494", + "www.pilarindonesia.com", + "1000", + "SW", + "IK", + "A"))); + // Search for the childWidget in the tree and verify it exists. + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(ListView), findsOneWidget); + expect(find.byType(Container), findsNWidgets(23)); + expect(find.byType(Column), findsNWidgets(1)); + expect(find.byType(Text), findsNWidgets(16)); + }); + +} diff --git a/test/detail_post_test.dart b/test/detail_post_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..f057e22d44c02e8dabe963b5830c05d52abd08cf --- /dev/null +++ b/test/detail_post_test.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/config/strings.dart'; +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/page/filter_fasilitas/postingan/detailpost.dart'; + +void main() { + Widget buildTestableWidget(Widget widget) { + return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget)); + } + + final detailPostData = { + "nama_lokasi": "Margo City", + "deskripsi": + "Ada toilet khusus disabilitas terletak di lantai 2 dekat kintan, kondisinya bagus dan bersih layak pakai.\r\n\r\nAda kursi roda juga di customer service lantai dasar, saya tidak ingat jumlahnya ada berapa, tapi ada lumayan banyak.", + "creator": "", + "date_time": "12-04-2020 14:33:54", + "like": 20, + "dislike": 1, + "rating": 3, + "tag": ["KR", "TD"], + "image": "static/img/2669211407.jpg", + "is_verified": false + }; + final detailPostPage = + DetailPostPage(komentar: KomentarModel.fromJson(detailPostData)); + testWidgets('Detail post positive test', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(detailPostPage)); + expect(find.byKey(Key('appbar-text-${detailPostData['nama_lokasi']}')), + findsOneWidget); + expect(find.byKey(Key('desc')), findsOneWidget); + expect(find.byKey(Key('creator-${detailPostData['creator']}')), + findsOneWidget); + expect(find.byKey(Key('timestamp')), findsOneWidget); + expect(find.byKey(Key('like')), findsOneWidget); + expect(find.byKey(Key('dislike')), findsOneWidget); + expect(find.byKey(Key('rating')), findsOneWidget); + expect(find.byKey(Key('tambah komentar')), findsOneWidget); + expect(find.byKey(Key('Komentar')), findsOneWidget); + }); + + testWidgets('Detail post negative test', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(detailPostPage)); + expect(find.byKey(Key('appbar-text')), findsNothing); + expect(find.byKey(Key('creator')), findsNothing); + expect(find.byKey(Key('komentar')), findsNothing); + }); + + test('Should decrypt tag code', () { + expect(getTag('KR'), tags['KR']); + }); +} diff --git a/test/fasilitas_test.dart b/test/fasilitas_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..515878d35c84632e1f866155c7f473197e060ba3 --- /dev/null +++ b/test/fasilitas_test.dart @@ -0,0 +1,93 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/globalnetwork.dart'; +import 'package:ppl_disabilitas/page/filter_fasilitas/fasilitas.dart'; + +void main() { + final mockFasilitas = { + "2": { + "id": 2, + "nama_lokasi": "Margo City", + "deskripsi": + "Ada toilet khusus disabilitas terletak di lantai 2 dekat kintan, kondisinya bagus dan bersih layak pakai.\r\n\r\nAda kursi roda juga di customer service lantai dasar, saya tidak ingat jumlahnya ada berapa, tapi ada lumayan banyak.", + "creator": "", + "date_time": "2020-04-12 14:33:54.44", + "like": 20, + "dislike": 1, + "rating": 3, + "tag": ["KR", "TD"], + "image": "static/img/2669211407.jpg", + "is_verified": false + } + }; + Widget buildTestableWidget(Widget widget) { + // https://docs.flutter.io/flutter/widgets/MediaQuery-class.html + return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget)); + } + + setUp(() { + getDioInstance('test'); + mockFasilitasDependencies(mockFasilitas); + }); + + testWidgets('find inside filter page', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(Fasilitas( + alamat: 'Itu', + nama: 'Ya', + telpon: '9217424', + url: 'afalklksafn', + ))); + await tester.tap(find.byKey(Key('FilterButton'))); + await tester.pump(Duration(seconds: 1)); + // inside filter + expect(find.byKey(Key('Urutan')), findsOneWidget); + expect(find.byKey(Key('Jenis Fasilitas')), findsOneWidget); + expect(find.byKey(Key('Komentar Terbaru')), findsOneWidget); + expect(find.byKey(Key('Komentar Terpopuler')), findsOneWidget); + expect(find.byKey(Key('Komentar dengan Rating Tertinggi')), findsOneWidget); + expect(find.byKey(Key('Kursi Roda')), findsOneWidget); + expect(find.byKey(Key('Lift')), findsOneWidget); + expect(find.byKey(Key('Toilet Disabilitas')), findsOneWidget); + expect(find.byKey(Key('Tempat Ibadah')), findsOneWidget); + await tester.drag(find.byKey(Key('Tempat Ibadah')), Offset(0, -200)); + await tester.pump(); + // expect(find.byKey(Key('Guiding Block')), findsOneWidget); + //expect(find.byKey(Key('Bidang Miring (Ramp)')), findsOneWidget); + //expect(find.byKey(Key('Juru Bahasa Isyarat')), findsOneWidget); + //expect(find.byKey(Key('Tongkat Disabilitas Netra')), findsOneWidget); + //expect(find.byKey(Key('Kursi Umum Disabilitas')), findsOneWidget); + //expect(find.byKey(Key('Parkir Umum')), findsOneWidget); + //expect(find.byKey(Key('Runing Text')), findsOneWidget); + //expect(find.byKey(Key('Parkir Disabilitas')), findsOneWidget); + // filter + await tester.tap(find.byKey(Key('Alamat'))); + await tester.pump(); + }); + + testWidgets('find fasilitas page', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(Fasilitas( + alamat: 'Itu', + nama: 'Ya', + telpon: '9217424', + url: 'afalklksafn', + ))); + expect(find.text('9217424'), findsOneWidget); + expect(find.text('Ya'), findsOneWidget); + expect(find.text('Itu'), findsOneWidget); + await tester.pump(); + // expect(find.text(mockFasilitas['2']['deskripsi']), findsOneWidget); + await tester.tap(find.byKey(Key('Alamat'))); + await tester.pump(); + await tester.pump(); + await tester.pump(); + }); +} diff --git a/test/layananDisabilitas_test.dart b/test/layananDisabilitas_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..fcad741486a6395985a732744de48ae43202752a --- /dev/null +++ b/test/layananDisabilitas_test.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/page/informasi/layananDisabilitas.dart'; + +void main() { + Widget buildTestableWidget(Widget widget) { + // https://docs.flutter.io/flutter/widgets/MediaQuery-class.html + return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget)); + } + + testWidgets('find informasi layanan disabilitas page', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(LayananDisabilitas())); + final scaffoldTextFieldKey = Key("Scaffold Text Field"); + + //positive test + //expect(find.byType(Container), findsNWidgets(4)); + expect(find.byType(Column), findsOneWidget); + expect(find.byType(Text), findsNWidgets(4)); + expect(find.byType(Icon), findsNWidgets(5)); + expect(find.byType(Row), findsNWidgets(3)); + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(SizedBox), findsNWidgets(8)); + expect(find.byType(FlatButton), findsNWidgets(2)); + expect(find.byKey(scaffoldTextFieldKey), findsOneWidget); + + + //negative test + expect(find.byType(Flex), findsNothing); + expect(find.byType(BoxDecoration), findsNothing); + expect(find.byType(BorderSide), findsNothing); + expect(find.byType(TextStyle), findsNothing); + expect(find.text('regtrs pnydng disabilts'), findsNothing); + expect(find.text('informs pyndg disable'), findsNothing); + expect(find.text('informasshi sklh dngn dkgn disable'), findsNothing); + + }); + + + + +} diff --git a/test/list_sekolah_test.dart b/test/list_sekolah_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..b896403fb56e0f9a2471ec7196a92e615647ca65 --- /dev/null +++ b/test/list_sekolah_test.dart @@ -0,0 +1,44 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/page/informasi/list_sekolah.dart'; + +void main() { + Widget buildTestableWidget(Widget widget) { + // https://docs.flutter.io/flutter/widgets/MediaQuery-class.html + return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget)); + } + + testWidgets("find a title app bar", (WidgetTester tester) async { + final textAppBar = Key("appbar-text-informasi-sekolah"); + await tester.pumpWidget(MaterialApp(home: ListSekolah())); + + expect(find.byKey(textAppBar), findsOneWidget); + expect(find.text("Sekolah dengan Dukungan Disabilitas"), findsOneWidget); + }); + + testWidgets('find inside filter page', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(ListSekolah())); + await tester.tap(find.byKey(Key('FilterButton'))); + await tester.pump(Duration(seconds: 1)); + expect(find.byType(Container), findsNWidgets(23)); + expect(find.byType(Row), findsNWidgets(17)); + expect(find.byType(Column), findsNWidgets(3)); + expect(find.byType(Text), findsNWidgets(21)); + expect(find.byType(Flex), findsNothing); + expect(find.text('jns fasilitas'), findsNothing); + expect(find.text('urutn'), findsNothing); + expect(find.text('hps smw'), findsNothing); + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(Icon), findsNWidgets(3)); + await tester.tap(find.byKey(Key('FilterButton'))); + await tester.pump(); + }); +} diff --git a/test/login_test.dart b/test/login_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..6c3923c6325b25abef1a469dbec3a891a6b448e0 --- /dev/null +++ b/test/login_test.dart @@ -0,0 +1,42 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; +import 'package:ppl_disabilitas/page/login/login.dart'; +//import 'package:http/http.dart' as http; + +class MockNetwork extends Mock implements NetworkInterface {} + +void main() { + MockNetwork mockNetwork; + setUp(() { + mockNetwork = MockNetwork(); + when(mockNetwork.get(isLogin: false, url: anyNamed('url'))) + .thenAnswer((_) async { + await Future.delayed(Duration(milliseconds: 50)); + return Future.value([ + { + "username": "dummy@mail.com", + "name": "Dummy", + "email": "dummy@mail.com", + "phone_number": "085222333444", + } + ]); + }); + }); + + testWidgets('Find Username Text Field', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Akun"); + await tester.pumpWidget(MaterialApp(home: Login())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('Find Password Text Field', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Password"); + await tester.pumpWidget(MaterialApp(home: Login())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + +} \ No newline at end of file diff --git a/test/mock_test.dart b/test/mock_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..537257fa5a6978b2f3df1af8853a28e8a10733c0 --- /dev/null +++ b/test/mock_test.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:mockito/mockito.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; +import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; +import 'package:http/http.dart' as http; +import 'package:pedantic/pedantic.dart'; + +class MockNavigatorObserver extends Mock implements NavigatorObserver {} + +class MockNetwork extends Mock implements NetworkInterface {} + +class MockHttp extends Mock implements http.Client {} + +void main() { + group('Dashboard navigation tests', () { + NavigatorObserver mockObserver; + NetworkInterface mockNetwork; + MockHttp mockHttp; + setUp(() { + mockObserver = MockNavigatorObserver(); + mockNetwork = MockNetwork(); + mockHttp = MockHttp(); + when(mockHttp.get('http://wwww.google.com')) + .thenAnswer((_) async => http.Response('{"title": "Test"}', 200)); + when(mockNetwork.get(isLogin: false, url: anyNamed('url'))) + .thenAnswer((_) async { + await Future.delayed(Duration(milliseconds: 50)); + return Future.value([ + { + "nama": "Coolidge", + "latitude": -23.7169139, + "longitude": -46.8498038, + "alamat": "74809 Hooker Drive", + "telepon": "+55 956 836 5799" + } + ]); + }); + }); + + Future _buildDashboardPage(WidgetTester tester) async { + await tester.pumpWidget(MaterialApp( + home: Dashboard(), + + /// This mocked observer will now receive all navigation events + /// that happen in our app. + navigatorObservers: [mockObserver], + )); + + /// The tester.pumpWidget() call above just built our app widget + /// and triggered the pushObserver method on the mockObserver once. + verify(mockObserver.didPush(any, any)); + } + + Future _navigateToPencarianPage(WidgetTester tester) async { + final textFieldKey = Key("Text Field Mau Kemana"); + await tester.tap(find.byKey(textFieldKey)); + await tester.pump(); + } + + testWidgets( + 'when tapping text form field, should navigate to pencarian page', + (WidgetTester tester) async { + final textFieldKeyPencarian = Key("Text Field Mau Kemana"); + await _buildDashboardPage(tester); + await _navigateToPencarianPage(tester); + + verify(mockObserver.didPush(any, any)); + expect(find.byKey(textFieldKeyPencarian), findsOneWidget); + }); + + testWidgets('tapping the back button should navigate back to the dashboard', + (WidgetTester tester) async { + final backIconKey = Key("Back Icon Key"); + await _buildDashboardPage(tester); + await _navigateToPencarianPage(tester); + await tester.pump(); + final Route pushedRoute = + verify(mockObserver.didPush(captureAny, any)).captured.single; + String popResult; + unawaited(pushedRoute.popped.then((result) => popResult = result)); + await tester.tap(find.byKey(backIconKey)); + await tester.pumpAndSettle(); + expect(popResult, 'Take me back'); + }); + }); +} diff --git a/test/pencarian_test.dart b/test/pencarian_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..fe290abdff0e818537f832042ed535bc2150ce73 --- /dev/null +++ b/test/pencarian_test.dart @@ -0,0 +1,69 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:ppl_disabilitas/page/pencarian/pencarian.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; + +class MockNetwork extends Mock implements NetworkInterface {} + +void main() { + MockNetwork mockNetwork; + setUp(() { + mockNetwork = MockNetwork(); + when(mockNetwork.get(isLogin: false, url: anyNamed('url'))) + .thenAnswer((_) async { + await Future.delayed(Duration(milliseconds: 50)); + return Future.value([ + { + "nama": "Coolidge", + "latitude": -23.7169139, + "longitude": -46.8498038, + "alamat": "74809 Hooker Drive", + "telepon": "+55 956 836 5799" + } + ]); + }); + }); + testWidgets('display list view in pencarian', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp(home: Pencarian())); + expect(find.byKey(const Key("Text Field Mau Kemana")), findsOneWidget); + //var textField = find.byKey(const Key("Text Field Mau Kemana")); + //await tester.tap(textField); + await tester.enterText( + find.byKey(const Key("Text Field Mau Kemana")), "Coolidge"); + await tester.pump(); + expect(find.text("Hasil Pencarian"), findsOneWidget); + + //expect(find.byType(CircleAvatar), findsWidgets); + + //expect(find.byKey(const Key("api-Coolidge")), findsOneWidget); + // [TODO] tiap item itu punya key unik + // Search for the childWidget in the tree and verify it exists. + //expect(find.byType(ListView), findsNWidgets); + //expect(find.byType(Container), findsWidgets); + //expect(find.byType(Icon), findsWidgets); + }); + + testWidgets('finds a text field in pencarian', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Mau Kemana"); + await tester.pumpWidget(MaterialApp(home: Pencarian())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('test textfield result', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Mau Kemana"); + await tester.pumpWidget(MaterialApp(home: Pencarian())); + await tester.enterText(find.byKey(textFieldKey), 'Mallory'); + await tester.pump(); + expect(find.text('Mallory'), findsOneWidget); + }); +} diff --git a/test/registrasiInformasiLayananDisabilitas_test.dart b/test/registrasiInformasiLayananDisabilitas_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..285b6f7a9ecee751a70f297e338efee02f902fc2 --- /dev/null +++ b/test/registrasiInformasiLayananDisabilitas_test.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/page/registrasi_penyandang_disabilitas/registrasiInformasiLayananDisabilitas.dart'; + +void main() { + Widget buildTestableWidget(Widget widget) { + // https://docs.flutter.io/flutter/widgets/MediaQuery-class.html + return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget)); + } + + testWidgets('find registrasi page', (WidgetTester tester) async { + // Provide the childWidget to the Container. + await tester.pumpWidget(buildTestableWidget(RegistrasiInformasiLayananDisabilitas())); + final scaffoldTextFieldKey = Key("Scaffold Text Field"); + + //positive test + expect(find.byType(Container), findsNWidgets(53)); + expect(find.byType(Column), findsNWidgets(10)); + expect(find.byType(Text), findsNWidgets(53)); + expect(find.byType(Icon), findsNWidgets(5)); + expect(find.byType(Row), findsNWidgets(6)); + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(SizedBox), findsNWidgets(61)); + expect(find.byType(FlatButton), findsNWidgets(3)); + + + //negative test + expect(find.byType(FormField), findsNothing); + expect(find.byType(BoxDecoration), findsNothing); + expect(find.byType(Flex), findsNothing); + expect(find.byKey(scaffoldTextFieldKey), findsNothing); + expect(find.text('regtrs pnydng disabilts'), findsNothing); + expect(find.text('pengisi dt'), findsNothing); + expect(find.text('nm lngkp pnyndng'), findsNothing); + expect(find.text('jenis kelaMINNNN'), findsNothing); + + }); + + + + +} diff --git a/test/registrasi_test.dart b/test/registrasi_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..cfc2e29150660e95affaf7335b5b12c7e8789c46 --- /dev/null +++ b/test/registrasi_test.dart @@ -0,0 +1,52 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/page/registrasi/registrasi.dart'; +//import 'package:ppl_disabilitas/model/user.dart'; +//import 'package:http/http.dart' as http; + +void main() { + testWidgets('Find Name Text Field', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Nama"); + await tester.pumpWidget(MaterialApp(home: Registrasi())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('Find Phone Number Text Field', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Nomor Telepon"); + await tester.pumpWidget(MaterialApp(home: Registrasi())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('Find Email Text Field', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Email"); + await tester.pumpWidget(MaterialApp(home: Registrasi())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('Find Password Text Field', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Password"); + await tester.pumpWidget(MaterialApp(home: Registrasi())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('Find Password Confirmation Text Field', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Konfirmasi Password"); + await tester.pumpWidget(MaterialApp(home: Registrasi())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + +// test('Valid API end point for registering user', () async { +// User user = User( +// username: 'Dummy user', +// phonenumber: '081100000000', +// email: 'dummy@dummy.com', +// password: 'dummypassword' +// ); +// final result = await http.post( +// "https://my.api.mockaroo.com/register.json?key=095ee610&__method=POST", +// headers: {"content-type": "application/json"}, +// body: userToJson(user), +// ); +// expect(result.statusCode, 200); +// }); +} \ No newline at end of file diff --git a/test/updateInformasi_test.dart b/test/updateInformasi_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..041b14b3e846f750d162a1cbb8d9359e124cee86 --- /dev/null +++ b/test/updateInformasi_test.dart @@ -0,0 +1,58 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:ppl_disabilitas/page/addInformasi/addInfromasi.dart'; + +void main(){ + testWidgets('Test Input Gambar', (WidgetTester tester) async { + final testInputImage = Key("Input Gambar"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(testInputImage), findsOneWidget); + }); + + testWidgets('Info Text Field Test', (WidgetTester tester) async { + final textFieldKey = Key("Text Field Informasi"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + + testWidgets('Checkbox Fasilitas Test', (WidgetTester tester) async { + final checkBoxKey = Key("Checkbox Fasilitas"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(checkBoxKey), findsOneWidget); + }); + + testWidgets('Star Rating Exist Test', (WidgetTester tester) async { + final starKey = Key("Star Rating"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(starKey), findsOneWidget); + }); + + testWidgets('Simpan Button Test', (WidgetTester tester) async { + final simpanKey = Key("Simpan Button"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(simpanKey), findsOneWidget); + }); + + testWidgets('Batal Button Test', (WidgetTester tester) async { + final batalKey = Key("Batal Button"); + await tester.pumpWidget(MaterialApp(home: AddInformasi())); + expect(find.byKey(batalKey), findsOneWidget); + }); + + test('Empty Info Test', () { + var result = FieldValidator.validateInfo(''); + expect(result, '*Wajib diisi'); + }); + + test('Valid Info Test', () { + var result = FieldValidator.validateInfo('Margo city punya kursi roda'); + expect(result, null); + }); + + test('Star rating start from zero', (){ + var info = AddInformasiState(); + expect(info.rating, 0.0); + }); + +} \ No newline at end of file diff --git a/test/validator_test.dart b/test/validator_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..4fcd0e0c5d510c2ee15f214026fae01f4e5787bb --- /dev/null +++ b/test/validator_test.dart @@ -0,0 +1,60 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; + +void main() { + test('Empty Name Test', () { + var result = FieldValidator.validateName(''); + expect(result, '*Wajib diisi'); + }); + + test('Valid Name Test', () { + var result = FieldValidator.validateName('Dummy User'); + expect(result, null); + }); + + test('Empty Phone Number Test', () { + var result = FieldValidator.validatePhoneNumber(''); + expect(result, '*Wajib diisi'); + }); + + test('Invalid Phone Number Test', () { + var result = FieldValidator.validatePhoneNumber('abcd1234'); + expect(result, '*Masukkan nomor telepon yang valid'); + }); + + test('Valid Phone Number Test', () { + var result = FieldValidator.validatePhoneNumber('081000000000'); + expect(result, null); + }); + + test('Empty Email Test', () { + var result = FieldValidator.validateEmail(''); + expect(result, '*Wajib diisi'); + }); + + test('Invalid Email Test', () { + var result = FieldValidator.validateEmail('dummy'); + expect(result, '*Masukkan email yang valid'); + }); + + test('Valid Email Test', () { + var result = FieldValidator.validateEmail('dummy@test.com'); + expect(result, null); + }); + + test('Empty Password Test', () { + var result = FieldValidator.validatePassword(''); + expect(result, '*Wajib diisi'); + }); + + test('Invalid Password Test', () { + var result = FieldValidator.validatePassword('ab456'); + expect(result, '*Password harus lebih dari 6 karakter'); + }); + + test('Valid Password Test', () { + var result = FieldValidator.validatePassword('abcd1234'); + expect(result, null); + }); + +} diff --git a/test/widget_test.dart b/test/widget_test.dart index d5193c1a5479b96e0ab1e76ef8f2d64c6e1c61b4..3859e88c0d7cd59deb7968c98120a43fa4d01b52 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -1,21 +1,60 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import 'package:ppl_disabilitas/main.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:ppl_disabilitas/app.dart'; +import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; void main() { - testWidgets('Hello World smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); + testWidgets('finds a text field in dashboard', (WidgetTester tester) async { + final containerTextField = Key("Container Text Field"); + final iconButtonTextField = Key("IconButton Text Field"); + final textFieldKey = Key("Text Field Mau Kemana"); + final scaffoldTextFieldKey = Key("Scaffold Text Field"); + // Provide the childWidget to the Container. + await tester.pumpWidget(MaterialApp(home: Dashboard())); + // Search for the childWidget in the tree and verify it exists. + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byKey(Key("Stack")), findsOneWidget); + expect(find.byType(TextFormField), findsOneWidget); + expect(find.byType(Icon), findsNWidgets(4)); + expect(find.text('Kamu mau kemana?'), findsOneWidget); + expect(find.text('Kamu mau kmn?'), findsNothing); + expect(find.byKey(containerTextField), findsOneWidget); + expect(find.byKey(iconButtonTextField), findsOneWidget); + expect(find.byKey(textFieldKey), findsOneWidget); + expect(find.byKey(scaffoldTextFieldKey), findsOneWidget); + }); + + testWidgets('finds a google map in dashboard', (WidgetTester tester) async { + final containerGoogleMap = Key("Container GoogleMap"); + final googleMapKey = Key("Google Map"); + await tester.pumpWidget(MaterialApp(home: Dashboard())); + expect(find.byType(GoogleMap), findsOneWidget); + expect(find.byType(Container), findsNWidgets(4)); + expect(find.byKey(googleMapKey), findsOneWidget); + expect(find.byKey(containerGoogleMap), findsOneWidget); + }); + + testWidgets('finds a floating in dashboard', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp(home: Dashboard())); + expect(find.byKey(Key("FloatingActionButton")), findsOneWidget); + expect(find.byKey(Key("FloatingActionButtonnnn")), findsNothing); + }); + + // testWidgets('finds a marker in google map', (WidgetTester tester) async { + // await tester.pumpWidget(MaterialApp(home: Dashboard())); + // expect(find.byType(Marker), findsOneWidget); + // }); + + testWidgets('finds a navigation bar', (WidgetTester tester) async { + await tester.pumpWidget(MaterialApp(home: Dashboard())); + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(Theme), findsOneWidget); + expect(find.byType(AppBar), findsOneWidget); + }); - // Verify that our counter starts at 0. - expect(find.text('Hello World'), findsOneWidget); + testWidgets('Shows dashboard on App Start', (WidgetTester tester) async { + await tester.pumpWidget(BisaGo()); + expect(find.byType(Dashboard), findsOneWidget); }); }