diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index e49cab89bc9eaab918130ecfdcd141b49c1b2043..c6ecbd36fa33b864b07cb429b7d1423584d69228 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.","plugins":{"ios":[{"name":"google_maps_flutter","path":"D:\\\\Flutter\\\\flutter_windows_v1.9.1+hotfix.2-stable\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_maps_flutter-0.5.24+1\\\\","dependencies":[]},{"name":"location","path":"D:\\\\Flutter\\\\flutter_windows_v1.9.1+hotfix.2-stable\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location-2.5.3\\\\","dependencies":[]}],"android":[{"name":"flutter_plugin_android_lifecycle","path":"D:\\\\Flutter\\\\flutter_windows_v1.9.1+hotfix.2-stable\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\flutter_plugin_android_lifecycle-1.0.6\\\\","dependencies":[]},{"name":"google_maps_flutter","path":"D:\\\\Flutter\\\\flutter_windows_v1.9.1+hotfix.2-stable\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\google_maps_flutter-0.5.24+1\\\\","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"location","path":"D:\\\\Flutter\\\\flutter_windows_v1.9.1+hotfix.2-stable\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\location-2.5.3\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"google_maps_flutter","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"location","dependencies":[]}],"date_created":"2020-03-25 22:29:07.715265","version":"1.15.17"} \ 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":"location","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_macos"]},{"name":"path_provider_macos","dependencies":[]},{"name":"sqflite","dependencies":[]}]} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 93baea49f73ca9c807d41f71ac6cba1aa443ff43..a1b47e53bf30b0552bf6204186dc275a0899c63b 100644 --- a/.gitignore +++ b/.gitignore @@ -289,3 +289,5 @@ modules.xml # 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 c73806b74dce2b8ad3336235acda0c95f4e4e742..da9a47c7190313948d82edb935b54ebcdf895416 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,8 +22,8 @@ Lint: Test: stage: test script: - - flutter test --machine > tests.output - flutter test --coverage + - flutter test --machine > tests.output - lcov --summary coverage/lcov.info - genhtml coverage/lcov.info --output=coverage artifacts: diff --git a/README.md b/README.md index 67bdfefd39a8e5db3902558252c432f5f09598a4..6c0f425d264c9e29e46a7929166d7d3cb77bf6c3 100644 --- a/README.md +++ b/README.md @@ -50,4 +50,17 @@ MAPS_API_KEY=Bu*************** Run the app using the development flavor ```bash flutter run -t lib/main_dev.dart -``` \ No newline at end of file +``` +## 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/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/lib/app.dart b/lib/app.dart index f5a00dfb9b5822c8be96289a04ace48f9c1df934..78d0da222775ab094d20947386a3509a35209170 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -1,5 +1,8 @@ import 'package:flutter/material.dart'; import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; +import 'package:ppl_disabilitas/page/login/login.dart'; +import 'package:ppl_disabilitas/page/registrasi/registrasi.dart'; +//import 'package:ppl_disabilitas/page/filter & fasilitas/fasilitas.dart'; class BisaGo extends StatelessWidget { @override @@ -10,7 +13,12 @@ class BisaGo extends StatelessWidget { fontFamily: 'Muli', backgroundColor: Colors.white, ), - home: Dashboard(), + initialRoute: '/', + routes: { + '/': (context) => Dashboard(), + '/login': (context) => Login(), + '/register': (context) => Registrasi(), + }, ); } } diff --git a/lib/bloc/KomentarBloc.dart b/lib/bloc/KomentarBloc.dart new file mode 100644 index 0000000000000000000000000000000000000000..db892c69738827c844017b6fac56c0621cd2cadd --- /dev/null +++ b/lib/bloc/KomentarBloc.dart @@ -0,0 +1,37 @@ +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; + + StreamSink> get komentarListSink => + _komentarListController.sink; + Stream> get komentarListStream => + _komentarListController.stream; + + KomentarBloc() { + _komentarListController = StreamController>(); + _komentarRepository = KomentarRepository(); + fetchKomentarList(); + } + + fetchKomentarList() async { + komentarListSink.add(NetworkModel.loading('Getting Komentar')); + try { + KomentarList komentarListResponse = + await _komentarRepository.fetchKomentar(); + komentarListSink.add(NetworkModel.completed(komentarListResponse)); + } catch (e) { + komentarListSink.add(NetworkModel.error(e.toString())); + print("$e"); + } + } + + dispose() { + _komentarListController?.close(); + } +} diff --git a/lib/bloc/LokasiResponseBloc.dart b/lib/bloc/LokasiResponseBloc.dart new file mode 100644 index 0000000000000000000000000000000000000000..ace530a114d6116a017ba7c6d80bd1236d755ec0 --- /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 { + LokasiListResponse 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 { + LokasiListResponse 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/component/ImageHolder.dart b/lib/component/ImageHolder.dart new file mode 100644 index 0000000000000000000000000000000000000000..30f329d9a93541441498150b2622e4fb40b52743 --- /dev/null +++ b/lib/component/ImageHolder.dart @@ -0,0 +1,26 @@ +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( + decoration: BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/margocity.png'), + fit: BoxFit.scaleDown)), + ), + ); + } +} diff --git a/lib/component/bisago_drawer.dart b/lib/component/bisago_drawer.dart index ff510da5af717d496172b48488b38676caca3778..644aec0c0759a9bfc3c6ea6c2cdd1d77bd3a29a3 100644 --- a/lib/component/bisago_drawer.dart +++ b/lib/component/bisago_drawer.dart @@ -79,7 +79,7 @@ class BisaGoDrawer extends StatelessWidget { ), ), onTap: () { - Navigator.pop(context); + Navigator.pushNamed(context, '/login'); }, ), decoration: BoxDecoration( diff --git a/lib/config/custom_serializer.dart b/lib/config/custom_serializer.dart new file mode 100644 index 0000000000000000000000000000000000000000..3c7dc1f59c5c53a3186f967ea52b376bed2b0f72 --- /dev/null +++ b/lib/config/custom_serializer.dart @@ -0,0 +1,3 @@ +class CustomSerializer { + static DateTime stringToDateTime(String date) => DateTime.parse(date); +} diff --git a/lib/config/strings.dart b/lib/config/strings.dart index f680bdbc8eb6ac533121eaa2f9de0da036523dac..0162847de9bfef0804b5b982a287419cc9838126 100644 --- a/lib/config/strings.dart +++ b/lib/config/strings.dart @@ -5,12 +5,12 @@ final String devBaseURL = "poipole.herokuapp.com"; final String baseURL = "poipole.herokuapp.com"; String key = ""; String csrf = ""; -String sessionID = ""; +String sessionId = ""; -setKey(String key) { - key = key; +setKey(String newKey) { + key = newKey; } -setSessionId(String sessionId) { - sessionID = sessionId; +setSessionId(String newSessionId) { + sessionId = newSessionId; } \ No newline at end of file diff --git a/lib/config/styles.dart b/lib/config/styles.dart index 3b140b67428cd2b3e08642963582324ae7d0420e..aac8a3981d60533fabc4e7f790ab1510680049d9 100644 --- a/lib/config/styles.dart +++ b/lib/config/styles.dart @@ -1,21 +1,40 @@ import 'package:flutter/material.dart'; final Color greenPrimary = Color(0xff3A903A); +final Color greenPale = Color(0xff4FBA4F); final Color redPrimary = Color(0xffC60000); -final Color bluePrimary = Color(0xff537AC6); +final double superSmallSpace = 4.0; final double smallSpace = 4.0; final double regularSpace = 8.0; +final double regularBiggerSpace = 12.0; final double doubleSpace = 16.0; final double tripleSpace = 32.0; +final double spaceFourty = 45.0; final double quartetSpace = 64.0; final double spaceFourtyEight = 48.0; final List regularShadow = [ BoxShadow( - blurRadius: 4, - color: Colors.black.withOpacity(0.25), - offset: Offset(0, 0)) + 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/main.dart b/lib/main.dart index 07a3a29d179411d3c30572c51cd00f31fbc5023d..7a6c647000852b07c2f705d6e579d50a8b737454 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:ppl_disabilitas/app.dart'; import 'flavor/flavor.dart'; -import 'page/login/landing.dart'; void main() { ApiFlavor.flavor = BuildFlavor.production.toString(); diff --git a/lib/model/komentar.dart b/lib/model/komentar.dart new file mode 100644 index 0000000000000000000000000000000000000000..7c37c099eead509b5db45fb96c56c4f0aee6a568 --- /dev/null +++ b/lib/model/komentar.dart @@ -0,0 +1,24 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'komentar.g.dart'; + +@JsonSerializable() +class KomentarList { + final List allKomentar; + KomentarList(this.allKomentar); +} + +@JsonSerializable() +class KomentarModel { + final String nama_orang; + final int suka; + final int tidak_suka; + final String foto; + + KomentarModel( + {this.nama_orang, this.suka, this.tidak_suka, this.foto}); + + 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..14d38aac572c9f1c5ab7fa8d26ae282e37fa59f2 --- /dev/null +++ b/lib/model/komentar.g.dart @@ -0,0 +1,39 @@ +// 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( + nama_orang: json['nama_orang'] as String, + suka: json['suka'] as int, + tidak_suka: json['tidak_suka'] as int, + foto: json['foto'] as String, + ); +} + +Map _$KomentarModelToJson(KomentarModel instance) => + { + 'nama_orang': instance.nama_orang, + 'suka': instance.suka, + 'tidak_suka': instance.tidak_suka, + 'foto': instance.foto, + }; diff --git a/lib/model/lokasi.dart b/lib/model/lokasi.dart new file mode 100644 index 0000000000000000000000000000000000000000..90aea3a69a0c3f7d4358f670cee510ebf8803697 --- /dev/null +++ b/lib/model/lokasi.dart @@ -0,0 +1,23 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'lokasi.g.dart'; +@JsonSerializable() +class LokasiListResponse { + List listLokasi; + + LokasiListResponse(this.listLokasi); +} + +@JsonSerializable(nullable: true) +class Lokasi { + String nama; + double latitude; + double longitude; + String alamat; + String foto; + String telepon; + + 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..96672379419c423440447568134d9f916c14a3c0 --- /dev/null +++ b/lib/model/lokasi.g.dart @@ -0,0 +1,40 @@ +// 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() + ..nama = json['nama'] as String + ..latitude = (json['latitude'] as num)?.toDouble() + ..longitude = (json['longitude'] as num)?.toDouble() + ..alamat = json['alamat'] as String + ..foto = json['foto'] as String + ..telepon = json['telepon'] as String; +} + +Map _$LokasiToJson(Lokasi instance) => { + 'nama': instance.nama, + 'latitude': instance.latitude, + 'longitude': instance.longitude, + 'alamat': instance.alamat, + 'foto': instance.foto, + 'telepon': instance.telepon, + }; diff --git a/lib/model/pengguna.dart b/lib/model/pengguna.dart new file mode 100644 index 0000000000000000000000000000000000000000..b71491f75f87c314b661873338c8b7bbc1294628 --- /dev/null +++ b/lib/model/pengguna.dart @@ -0,0 +1,24 @@ +import 'package:json_annotation/json_annotation.dart'; +part 'pengguna.g.dart'; + +@JsonSerializable() +class UserListResponse { + List listUser; + + UserListResponse(); + factory UserListResponse.fromJson(Map json) => _$UserListResponseFromJson(json); + Map toJson() => _$UserListResponseToJson(this); +} + +@JsonSerializable(nullable: true) +class User { + String username; + String phonenumber; + String email; + String password; + + User(); + + factory User.fromJson(Map json) => _$UserFromJson(json); + Map toJson() => _$UserToJson(this); +} \ No newline at end of file diff --git a/lib/model/pengguna.g.dart b/lib/model/pengguna.g.dart new file mode 100644 index 0000000000000000000000000000000000000000..b267afdbb4350be1347f7e68f2c0fe126b6b6505 --- /dev/null +++ b/lib/model/pengguna.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pengguna.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UserListResponse _$UserListResponseFromJson(Map json) { + return UserListResponse() + ..listUser = (json['listUser'] as List) + ?.map( + (e) => e == null ? null : User.fromJson(e as Map)) + ?.toList(); +} + +Map _$UserListResponseToJson(UserListResponse instance) => + { + 'listUser': instance.listUser, + }; + +User _$UserFromJson(Map json) { + return User() + ..username = json['username'] as String + ..phonenumber = json['phonenumber'] as String + ..email = json['email'] as String + ..password = json['password'] as String; +} + +Map _$UserToJson(User instance) => { + 'username': instance.username, + 'phonenumber': instance.phonenumber, + 'email': instance.email, + 'password': instance.password, + }; diff --git a/lib/model/user.dart b/lib/model/user.dart new file mode 100644 index 0000000000000000000000000000000000000000..156ebfa25d90e097c3009909e8949f48d4e03677 --- /dev/null +++ b/lib/model/user.dart @@ -0,0 +1,35 @@ +import 'dart:convert'; + +class User { + String username; + String phonenumber; + String email; + String password; + + User({this.username, this.phonenumber, this.email, this.password}); + + factory User.fromJson(Map map) { + return User( + username: map["username"], phonenumber: map["phonenumber"], email: map["email"], password: map["password"]); + } + + Map toJson() { + return {"username": username, "phonenumber": phonenumber, "email": email, "password": password}; + } + + @override + String toString() { + return 'User{"username": $username, "phonenumber": $phonenumber, "email": $email, "password": $password}'; + } + +} + +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 new file mode 100644 index 0000000000000000000000000000000000000000..52ac47bcd60e780aba333c2d13cc6326ff4572cf --- /dev/null +++ b/lib/network/cookies_interface.dart @@ -0,0 +1,101 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:path_provider/path_provider.dart'; +import 'package:ppl_disabilitas/config/strings.dart'; + +class CookiesInterface { + Future checkCookieFileAvailability({String fileName}) async { + Directory dir; + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + File cookieFile = File("${dir.path}/$fileName.json"); + bool cookiesExist = cookieFile.existsSync(); + + return cookiesExist; + } + + Future createSignInCookie({ + Map responseHeaders}) async { + try { + String setCookie; + String csrfToken; + String sessionId; + String userKey; + List cookiesList; + Directory dir; + + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + File 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; + } + cookiesList = [ + csrfToken, + sessionId, + userKey, + ]; + cookieFile.writeAsStringSync(json.encode(cookiesList)); + return cookieFile; + } on Exception catch (e) { + print(e.toString()); + rethrow; + } + } + + Future createSearchHistoryCookie({ + Map recentSearch}) async { + print("recent searrch $recentSearch"); + Directory dir; + List currentSearchHistory; + try { + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + File 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); + } + currentSearchHistory.insert(0, recentSearch); + }); + } else { + currentSearchHistory = []; + } + await cookieFile.writeAsString(json.encode(currentSearchHistory)); + }); + return cookieFile; + } on Exception catch (e) { + print(e.toString()); + rethrow; + } + } + + Future getCookieFile({String fileName}) async { + Directory dir; + await getApplicationDocumentsDirectory().then((Directory directory) { + dir = directory; + }); + File file = File("${dir.path}/$fileName.json"); + dynamic res; + try { + res = file.readAsStringSync(); + } on Exception { + res = []; + } + return res; + } +} diff --git a/lib/network/data/network_model.dart b/lib/network/data/network_model.dart new file mode 100644 index 0000000000000000000000000000000000000000..f42bffafabfe8b772622147ab6b0e697dddfc463 --- /dev/null +++ b/lib/network/data/network_model.dart @@ -0,0 +1,16 @@ +class NetworkModel { + Status status; + T data; + String message; + + 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 new file mode 100644 index 0000000000000000000000000000000000000000..a451cf3934eafb869984372427c71a5aad9b6e95 --- /dev/null +++ b/lib/network/network_interface.dart @@ -0,0 +1,94 @@ +import 'dart:convert'; +import 'package:ppl_disabilitas/network/CustomException.dart'; +import 'package:http/http.dart' as http; +import 'dart:io'; + +class NetworkInterface { + //String key = KEY; + + // POST request + Future post({ + String url, //url nya apa + dynamic bodyParams, //data apa yang mau dikasih + bool isLogin, //dia login apa ngga + }) async { + var responseJson; + Map headersJson = + await _buildRequestHeader(isLogin); //butuh header apa ngga + try { + final response = await http.post( + "$url", + body: json.encode(bodyParams), + headers: headersJson, + ); + responseJson = _response(response); + } on SocketException { + throw FetchDataException("No Internet Connection"); + } + return responseJson; + } + + // GET request + Future get({ + String url, + bool isLogin, + }) async { + var responseJson; + Map headersJson = await _buildRequestHeader(isLogin); + try { + final response = await http.get( + "$url", + headers: headersJson, + ); + responseJson = _response(response); + } on SocketException { + throw FetchDataException("No Internet Connection"); + } + return responseJson; + } + + // buildRequestHeader: untuk nentuin pake header apa aja berdasarkan login apa ngga + Future> _buildRequestHeader(bool isLogin) async { + Map headers = Map(); + headers.putIfAbsent("Content-Type", () => "application/json"); + //if (isLogin) { + //List cookieFile = await CookiesInterface().getCookieFile( + // fileName: + // "userCookies"); //ngambil data dari yg udh disimpen di cookie + //print("cookieFile list --> ${cookieFile.toString()}"); + //print("check key here >>> $key"); + //setKey(cookieFile[2]); + //key = cookieFile[2]; + //headers.putIfAbsent( + // "Authorization", + // () => + // 'Token $key'); //ini kalau authorization nya ngga ada baru taro token nya + //headers.putIfAbsent("X-CSRFToken", () => cookieFile[0]); //csrf token + //headers.putIfAbsent( + // "Cookie", + // () => + // "csrftoken=${cookieFile[0]};sessionid=${cookieFile[1]}"); //cookie file + //print("headers --> ${headers}"); + //} + return headers; + } + + dynamic _response(http.Response response) { + switch (response.statusCode) { + case 200: + var responseJson = json.decode(response.body.toString()); + return responseJson; + case 400: + throw BadRequestException(response.body.toString()); + case 401: + + case 403: + throw UnauthorisedException(response.body.toString()); + case 500: + + default: + throw FetchDataException( + 'Error occured while Communication with Server with status : ${response.statusCode}'); + } + } +} diff --git a/lib/page/dashboard/dashboard.dart b/lib/page/dashboard/dashboard.dart index 1f4dcea180ad2772a05bc7cb2d5088c89bf6729d..a8c24ec04d86ccf7a26ad49651e23816c808e6e3 100644 --- a/lib/page/dashboard/dashboard.dart +++ b/lib/page/dashboard/dashboard.dart @@ -46,6 +46,7 @@ class DashboardState extends State { } void enableLocationService() async { + await location.changeSettings(accuracy: LocationAccuracy.HIGH); _serviceEnabled = await location.serviceEnabled(); if (!_serviceEnabled) { _serviceEnabled = await location.requestService(); @@ -72,7 +73,7 @@ class DashboardState extends State { Widget build(BuildContext context) { return Scaffold( drawer: BisaGoDrawer(), - body: Stack(children: [ + body: Stack(key: Key("Stack"),children: [ _buildGoogleMap(context), InkWell( key: Key("Navigate to Pencarian"), diff --git a/lib/page/filter_fasilitas/fasilitas.dart b/lib/page/filter_fasilitas/fasilitas.dart new file mode 100644 index 0000000000000000000000000000000000000000..bcbdd8fcc575fd983905e7eb0eb7445c1363b9d8 --- /dev/null +++ b/lib/page/filter_fasilitas/fasilitas.dart @@ -0,0 +1,754 @@ +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/filter_fasilitas/komentar.dart'; + +class Fasilitas extends StatefulWidget { + final String nama; + final String alamat; + final String url; + final String telpon; + Fasilitas({this.nama, this.alamat, this.url, this.telpon}); + @override + _FasilitasState createState() => _FasilitasState(); +} + +class _FasilitasState extends State { + var kursiRodaVal = false; + var liftVal = false; + var toiletDisabilitasVal = false; + var tempatIbadahVal = false; + var bidangMiringVal = false; + var parkirUmumVal = false; + var parkirDisabilitasVal = false; + var komentarTerbaru = false; + var komentarRatingTertinggi = false; + var komentarTerpopuler = false; + var showUrutan = true; + final KomentarBloc _bloc = KomentarBloc(); + @override + Widget build(BuildContext context) { + print('widget.telpon ${widget.url}'); + 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( + 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( + '08724981274', + 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: () { + /*...*/ + }, + 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), + ), + ], + ), + ), + ), + ], + ), + ), + // TODO change with komentar stream + 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: + final komentar = snapshot.data.data; + return ListView.builder( + shrinkWrap: true, + itemCount: komentar.allKomentar.length, + itemBuilder: (BuildContext context, int index) { + return Komentar( + dislike: + komentar.allKomentar[index].tidak_suka, + komentar: 'Lorem ipsum', + like: komentar.allKomentar[index].suka, + tags: ['#toiletdisabilitas', '#kursiroda'], + urlImage: [ + komentar.allKomentar[index].foto + ], + user: + komentar.allKomentar[index].nama_orang, + ); + }); + break; + case Status.ERROR: + return Center( + child: Text(snapshot.data.data.toString()), + ); + break; + } + } + return Container(); + }), + ], + ), + ), + ]), + ), + appBar: PreferredSize( + preferredSize: Size.fromHeight(55), + child: BisaGoAppBar(), + key: Key('Scaffold Text Field'), + ), + ); + } + + 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( + 'Urutan', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + splashColor: Colors.green[400], + highlightColor: Colors.green[400], + onTap: () => setStateModal(() { + print('no'); + showUrutan = true; + })), + 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( + 'Jenis Fasilitas', + style: TextStyle( + fontSize: 18, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + splashColor: Colors.green[400], + highlightColor: Colors.green[400], + onTap: () => setStateModal(() { + print("yes"); + 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 ? 0 : 1, + child: ListView( + children: [ + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: komentarTerbaru, + onChanged: (bool value) { + setStateModal(() { + komentarTerbaru = value; + }); + }, + ), + ), + Text( + "Komentar Terbaru", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: komentarTerpopuler, + onChanged: (bool value) { + setStateModal(() { + komentarTerpopuler = value; + }); + }, + ), + ), + Text( + "Komentar Terpopuler", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Container( + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: + greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: komentarTerpopuler, + onChanged: (bool value) { + setStateModal(() { + komentarTerpopuler = value; + }); + }, + ), + ), + Flexible( + child: Text( + "Komentar dengan Rating Tertinggi", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ), + ], + ), + ), + ], + ), + ), + Opacity( + opacity: showUrutan ? 1 : 0, + child: ListView( + children: [ + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: kursiRodaVal, + onChanged: (bool value) { + setStateModal(() { + kursiRodaVal = value; + }); + }, + ), + ), + Text( + "Kursi roda", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: liftVal, + onChanged: (bool value) { + setStateModal(() { + liftVal = value; + }); + }, + ), + ), + Text( + "Lift", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: toiletDisabilitasVal, + onChanged: (bool value) { + setStateModal(() { + toiletDisabilitasVal = value; + }); + }, + ), + ), + Text( + "Toilet Disabilitas", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: tempatIbadahVal, + onChanged: (bool value) { + setStateModal(() { + tempatIbadahVal = value; + }); + }, + ), + ), + Text( + "Tempat Ibadah", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: bidangMiringVal, + onChanged: (bool value) { + setStateModal(() { + bidangMiringVal = value; + }); + }, + ), + ), + Text( + "Bidang Miring (Ramp)", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: parkirUmumVal, + onChanged: (bool value) { + setStateModal(() { + parkirUmumVal = value; + }); + }, + ), + ), + Text( + "Parkir Umum", + style: TextStyle( + color: Colors.black, + fontSize: 18), + ), + ], + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Theme( + data: Theme.of(context).copyWith( + unselectedWidgetColor: greenPrimary, + ), + child: Checkbox( + checkColor: Colors.red, + activeColor: Colors.amberAccent, + value: parkirDisabilitasVal, + onChanged: (bool value) { + 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( + 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), + ), + ), + ), + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/page/filter_fasilitas/komentar.dart b/lib/page/filter_fasilitas/komentar.dart new file mode 100644 index 0000000000000000000000000000000000000000..4dbad48cffaec09ee0911901196625ea41d80588 --- /dev/null +++ b/lib/page/filter_fasilitas/komentar.dart @@ -0,0 +1,142 @@ +import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; + +class Komentar extends StatefulWidget { + final String user; + final int like; + final int dislike; + final List urlImage; + final String komentar; + final List tags; + + Komentar( + {@required this.user, + @required this.like, + @required this.dislike, + @required this.urlImage, + @required this.komentar, + @required this.tags}); + @override + _KomentarState createState() => _KomentarState(); +} + +class _KomentarState extends State { + @override + Widget build(BuildContext context) { + return 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( + children: [ + Container( + margin: EdgeInsets.only(bottom: regularSpace), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + widget.user, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + Row( + children: [ + Container( + margin: EdgeInsets.only(right: regularSpace), + child: Row( + children: [ + Icon(Icons.thumb_up, + color: Colors.green[800], size: 20), + Text( + '${widget.like} suka', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Colors.green[800], + ), + ), + ], + )), + Icon(Icons.thumb_down, color: redPrimary, size: 20), + Text( + '${widget.dislike} tidak suka', + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w600, + color: redPrimary, + ), + ), + ], + ) + ], + ), + ), + Container( + margin: EdgeInsets.only(bottom: regularSpace), + child: ClipRRect( + borderRadius: BorderRadius.circular(5), + child: Image.asset('assets/images/disabletoilet.jpg'), + )), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: Text( + widget.komentar, + softWrap: true, + textAlign: TextAlign.left, + style: TextStyle( + fontSize: 15, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + ), + ], + ), + Row( + children: [ + ...widget.tags.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( + tag, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + color: greenPrimary, + fontFamily: 'Muli', + ), + ), + ); + } +} diff --git a/lib/page/login/landing.dart b/lib/page/login/landing.dart deleted file mode 100644 index 50b5ae5c14897493beb482e4f5582c30094179af..0000000000000000000000000000000000000000 --- a/lib/page/login/landing.dart +++ /dev/null @@ -1,77 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:ppl_disabilitas/page/login/login.dart'; -import 'package:ppl_disabilitas/page/registrasi/registrasi.dart'; -import 'package:ppl_disabilitas/utils/customButton.dart'; - -class Landing extends StatelessWidget { - const Landing({Key key}) : super(key: key); - - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Color(0xff3A903A), - ), - backgroundColor: Color(0xff3A903A), - body: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Container( - margin: EdgeInsets.fromLTRB(20, 30, 20, 10), - alignment: Alignment.center, - child: ButtonTheme( - minWidth: double.infinity, - height: 60, - child: RaisedButton( - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: new BorderRadius.all(Radius.circular(10)), - ), - child: Text( - 'Masuk', - style: TextStyle(fontSize: 25, color: Color(0xff3A903A), fontWeight: FontWeight.bold), - ), - onPressed: () => _navigateToLogin(context), - ), - ) - ), - Container( - child: separator('ATAU', 20, 0xffFFFFFF, 2, 0xffFFFFFF), - ), - Container( - margin: EdgeInsets.fromLTRB(20, 10, 20, 30), - alignment: Alignment.center, - child: ButtonTheme( - minWidth: double.infinity, - height: 60, - child: RaisedButton( - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: new BorderRadius.all(Radius.circular(10)), - ), - child: Text( - 'Daftar', - style: TextStyle(fontSize: 25, color: Color(0xff3A903A), fontWeight: FontWeight.bold), - ), - onPressed: () => _navigateToRegistrasi(context), - ), - ) - ), - ], - ), - ), - ); - } - - void _navigateToLogin(BuildContext context) { - final route = MaterialPageRoute(builder: (_) => Login()); - Navigator.of(context).push(route); - } - - void _navigateToRegistrasi(BuildContext context) { - final route = MaterialPageRoute(builder: (_) => Registrasi()); - Navigator.of(context).push(route); - } - -} \ No newline at end of file diff --git a/lib/page/login/login.dart b/lib/page/login/login.dart index 8e2054b4420a4d1f3a6167dae1689d8a35d6418b..99cdf3156ab718eb26b627c29dc8cf550467c01b 100644 --- a/lib/page/login/login.dart +++ b/lib/page/login/login.dart @@ -1,10 +1,10 @@ -import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:ppl_disabilitas/config/styles.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 Login extends StatefulWidget{ @@ -13,15 +13,43 @@ class Login extends StatefulWidget{ class LoginState extends State { final GlobalKey _formKey = GlobalKey(); - String _accountCredential; - String _password; + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('bisaGO'), + elevation: 15, centerTitle: true, - backgroundColor: Color(0xff3A903A), + 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: () { + Navigator.pushNamed(context, '/register'); + }, + ), + ) + ], ), body: SingleChildScrollView( child: Form( @@ -45,19 +73,15 @@ class LoginState extends State { CustomTextField( title: 'Nomor Telepon atau Email', key: Key('Text Field Akun'), - onSaved: (input) { - _accountCredential = input; - }, validator: FieldValidator.validateEmail, + controller: emailController, ), CustomTextField( title: 'Password', key: Key('Text Field Password'), obsecure: true, - onSaved: (input) { - _password = input; - }, validator: FieldValidator.validatePassword, + controller: passwordController, ), Container( margin: EdgeInsets.fromLTRB(0, 30, 0, 10), @@ -91,6 +115,26 @@ class LoginState extends State { 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 = { + 'email' : email, + 'password' : password + }; +// var jsonData; + var response = await http.post('https://my.api.mockaroo.com/register.json?key=095ee610', body: data); + if(response.statusCode == 200) { +// jsonData = json.decode(response.body); + await Navigator.pushNamed(context, '/'); + } + else { + print(response.body); } } } \ No newline at end of file diff --git a/lib/page/pencarian/pencarian.dart b/lib/page/pencarian/pencarian.dart index 5e4a680c2eed5bdd1f02e93cdf49c03cefadda00..8e2c636bc4ae86f39791dcc370c1b381ccba58ba 100644 --- a/lib/page/pencarian/pencarian.dart +++ b/lib/page/pencarian/pencarian.dart @@ -1,14 +1,65 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/bloc/LokasiResponseBloc.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); - Widget appBarText = Text("Pencarian Lokasi"); + + /// 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] + .nama + .toLowerCase() + .contains(myController.text.toLowerCase())) { + tempList.add(places[i]); + } + } + } + setState(() { + currentSearch = tempList; + }); + }); + super.initState(); + } @override Widget build(BuildContext context) { @@ -17,7 +68,7 @@ class PencarianState extends State { backgroundColor: greenPrimary, leading: IconButton( icon: Icon(Icons.arrow_back_ios, size: 25), - key: Key("Back Icon Key"), + key: Key('Back Icon Key'), onPressed: () => Navigator.pop(context, 'Take me back')), title: Container( margin: EdgeInsets.only(top: doubleSpace, bottom: doubleSpace), @@ -26,7 +77,8 @@ class PencarianState extends State { borderRadius: doubleBorderRadius, boxShadow: regularShadow), child: TextFormField( - key: Key("Text Field Mau Kemana"), + controller: myController, + key: Key('Text Field Mau Kemana'), decoration: InputDecoration( contentPadding: EdgeInsets.all(0), isDense: false, @@ -44,127 +96,177 @@ class PencarianState extends State { fontFamily: 'Muli', fontWeight: FontWeight.w700), suffixIcon: IconButton( - icon: Icon( - Icons.mic, - color: greenPrimary, - size: 25, - ), - onPressed: () {})), + icon: Icon( + Icons.mic, + color: greenPrimary, + size: 25, + ), + onPressed: () {}, + )), ), ), ), - body: ListView( - padding: const EdgeInsets.all(8), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: EdgeInsets.only(left: doubleSpace, top: 10), - child: Text( - 'Hasil Pencarian', - style: TextStyle( - fontSize: 15, - color: Colors.black, - fontFamily: 'Muli', - ), - ), - ), - Container( - height: 90, - color: Colors.transparent, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircleAvatar( - backgroundColor: greenPrimary, - child: Text('Test'), - ), - Padding( - padding: EdgeInsets.all(doubleSpace), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'Margo City', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w800, - color: Colors.black, - fontFamily: 'Muli', - ), - ), - Text( - 'Jl. Margonda Raya No.358, Kemir...', - style: TextStyle( - fontSize: 15, - color: Colors.black, - fontFamily: 'Muli', - ), + StreamBuilder>( + stream: _bloc.recentSearchStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + switch (snapshot.data.status) { + case Status.LOADING: + return Center( + child: CircularProgressIndicator( + valueColor: AlwaysStoppedAnimation(greenPrimary), ), - ], - ), - ), - Icon( - Icons.arrow_forward_ios, - color: Colors.grey[400], - size: 20, - ) - ], - ), + ); + 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( - decoration: BoxDecoration( - border: Border(top: BorderSide(color: Colors.grey[400]))), + margin: EdgeInsets.only( + left: doubleSpace, top: regularSpace, bottom: smallSpace), + child: Text("Hasil Pencarian"), ), - Container( - height: 90, - color: Colors.transparent, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircleAvatar( - backgroundColor: greenPrimary, - child: Text('Test'), - ), - Padding( - padding: EdgeInsets.all(doubleSpace), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, + 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) { + print('$key - $places'); + return ListView.builder( + shrinkWrap: true, + itemCount: places.length, + itemBuilder: (context, index) { + return InkWell( + key: Key("$key-${places[index].nama}"), + onTap: () { + _bloc.saveRecentSearch(places[index]); + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) => Fasilitas( + alamat: places[index].alamat, + nama: places[index].nama, + telpon: places[index].telepon, + url: 'http://dummyimage.com/128x141.png/ff4444/ffffff', + ))); + }, + 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: [ + Row( children: [ - Text( - 'Margo City', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w800, - color: Colors.black, - fontFamily: 'Muli', - ), + CircleAvatar( + backgroundColor: greenPrimary, + child: Text('Test'), ), - Text( - 'Jl. Margonda Raya No.358, Kemir...', - style: TextStyle( - fontSize: 15, - color: Colors.black, - fontFamily: 'Muli', + Container( + padding: EdgeInsets.all(doubleSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + places[index].nama, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w800, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + Text( + places[index].alamat, + style: TextStyle( + fontSize: 15, + color: Colors.black, + fontFamily: 'Muli', + ), + ), + ], ), ), ], ), - ), - Icon( - Icons.arrow_forward_ios, - color: Colors.grey[400], - size: 20, - ) - ], + Icon( + Icons.arrow_forward_ios, + color: Colors.grey[400], + size: 20, + ) + ], + ), ), - ), - Container( - decoration: BoxDecoration( - border: Border(top: BorderSide(color: Colors.grey[400]))), - ), - ], - ), - ); + ); + }); } } diff --git a/lib/page/registrasi/registrasi.dart b/lib/page/registrasi/registrasi.dart index 59aae7185b4363954ce51f2b5454565f90f59149..38e3e76f0da07d6de884fc5b22253701a5108a8c 100644 --- a/lib/page/registrasi/registrasi.dart +++ b/lib/page/registrasi/registrasi.dart @@ -1,9 +1,12 @@ -import 'dart:async'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:ppl_disabilitas/config/styles.dart'; import 'package:ppl_disabilitas/utils/customButton.dart'; import 'package:ppl_disabilitas/utils/customTextField.dart'; +//import 'package:ppl_disabilitas/network/network_interface.dart'; +import 'package:ppl_disabilitas/model/user.dart'; +import 'package:ppl_disabilitas/utils/validator.dart'; +import 'package:http/http.dart' as http; class Registrasi extends StatefulWidget { RegistrasiState createState() => RegistrasiState(); @@ -15,9 +18,38 @@ class RegistrasiState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text('bisaGO'), + elevation: 15, centerTitle: true, - backgroundColor: Color(0xff3A903A), + 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( @@ -41,26 +73,38 @@ class RegistrasiState extends State { CustomTextField( title: 'Nama Lengkap', key: Key('Text Field Nama'), - validator: (input) => input.isEmpty ? "*Wajib diisi" : null, + validator: FieldValidator.validateName, + controller: nameController, ), CustomTextField( title: 'Nomor Telepon', key: Key('Text Field Nomor Telepon'), - validator: (input) => input.isEmpty ? "*Wajib diisi" : null, + validator: FieldValidator.validatePhoneNumber, + controller: phoneController, ), CustomTextField( - title: 'Email (Opsional)', + title: 'Email', key: Key('Text Field Email'), + controller: emailController, + validator: FieldValidator.validateEmail, ), CustomTextField( title: 'Password', key: Key('Text Field Password'), - validator: (input) => input.isEmpty ? "*Wajib diisi" : null, + obsecure: true, + validator: FieldValidator.validatePassword, + controller: passwordController, ), CustomTextField( title: 'Konfirmasi Password', key: Key('Text Field Konfirmasi Password'), - validator: (input) => input.isEmpty ? "*Wajib diisi" : null, + obsecure: true, + validator: (input) { + if (input != passwordController.text) { + return '*Password tidak sesuai. Coba lagi'; + } + return null; + }, ), Container( margin: EdgeInsets.fromLTRB(0, 30, 0, 10), @@ -88,10 +132,53 @@ class RegistrasiState extends State { ), ); } + void _validateLoginInput() async { final FormState form = _formKey.currentState; if (_formKey.currentState.validate()) { form.save(); + User user = User( + username: nameController.text.toString(), + phonenumber: phoneController.text.toString(), + email: emailController.text.toString(), + password: passwordController.text.toString() + ); + await createUser(user); } } -} \ No newline at end of file + + TextEditingController nameController = TextEditingController(); + TextEditingController phoneController = TextEditingController(); + TextEditingController emailController = TextEditingController(); + TextEditingController passwordController = TextEditingController(); + +// static Future register(User data) async { +// final response = await http.post( +// 'https://my.api.mockaroo.com/register.json?key=095ee610&__method=POST', +// body: data); +// if (response.statusCode == 200) { +// return true; +// } +// else { +// return false; +// } +// } +// var response = NetworkInterface().post( +// url: 'https://my.api.mockaroo.com/register.json?key=095ee610', +// bodyParams: data, +// isLogin: false +// ); +} + +Future createUser(User data) async { + final response = await http.post( + "https://my.api.mockaroo.com/register.json?key=095ee610&__method=POST", + headers: {"content-type": "application/json"}, + body: userToJson(data), + ); + if (response.statusCode == 200) { + return true; + } else { + return false; + } +} diff --git a/lib/repository/KomentarRepository.dart b/lib/repository/KomentarRepository.dart new file mode 100644 index 0000000000000000000000000000000000000000..a1bd088128787159dfdcb0527d45acf163a14de5 --- /dev/null +++ b/lib/repository/KomentarRepository.dart @@ -0,0 +1,15 @@ +import 'package:ppl_disabilitas/model/komentar.dart'; +import 'package:ppl_disabilitas/network/network_interface.dart'; + +class KomentarRepository { + NetworkInterface _network = NetworkInterface(); + + Future fetchKomentar() async { + final response = await _network.get( + url: 'https://my.api.mockaroo.com/postingan.json?key=dbcde960', + isLogin: false); + print(response); + return KomentarList( + response.map((komentar) => KomentarModel.fromJson(komentar)).toList()); + } +} diff --git a/lib/repository/LokasiRepository.dart b/lib/repository/LokasiRepository.dart new file mode 100644 index 0000000000000000000000000000000000000000..d6e7163161fa6d5bf846ae21a1d5ae0cb278a5a4 --- /dev/null +++ b/lib/repository/LokasiRepository.dart @@ -0,0 +1,43 @@ +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 { + NetworkInterface _network = NetworkInterface(); + CookiesInterface _cookie = CookiesInterface(); + Future fetchLokasi() async { + final response = await _network.get( + url: 'https://my.api.mockaroo.com/mall.json?key=dbcde960', + 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 { + Map searchToMap = recentSearch.toJson(); + await _cookie.createSearchHistoryCookie(recentSearch: searchToMap); + } +} diff --git a/lib/utils/customButton.dart b/lib/utils/customButton.dart index 2c71a88fa9d9d3b7c48c70ce35bb06c2aea9a92d..cdab226fa51da5285c4086510454f0a642dd31c8 100644 --- a/lib/utils/customButton.dart +++ b/lib/utils/customButton.dart @@ -11,7 +11,7 @@ Color fillColor, Color textColor, void function()) { elevation: 0.0, color: fillColor, shape: RoundedRectangleBorder( - borderRadius: new BorderRadius.all(Radius.circular(10)), + borderRadius: BorderRadius.all(Radius.circular(10)), ), child: Text( text, @@ -71,36 +71,30 @@ Widget googleButton() { ], color: Colors.white, ), - child: Row( + child: Stack( children: [ - Expanded( - flex: 1, - child: Container( - padding: EdgeInsets.all(15), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(10), - topLeft: Radius.circular(10)), - ), - alignment: Alignment.center, - child: Image( - image: NetworkImage('https://upload.wikimedia.org/wikipedia/commons/thumb/5/53/Google_%22G%22_Logo.svg/512px-Google_%22G%22_Logo.svg.png'), - ), + 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, ), ), - Expanded( - flex: 6, - child: 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) - ), + 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) ), ), ], diff --git a/lib/utils/customTextField.dart b/lib/utils/customTextField.dart index 971a1edf05bdcde6801e518afe11cb3d0ba7fed5..73c5f4266c5365ebb7e94ff16164cbef13259d47 100644 --- a/lib/utils/customTextField.dart +++ b/lib/utils/customTextField.dart @@ -8,6 +8,7 @@ class CustomTextField extends StatelessWidget { this.obsecure = false, this.key, this.validator, + this.controller, this.onSaved}); final String title; final Key key; @@ -15,10 +16,10 @@ class CustomTextField extends StatelessWidget { final String hint; final bool obsecure; final FormFieldValidator validator; + final TextEditingController controller; @override Widget build(BuildContext context) { - key: key; return Container( margin: EdgeInsets.symmetric(vertical: 10), child: Column( @@ -34,6 +35,7 @@ class CustomTextField extends StatelessWidget { TextFormField( onSaved: onSaved, validator: validator, + controller: controller, autofocus: true, obscureText: obsecure, style: TextStyle( diff --git a/lib/utils/validator.dart b/lib/utils/validator.dart index 97649872915f4a95cac43e39946ccf77f509f871..f824999eef0dd6beac957d399c0ffe52740dc88b 100644 --- a/lib/utils/validator.dart +++ b/lib/utils/validator.dart @@ -2,19 +2,43 @@ class FieldValidator { 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 = new RegExp(pattern); + RegExp regex = RegExp(pattern); if (value.isEmpty) return '*Wajib diisi'; - if (!regex.hasMatch(value)) + if (!regex.hasMatch(value)) { return '*Masukkan email yang valid'; - else + } 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 + 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; + } } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 9ca95dc282126c7dfcf5497f5b3f43209533f235..d360acc26878a43bc8f57ce483f46b6f8a836156 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,7 +14,7 @@ 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: @@ -25,19 +25,20 @@ dependencies: location: ^2.5.3 flutter_plugin_android_lifecycle: ^1.0.6 flutter_polyline_points: ^0.1.0 - # The following adds the Cupertino Icons font to your application. - # Use with the CupertinoIcons class for iOS style icons. + 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 dev_dependencies: flutter_test: sdk: flutter - image_test_utils: ^1.0.0 flutter_launcher_icons: ^0.7.4 # Linter dependency pedantic: ^1.8.0 # The default Linter package used in Google + build_runner: ^1.8.0 flutter_icons: android: "launcher_icon" @@ -63,6 +64,9 @@ flutter: - 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. 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/fasilitas_test.dart b/test/fasilitas_test.dart new file mode 100644 index 0000000000000000000000000000000000000000..a689a5493cb526ff2debbbc214c8919ca799391c --- /dev/null +++ b/test/fasilitas_test.dart @@ -0,0 +1,65 @@ +// 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/filter_fasilitas/fasilitas.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 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.byType(Container), findsNWidgets(28)); + expect(find.byType(Row), findsNWidgets(17)); + expect(find.byType(Column), findsNWidgets(4)); + 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); + // filter + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(Icon), findsNWidgets(5)); + await tester.tap(find.byKey(Key('Tambah Informasi'))); + 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', + ))); + // Search for the childWidget in the tree and verify it exists. + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(Container), findsNWidgets(10)); + expect(find.byType(Icon), findsNWidgets(4)); + expect(find.byType(Column), findsNWidgets(2)); + expect(find.byType(Row), findsNWidgets(5)); + expect(find.byType(Text), findsNWidgets(7)); + expect(find.byType(Flexible), findsNWidgets(2)); + expect(find.byType(FlatButton), findsNWidgets(2)); + }); + +} diff --git a/test/login_test.dart b/test/login_test.dart index 90b1c685d25b0c6bc006b199f093e1b47f670cb3..0a7189598f026cee9ea849622a43dee8597aae61 100644 --- a/test/login_test.dart +++ b/test/login_test.dart @@ -1,56 +1,28 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:image_test_utils/image_test_utils.dart'; - -import 'package:ppl_disabilitas/utils/validator.dart'; import 'package:ppl_disabilitas/page/login/login.dart'; +//import 'package:http/http.dart' as http; void main() { testWidgets('Find Username Text Field', (WidgetTester tester) async { - provideMockedNetworkImages(() async { - final textFieldKey = Key("Text Field Akun"); - await tester.pumpWidget(MaterialApp(home: Login())); - expect(find.byKey(textFieldKey), findsOneWidget); - }); + 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 { - provideMockedNetworkImages(() async { - final textFieldKey = Key("Text Field Password"); - await tester.pumpWidget(MaterialApp(home: Login())); - expect(find.byKey(textFieldKey), findsOneWidget); - }); - }); - - - 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); - }); + final textFieldKey = Key("Text Field Password"); + await tester.pumpWidget(MaterialApp(home: Login())); + expect(find.byKey(textFieldKey), findsOneWidget); + }); + +// test('Valid API end point for validating user', () async { +// Map data = { +// 'email' : 'dummy@dummy.com', +// 'password' : 'dummypassword', +// }; +// var result = await http.post('https://my.api.mockaroo.com/register.json?key=095ee610', body: data); +// expect(result.statusCode, 200); +// }); } \ 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/navigation_test.dart b/test/navigation_test.dart deleted file mode 100644 index d8952af10976e7f65cee572985b8f078949ec8b7..0000000000000000000000000000000000000000 --- a/test/navigation_test.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:mockito/mockito.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; -import 'package:pedantic/pedantic.dart'; - - -class MockNavigatorObserver extends Mock implements NavigatorObserver {} - -void main() { - group('Dashboard navigation tests', () { - NavigatorObserver mockObserver; - - setUp(() { - mockObserver = MockNavigatorObserver(); - }); - - 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.pumpAndSettle(); - } - - testWidgets( - 'when tapping text form field, should navigate to pencarina 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); - 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'); - - - - }); - }); -} \ No newline at end of file diff --git a/test/pencarian_test.dart b/test/pencarian_test.dart index 43546747e61eccf3c9b60b39e43965a131a56741..db66d48281936f9d23071a6a5fd3ca0838684ae5 100644 --- a/test/pencarian_test.dart +++ b/test/pencarian_test.dart @@ -6,19 +6,52 @@ // 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 { - // Provide the childWidget to the Container. 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), findsOneWidget); - expect(find.byType(Container), findsNWidgets(7)); - expect(find.byType(Icon), findsNWidgets(5)); + //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 { @@ -27,4 +60,13 @@ void main() { 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/registrasi_test.dart b/test/registrasi_test.dart index d0abba49410b0263856fcf93184b594cda22c379..cfc2e29150660e95affaf7335b5b12c7e8789c46 100644 --- a/test/registrasi_test.dart +++ b/test/registrasi_test.dart @@ -1,49 +1,52 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:image_test_utils/image_test_utils.dart'; - -import 'package:ppl_disabilitas/utils/validator.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 { - provideMockedNetworkImages(() async { - final textFieldKey = Key("Text Field Nama"); - await tester.pumpWidget(MaterialApp(home: Registrasi())); - expect(find.byKey(textFieldKey), findsOneWidget); - }); + 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 { - provideMockedNetworkImages(() async { - final textFieldKey = Key("Text Field Nomor Telepon"); - await tester.pumpWidget(MaterialApp(home: Registrasi())); - expect(find.byKey(textFieldKey), findsOneWidget); - }); + 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 { - provideMockedNetworkImages(() async { - final textFieldKey = Key("Text Field Email"); - await tester.pumpWidget(MaterialApp(home: Registrasi())); - expect(find.byKey(textFieldKey), findsOneWidget); - }); + 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 { - provideMockedNetworkImages(() async { - final textFieldKey = Key("Text Field Password"); - await tester.pumpWidget(MaterialApp(home: Registrasi())); - expect(find.byKey(textFieldKey), findsOneWidget); - }); + 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 { - provideMockedNetworkImages(() async { - final textFieldKey = Key("Text Field Konfirmasi Password"); - await tester.pumpWidget(MaterialApp(home: Registrasi())); - expect(find.byKey(textFieldKey), findsOneWidget); - }); + 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/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 0337d3091bf1d658deecd094f759046644658ace..0a223972d3cab637dbed4c8c3d3ed006175fa98c 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -14,7 +14,7 @@ void main() { await tester.pumpWidget(MaterialApp(home: Dashboard())); // Search for the childWidget in the tree and verify it exists. expect(find.byType(Scaffold), findsOneWidget); - expect(find.byType(Stack), findsNWidgets(2)); + expect(find.byKey(Key("Stack")), findsOneWidget); expect(find.byType(TextFormField), findsOneWidget); expect(find.byType(Icon), findsNWidgets(3)); expect(find.text('Kamu mau kemana?'), findsOneWidget);