From 5eb707b2eb9f59df8df3dafb23046a4e22d4d561 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 21 Feb 2020 17:57:59 +0700 Subject: [PATCH 01/19] [GREEN] implementasi widget google map in dashboard --- test/widget_test.dart | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/test/widget_test.dart b/test/widget_test.dart index e702e83..89dfbbb 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -9,33 +9,25 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; - -import 'package:ppl_disabilitas/main.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; void main() { testWidgets('finds a google map in dashboard', (WidgetTester tester) async { Completer _controller = Completer(); - final googleMap = Builder(builder: (BuildContext context) { - Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - child: GoogleMap( - mapType: MapType.normal, - initialCameraPosition: - CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12), - onMapCreated: (GoogleMapController controller) { - _controller.complete(controller); - }, - ), - ); - }); + final googleMap = GoogleMap( + mapType: MapType.normal, + initialCameraPosition: + CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12), + onMapCreated: (GoogleMapController controller) { + _controller.complete(controller); + }, + ); // Provide the childWidget to the Container. - await tester.pumpWidget(Dashboard()); + await tester.pumpWidget(MaterialApp(home: Dashboard())); // Search for the childWidget in the tree and verify it exists. - expect(find.byWidget(googleMap), findsOneWidget); + expect(find.byType(GoogleMap), findsOneWidget); }); } -- GitLab From fe1cce8549394941d8199aff602fc02a9d63ae7d Mon Sep 17 00:00:00 2001 From: "agnes.handoko" Date: Fri, 21 Feb 2020 18:27:35 +0700 Subject: [PATCH 02/19] [RED] test for navigation bar widget in dashboard --- test/widget_test.dart | 51 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/widget_test.dart b/test/widget_test.dart index e702e83..c582eb3 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -38,4 +38,55 @@ void main() { // Search for the childWidget in the tree and verify it exists. expect(find.byWidget(googleMap), findsOneWidget); }); + + testWidgets('finds a navigation bar', (WidgetTester tester) async { + Completer _controller = Completer(); + final navBar = Builder(builder: (BuildContext context) { + MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Basic AppBar'), + actions: [ + // action button + IconButton( + icon: Icon(choices[0].icon), + onPressed: () { + _select(choices[0]); + }, + ), + // action button + IconButton( + icon: Icon(choices[1].icon), + onPressed: () { + _select(choices[1]); + }, + ), + // overflow menu + PopupMenuButton( + onSelected: _select, + itemBuilder: (BuildContext context) { + return choices.skip(2).map((Choice choice) { + return PopupMenuItem( + value: choice, + child: Text(choice.title), + ); + }).toList(); + }, + ), + ], + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: ChoiceCard(choice: _selectedChoice), + ), + ), + ); + }); + + // Provide the childWidget to the Container. + await tester.pumpWidget(Dashboard()); + + // Search for the childWidget in the tree and verify it exists. + expect(find.byWidget(navBar), findsOneWidget); + }); } -- GitLab From 787bb7d5f7dd939f873cf58a7767302c8669d003 Mon Sep 17 00:00:00 2001 From: Firriyal Bin Yahya Date: Fri, 21 Feb 2020 18:35:12 +0700 Subject: [PATCH 03/19] [CHORE] check username --- test/widget_test.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/widget_test.dart b/test/widget_test.dart index 89dfbbb..a8e8abc 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -24,7 +24,7 @@ void main() { }, ); - // Provide the childWidget to the Container. + await tester.pumpWidget(MaterialApp(home: Dashboard())); // Search for the childWidget in the tree and verify it exists. -- GitLab From d8d3bb2ad405e10cb11c64b61e8e2b4e27cb9a1b Mon Sep 17 00:00:00 2001 From: "agnes.handoko" Date: Sat, 22 Feb 2020 11:28:22 +0700 Subject: [PATCH 04/19] [CHORE] add initial navigation bar --- lib/page/dashboard/dashboard.dart | 148 ++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 30 deletions(-) diff --git a/lib/page/dashboard/dashboard.dart b/lib/page/dashboard/dashboard.dart index b34ae2e..550c405 100644 --- a/lib/page/dashboard/dashboard.dart +++ b/lib/page/dashboard/dashboard.dart @@ -16,51 +16,139 @@ class DashboardState extends State { } double zoomVal = 5.0; - + //https://flutter.dev/docs/cookbook/design/drawer @override Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - leading: IconButton( - icon: Icon(Icons.arrow_left), - onPressed: () { - // - }), - title: Text("New York"), - actions: [ - IconButton( - icon: Icon(Icons.search), - onPressed: () { - // - }), - ], + return MaterialApp( + theme: ThemeData( + // Define the default brightness and colors. + primaryColor: Color.fromRGBO(58, 144, 58, 1), + accentColor: Colors.cyan[600], + + // Define the default font family. + fontFamily: 'Comfortaa', + + // Define the default TextTheme. Use this to specify the default + // text styling for headlines, titles, bodies of text, and more. + textTheme: TextTheme( + title: TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic), + headline: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic), + body1: TextStyle(fontSize: 14.0, fontFamily: 'Hind'), + ), ), - body: Stack( - children: [ + home: Scaffold( + drawer: Drawer( + // Add a ListView to the drawer. This ensures the user can scroll + // through the options in the drawer if there isn't enough vertical + // space to fit everything. + child: ListView( + // Important: Remove any padding from the ListView. + padding: EdgeInsets.zero, + children: [ + DrawerHeader( + child: Text('Drawer Header'), + decoration: BoxDecoration( + color: Color.fromRGBO(58, 144, 58, 1), + ), + ), + ListTile( + title: Text('Item 1'), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + ListTile( + title: Text('Item 2'), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + ], + ), + ), + appBar: AppBar( + elevation: 15, + title: Center( + child: Text( + "bisaGo", + textAlign: TextAlign.center, + ), + ), + ), + body: Stack(children: [ _buildGoogleMap(context), - ], + ]), ), ); } Widget _buildGoogleMap(BuildContext context) { return Container( - height: MediaQuery - .of(context) - .size - .height, - width: MediaQuery - .of(context) - .size - .width, + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, child: GoogleMap( mapType: MapType.normal, - initialCameraPosition: CameraPosition( - target: LatLng(40.712776, -74.005974), zoom: 12), + initialCameraPosition: + CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12), onMapCreated: (GoogleMapController controller) { _controller.complete(controller); }, ), ); } -} \ No newline at end of file + + Choice _selectedChoice = choices[0]; // The app's "state". + + void _select(Choice choice) { + // Causes the app to rebuild with the new _selectedChoice. + setState(() { + _selectedChoice = choice; + }); + } +} + +class Choice { + const Choice({this.title, this.icon}); + + final String title; + final IconData icon; +} + +const List choices = const [ + const Choice(title: 'Car', icon: Icons.directions_car), + const Choice(title: 'Bicycle', icon: Icons.directions_bike), + const Choice(title: 'Boat', icon: Icons.directions_boat), + const Choice(title: 'Bus', icon: Icons.directions_bus), + const Choice(title: 'Train', icon: Icons.directions_railway), + const Choice(title: 'Walk', icon: Icons.directions_walk), +]; + +class ChoiceCard extends StatelessWidget { + const ChoiceCard({Key key, this.choice}) : super(key: key); + + final Choice choice; + + @override + Widget build(BuildContext context) { + final TextStyle textStyle = Theme.of(context).textTheme.display1; + return Card( + color: Colors.white, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Icon(choice.icon, size: 128.0, color: textStyle.color), + Text(choice.title, style: textStyle), + ], + ), + ), + ); + } +} -- GitLab From 4afe512e384cbf49e07221f21da7cbf19c58c8d8 Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 15:01:12 +0700 Subject: [PATCH 05/19] [RED] Shows dashboard page on app start --- .gitlab-ci.yml | 3 ++- test/widget_test.dart | 17 +++++------------ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4cfb91b..3fa72cc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,8 +8,9 @@ variables: Test: stage: test - image: jro7/flutter_lcov script: + - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.7-stable.tar.xz && tar xf flutter.tar.xz -C / + - export PATH=$PATH:/flutter/bin - echo Testing $APP_NAME - flutter doctor -v - flutter test --coverage diff --git a/test/widget_test.dart b/test/widget_test.dart index a8e8abc..438f705 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -10,24 +10,17 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:ppl_disabilitas/main.dart'; import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; void main() { testWidgets('finds a google map in dashboard', (WidgetTester tester) async { - Completer _controller = Completer(); - final googleMap = GoogleMap( - mapType: MapType.normal, - initialCameraPosition: - CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12), - onMapCreated: (GoogleMapController controller) { - _controller.complete(controller); - }, - ); - - await tester.pumpWidget(MaterialApp(home: Dashboard())); - // Search for the childWidget in the tree and verify it exists. expect(find.byType(GoogleMap), findsOneWidget); }); + testWidgets('Shows dashboard on App Start', (WidgetTester tester) async { + await tester.pumpWidget(MyApp()); + expect(find.byType(Dashboard), findsOneWidget); + }); } -- GitLab From cf90ba443047b10cf8ec74abd53fe550058757a6 Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 15:01:55 +0700 Subject: [PATCH 06/19] [GREEN] detect device's current location on dashboard --- .flutter-plugins-dependencies | 2 +- android/app/src/debug/AndroidManifest.xml | 1 + android/build.gradle | 2 +- android/gradle.properties | 3 + assets/icon/2x/current_loc.png | Bin 0 -> 5898 bytes assets/icon/3x/current_loc.png | Bin 0 -> 9020 bytes assets/icon/current_loc.png | Bin 0 -> 2687 bytes assets/icon/loc.png | Bin 0 -> 1313 bytes lib/page/dashboard/dashboard.dart | 83 ++++++++++++++++++---- pubspec.yaml | 9 +-- 10 files changed, 79 insertions(+), 21 deletions(-) create mode 100644 assets/icon/2x/current_loc.png create mode 100644 assets/icon/3x/current_loc.png create mode 100644 assets/icon/current_loc.png create mode 100644 assets/icon/loc.png diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index d884d26..870e0c8 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"google_maps_flutter","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"path_provider","dependencies":[]}]} \ No newline at end of file +{"_info":"// This is a generated file; do not edit or check into version control.","dependencyGraph":[{"name":"flutter_plugin_android_lifecycle","dependencies":[]},{"name":"google_maps_flutter","dependencies":["flutter_plugin_android_lifecycle"]},{"name":"location","dependencies":[]},{"name":"path_provider","dependencies":[]}]} \ No newline at end of file diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index 3883899..eac5119 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -4,4 +4,5 @@ to allow setting breakpoints, to provide hot reload, etc. --> + diff --git a/android/build.gradle b/android/build.gradle index 3100ad2..abfc160 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.google.gms:google-services:4.2.0' } } @@ -17,7 +18,6 @@ allprojects { jcenter() } } - rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" diff --git a/android/gradle.properties b/android/gradle.properties index 38c8d45..28276e2 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -2,3 +2,6 @@ org.gradle.jvmargs=-Xmx1536M android.enableR8=true android.useAndroidX=true android.enableJetifier=true +android.enableJetifier=true +android.useAndroidX=true +org.gradle.jvmargs=-Xmx1536M diff --git a/assets/icon/2x/current_loc.png b/assets/icon/2x/current_loc.png new file mode 100644 index 0000000000000000000000000000000000000000..1c55a3058fc5c1429bac6949380435d055b2c689 GIT binary patch literal 5898 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 literal 0 HcmV?d00001 diff --git a/assets/icon/3x/current_loc.png b/assets/icon/3x/current_loc.png new file mode 100644 index 0000000000000000000000000000000000000000..930d897dceee528d3c2b13135718a712246099f8 GIT binary patch literal 9020 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 DashboardState(); } class DashboardState extends State { - Completer _controller = Completer(); + final Completer _controller = Completer(); + final double cameraZoom = 16; + final LatLng defaultLocation = LatLng(-6.1753924, 106.8249641); + final String currentLocationIcon = "assets/icon/current_loc.png"; + Location location; + Set _markers = Set(); + LocationData currentLocation; + BitmapDescriptor sourceIcon; @override void initState() { super.initState(); + location = new Location(); + location.onLocationChanged().listen((LocationData cLoc) { + currentLocation = cLoc; + updatePinOnMap(); + }); + // set custom marker pins + setSourceAndDestinationIcons(); + // set the initial location + setInitialLocation(); } - double zoomVal = 5.0; - @override Widget build(BuildContext context) { return Scaffold( @@ -44,23 +58,62 @@ class DashboardState extends State { } Widget _buildGoogleMap(BuildContext context) { + CameraPosition initialCameraPosition = CameraPosition( + target: defaultLocation, + zoom: cameraZoom, + ); + if (currentLocation != null) { + initialCameraPosition = CameraPosition( + target: LatLng(currentLocation.latitude, currentLocation.longitude), + zoom: cameraZoom, + ); + } return Container( - height: MediaQuery - .of(context) - .size - .height, - width: MediaQuery - .of(context) - .size - .width, + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, child: GoogleMap( + markers: _markers, mapType: MapType.normal, - initialCameraPosition: CameraPosition( - target: LatLng(40.712776, -74.005974), zoom: 12), + initialCameraPosition: initialCameraPosition, onMapCreated: (GoogleMapController controller) { _controller.complete(controller); }, ), ); } -} \ No newline at end of file + + void setSourceAndDestinationIcons() async { + sourceIcon = await BitmapDescriptor.fromAssetImage( + ImageConfiguration(devicePixelRatio: 5), currentLocationIcon); + } + + void updatePinOnMap() async { + // create a new CameraPosition instance + // every time the location changes, so the camera + // follows the pin as it moves with an animation + CameraPosition cPosition = CameraPosition( + zoom: cameraZoom, + target: LatLng(currentLocation.latitude, currentLocation.longitude), + ); + final GoogleMapController controller = await _controller.future; + controller.animateCamera(CameraUpdate.newCameraPosition(cPosition)); + // do this inside the setState() so Flutter gets notified + // that a widget update is due + setState(() { + // updated position + var pinPosition = + LatLng(currentLocation.latitude, currentLocation.longitude); + _markers.removeWhere((m) => m.markerId.value == 'currentLocationPin'); + _markers.add(Marker( + markerId: MarkerId('currentLocationPin'), + position: pinPosition, // updated position + icon: sourceIcon)); + }); + } + + void setInitialLocation() async { + // set the initial location by pulling the user's + // current location from the location's getLocation() + currentLocation = await location.getLocation(); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 4006f33..78fb533 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,7 +22,8 @@ dependencies: http: ^0.12.0+2 path_provider: ^0.4.1 intl: - + location: ^2.4.0 + 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. cupertino_icons: ^0.1.2 @@ -45,9 +46,9 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - assets/icon/loc.png + - assets/icon/current_loc.png # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. -- GitLab From 5f901d654629545f05a8bd4a76901c0140cce05a Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 15:28:29 +0700 Subject: [PATCH 07/19] [CHORE] add default sizing and color of the app --- lib/config/styles.dart | 21 +++++++++++++++++++++ lib/main.dart | 20 +++++++------------- lib/main_dev.dart | 2 +- lib/page/dashboard/dashboard.dart | 10 +++++----- test/widget_test.dart | 9 +-------- 5 files changed, 35 insertions(+), 27 deletions(-) diff --git a/lib/config/styles.dart b/lib/config/styles.dart index e69de29..3b140b6 100644 --- a/lib/config/styles.dart +++ b/lib/config/styles.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; + +final Color greenPrimary = Color(0xff3A903A); +final Color redPrimary = Color(0xffC60000); +final Color bluePrimary = Color(0xff537AC6); + +final double smallSpace = 4.0; +final double regularSpace = 8.0; +final double doubleSpace = 16.0; +final double tripleSpace = 32.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)) +]; +final BorderRadius regularBorderRadius = BorderRadius.circular(10); +final BorderRadius doubleBorderRadius = BorderRadius.circular(20); diff --git a/lib/main.dart b/lib/main.dart index bb20e5d..30d723a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,29 +1,23 @@ import 'package:flutter/material.dart'; +import 'package:ppl_disabilitas/config/styles.dart'; import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; import 'flavor/flavor.dart'; void main() { ApiFlavor.flavor = BuildFlavor.production.toString(); - runApp(MyApp()); + runApp(BisaGo()); } -class MyApp extends StatelessWidget { +class BisaGo extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'bisaGo', theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, + primarySwatch: greenPrimary, + fontFamily: 'Muli', + backgroundColor: Colors.white, ), home: Dashboard(), ); diff --git a/lib/main_dev.dart b/lib/main_dev.dart index c20de18..e8dc8f6 100644 --- a/lib/main_dev.dart +++ b/lib/main_dev.dart @@ -4,5 +4,5 @@ import 'main.dart'; void main() { ApiFlavor.flavor = BuildFlavor.development.toString(); - runApp(MyApp()); + runApp(BisaGo()); } \ No newline at end of file diff --git a/lib/page/dashboard/dashboard.dart b/lib/page/dashboard/dashboard.dart index a0cb901..185c313 100644 --- a/lib/page/dashboard/dashboard.dart +++ b/lib/page/dashboard/dashboard.dart @@ -11,11 +11,11 @@ class DashboardState extends State { final Completer _controller = Completer(); final double cameraZoom = 16; final LatLng defaultLocation = LatLng(-6.1753924, 106.8249641); - final String currentLocationIcon = "assets/icon/current_loc.png"; + final String currentLocationIconAsset = "assets/icon/current_loc.png"; Location location; Set _markers = Set(); LocationData currentLocation; - BitmapDescriptor sourceIcon; + BitmapDescriptor currentLocationIcon; @override void initState() { @@ -83,8 +83,8 @@ class DashboardState extends State { } void setSourceAndDestinationIcons() async { - sourceIcon = await BitmapDescriptor.fromAssetImage( - ImageConfiguration(devicePixelRatio: 5), currentLocationIcon); + currentLocationIcon = await BitmapDescriptor.fromAssetImage( + ImageConfiguration(devicePixelRatio: 5), currentLocationIconAsset); } void updatePinOnMap() async { @@ -107,7 +107,7 @@ class DashboardState extends State { _markers.add(Marker( markerId: MarkerId('currentLocationPin'), position: pinPosition, // updated position - icon: sourceIcon)); + icon: currentLocationIcon)); }); } diff --git a/test/widget_test.dart b/test/widget_test.dart index 438f705..8d274b8 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -1,10 +1,3 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility that Flutter provides. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - import 'dart:async'; import 'package:flutter/material.dart'; @@ -20,7 +13,7 @@ void main() { expect(find.byType(GoogleMap), findsOneWidget); }); testWidgets('Shows dashboard on App Start', (WidgetTester tester) async { - await tester.pumpWidget(MyApp()); + await tester.pumpWidget(BisaGo()); expect(find.byType(Dashboard), findsOneWidget); }); } -- GitLab From 71471df7fd9f034946a0631558ac526c06ef0d1b Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 16:05:02 +0700 Subject: [PATCH 08/19] Update test CI script --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3fa72cc..2b04497 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,6 +14,7 @@ Test: - echo Testing $APP_NAME - flutter doctor -v - flutter test --coverage + - apt-get install lcov -y - lcov --summary coverage/lcov.info - genhtml coverage/lcov.info --output=coverage coverage: '/lines......: \d+\.\d+\%/' -- GitLab From 98c86d183cd43665cccfa655de13bee743611c1f Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 16:14:25 +0700 Subject: [PATCH 09/19] [CHORE] remove primary color from theme --- lib/main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 30d723a..d8616fd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,7 +15,6 @@ class BisaGo extends StatelessWidget { return MaterialApp( title: 'bisaGo', theme: ThemeData( - primarySwatch: greenPrimary, fontFamily: 'Muli', backgroundColor: Colors.white, ), -- GitLab From 67228f7df02e76e915686c5a5415b035e731c2ea Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 16:19:53 +0700 Subject: [PATCH 10/19] Update gitlab ci --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2b04497..403408d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,7 +14,7 @@ Test: - echo Testing $APP_NAME - flutter doctor -v - flutter test --coverage - - apt-get install lcov -y + - apt-get install -y lcov - lcov --summary coverage/lcov.info - genhtml coverage/lcov.info --output=coverage coverage: '/lines......: \d+\.\d+\%/' -- GitLab From c4f06bb8908ea410d0a5b4e6e64f8aba8464d070 Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 16:35:34 +0700 Subject: [PATCH 11/19] [CHORE] Update CI --- .gitlab-ci.yml | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 403408d..169d35f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,23 +6,32 @@ stages: variables: APP_NAME: "bisaGo" +image: michael09/flutter:latest + Test: stage: test script: - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.7-stable.tar.xz && tar xf flutter.tar.xz -C / - - export PATH=$PATH:/flutter/bin - - echo Testing $APP_NAME - - flutter doctor -v + - flutter test --machine > tests.output - flutter test --coverage - - apt-get install -y lcov - lcov --summary coverage/lcov.info - - genhtml coverage/lcov.info --output=coverage coverage: '/lines......: \d+\.\d+\%/' artifacts: name: mobile-coverage paths: - $CI_PROJECT_DIR/coverage +test:sonarqube: + dependencies: + - test:flutter + stage: sonarqube + before_script: + - export PATH=$PATH:/sdk/flutter/bin/cache/dart-sdk/bin + - flutter pub get + script: + - sonar-scanner -Dsonar.login=$SONARQUBE_TOKEN -Dsonar.branch.name=$CI_COMMIT_REF_NAME -Dsonar.projectKey=$SONARQUBE_PROJECT_KEY + only: + - master + - staging DeployToProduction: @@ -37,7 +46,6 @@ DeployToProduction: refs: - master before_script: - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.7-stable.tar.xz && tar xf flutter.tar.xz -C / - export PATH=$PATH:/flutter/bin - apt-get update && apt-get install gnupg -y - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs @@ -63,7 +71,6 @@ DeployToStaging: refs: - staging before_script: - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.7-stable.tar.xz && tar xf flutter.tar.xz -C / - export PATH=$PATH:/flutter/bin - apt-get update && apt-get install gnupg -y - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs @@ -89,7 +96,6 @@ DeployToDevelopment: refs: - /^US-.*$/ before_script: - - wget --quiet --output-document=flutter.tar.xz https://storage.googleapis.com/flutter_infra/releases/stable/linux/flutter_linux_v1.12.13+hotfix.7-stable.tar.xz && tar xf flutter.tar.xz -C / - export PATH=$PATH:/flutter/bin - apt-get update && apt-get install gnupg -y - curl -sL https://deb.nodesource.com/setup_12.x | bash - && apt-get install -y nodejs -- GitLab From 550ef03948f5d0ee199dd925866e3fbdf89e03b6 Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 16:56:38 +0700 Subject: [PATCH 12/19] [CHORE] update CI --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 169d35f..5d88dd8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,10 +20,10 @@ Test: paths: - $CI_PROJECT_DIR/coverage -test:sonarqube: +Sonarqube: dependencies: - - test:flutter - stage: sonarqube + - Test + stage: test before_script: - export PATH=$PATH:/sdk/flutter/bin/cache/dart-sdk/bin - flutter pub get -- GitLab From a2fd8a42e0a3c208c2c27799ff0d93702fa5ddec Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 17:00:56 +0700 Subject: [PATCH 13/19] [CHORE] update CI --- .gitlab-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5d88dd8..82e627e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,5 +1,6 @@ stages: - test + - sonarqube - deploy - show @@ -23,7 +24,7 @@ Test: Sonarqube: dependencies: - Test - stage: test + stage: sonarqube before_script: - export PATH=$PATH:/sdk/flutter/bin/cache/dart-sdk/bin - flutter pub get -- GitLab From b32f8cab5a40271f550e48f85889afb93928ea6a Mon Sep 17 00:00:00 2001 From: Fakhira Devina Date: Sat, 22 Feb 2020 22:41:25 +0700 Subject: [PATCH 14/19] [CHORE] Add linter in CI --- .gitlab-ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 82e627e..b898ffa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,5 @@ stages: + - lint - test - sonarqube - deploy @@ -9,6 +10,11 @@ variables: image: michael09/flutter:latest +Lint: + stage: lint + script: + - flutter analyze + Test: stage: test script: -- GitLab From 7d09bd5012aef554a6913875600857cf10709955 Mon Sep 17 00:00:00 2001 From: "agnes.handoko" Date: Sat, 22 Feb 2020 23:56:40 +0700 Subject: [PATCH 15/19] [CHORE] change navigation bar color and delete MaterialApp widget --- lib/main.dart | 3 +- lib/page/dashboard/dashboard.dart | 138 +++++++++++++++--------------- 2 files changed, 71 insertions(+), 70 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index bb20e5d..91211b7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,6 +7,7 @@ void main() { ApiFlavor.flavor = BuildFlavor.production.toString(); runApp(MyApp()); } + class MyApp extends StatelessWidget { // This widget is the root of your application. @override @@ -23,7 +24,7 @@ class MyApp extends StatelessWidget { // or simply save your changes to "hot reload" in a Flutter IDE). // Notice that the counter didn't reset back to zero; the application // is not restarted. - primarySwatch: Colors.blue, + primarySwatch: Colors.green, ), home: Dashboard(), ); diff --git a/lib/page/dashboard/dashboard.dart b/lib/page/dashboard/dashboard.dart index 550c405..144aa77 100644 --- a/lib/page/dashboard/dashboard.dart +++ b/lib/page/dashboard/dashboard.dart @@ -19,72 +19,81 @@ class DashboardState extends State { //https://flutter.dev/docs/cookbook/design/drawer @override Widget build(BuildContext context) { - return MaterialApp( - theme: ThemeData( - // Define the default brightness and colors. - primaryColor: Color.fromRGBO(58, 144, 58, 1), - accentColor: Colors.cyan[600], - - // Define the default font family. - fontFamily: 'Comfortaa', - - // Define the default TextTheme. Use this to specify the default - // text styling for headlines, titles, bodies of text, and more. - textTheme: TextTheme( - title: TextStyle(fontSize: 25.0, fontWeight: FontWeight.bold, fontStyle: FontStyle.italic), - headline: TextStyle(fontSize: 36.0, fontStyle: FontStyle.italic), - body1: TextStyle(fontSize: 14.0, fontFamily: 'Hind'), - ), - ), - home: Scaffold( - drawer: Drawer( - // Add a ListView to the drawer. This ensures the user can scroll - // through the options in the drawer if there isn't enough vertical - // space to fit everything. - child: ListView( - // Important: Remove any padding from the ListView. - padding: EdgeInsets.zero, - children: [ - DrawerHeader( - child: Text('Drawer Header'), - decoration: BoxDecoration( - color: Color.fromRGBO(58, 144, 58, 1), - ), - ), - ListTile( - title: Text('Item 1'), - onTap: () { - // Update the state of the app - // ... - // Then close the drawer - Navigator.pop(context); - }, - ), - ListTile( - title: Text('Item 2'), - onTap: () { - // Update the state of the app - // ... - // Then close the drawer - Navigator.pop(context); - }, + return Scaffold( + drawer: Drawer( + // Add a ListView to the drawer. This ensures the user can scroll + // through the options in the drawer if there isn't enough vertical + // space to fit everything. + child: ListView( + // Important: Remove any padding from the ListView. + padding: EdgeInsets.zero, + children: [ + DrawerHeader( + child: Text('Drawer Header'), + decoration: BoxDecoration( + color: Color.fromRGBO(58, 144, 58, 1), ), - ], - ), + ), + ListTile( + title: Text('Beranda'), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + ListTile( + title: Text('Riwayat Pencarian'), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + ListTile( + title: Text('Tentang Aplikasi'), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + ListTile( + title: Text('Logout'), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + ], ), - appBar: AppBar( - elevation: 15, - title: Center( - child: Text( + ), + appBar: AppBar( + elevation: 15, + centerTitle: true, + backgroundColor: Color.fromRGBO(58, 144, 58, 1), + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( "bisaGo", - textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), ), - ), + ], ), - body: Stack(children: [ - _buildGoogleMap(context), - ]), ), + body: Stack(children: [ + _buildGoogleMap(context), + ]), ); } @@ -102,15 +111,6 @@ class DashboardState extends State { ), ); } - - Choice _selectedChoice = choices[0]; // The app's "state". - - void _select(Choice choice) { - // Causes the app to rebuild with the new _selectedChoice. - setState(() { - _selectedChoice = choice; - }); - } } class Choice { -- GitLab From f58005a3ccef3b66d3cfa912d0922bee22569bcc Mon Sep 17 00:00:00 2001 From: "agnes.handoko" Date: Sun, 23 Feb 2020 01:39:22 +0700 Subject: [PATCH 16/19] [CHORE] add separator to navigation bar and change list tile color to green --- lib/page/dashboard/dashboard.dart | 226 ++++++++++++++++++------------ 1 file changed, 136 insertions(+), 90 deletions(-) diff --git a/lib/page/dashboard/dashboard.dart b/lib/page/dashboard/dashboard.dart index 144aa77..3c62207 100644 --- a/lib/page/dashboard/dashboard.dart +++ b/lib/page/dashboard/dashboard.dart @@ -20,57 +20,143 @@ class DashboardState extends State { @override Widget build(BuildContext context) { return Scaffold( - drawer: Drawer( - // Add a ListView to the drawer. This ensures the user can scroll - // through the options in the drawer if there isn't enough vertical - // space to fit everything. - child: ListView( - // Important: Remove any padding from the ListView. - padding: EdgeInsets.zero, - children: [ - DrawerHeader( - child: Text('Drawer Header'), - decoration: BoxDecoration( - color: Color.fromRGBO(58, 144, 58, 1), + drawer: Theme( + data: Theme.of(context).copyWith( + canvasColor: Color.fromRGBO(58, 144, 58, 1), + //This will change the drawer background to blue. + //other styles + ), + child: Drawer( + // Add a ListView to the drawer. This ensures the user can scroll + // through the options in the drawer if there isn't enough vertical + // space to fit everything. + child: ListView( + // Important: Remove any padding from the ListView. + padding: EdgeInsets.zero, + children: [ + Container( + height: 130, + child: DrawerHeader( + decoration: BoxDecoration( + color: Color.fromRGBO(58, 144, 58, 1), + ), + child: Row( + children: [ + FloatingActionButton( + backgroundColor: Colors.white, + elevation: 0, + onPressed: () => {}, + ), + Padding( + padding: EdgeInsets.all(16.0), + child: Text( + 'Nama Orang', + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + ), + ], + ), + ), ), - ), - ListTile( - title: Text('Beranda'), - onTap: () { - // Update the state of the app - // ... - // Then close the drawer - Navigator.pop(context); - }, - ), - ListTile( - title: Text('Riwayat Pencarian'), - onTap: () { - // Update the state of the app - // ... - // Then close the drawer - Navigator.pop(context); - }, - ), - ListTile( - title: Text('Tentang Aplikasi'), - onTap: () { - // Update the state of the app - // ... - // Then close the drawer - Navigator.pop(context); - }, - ), - ListTile( - title: Text('Logout'), - onTap: () { - // Update the state of the app - // ... - // Then close the drawer - Navigator.pop(context); - }, - ), - ], + Container( + child: ListTile( + title: Text( + 'Beranda', + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + decoration: new BoxDecoration( + border: new Border( + top: new BorderSide(color: Colors.white), + bottom: new BorderSide(color: Colors.white), + ), + ), + ), + Container( + child: ListTile( + title: Text( + 'Riwayat Pencarian', + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + decoration: new BoxDecoration( + border: new Border( + bottom: new BorderSide(color: Colors.white), + ), + ), + ), + Container( + child: ListTile( + title: Text( + 'Tentang Aplikasi', + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + decoration: new BoxDecoration( + border: new Border( + bottom: new BorderSide(color: Colors.white), + ), + ), + ), + Container( + child: ListTile( + title: Text( + 'Logout', + style: TextStyle( + fontSize: 20, + color: Colors.white, + fontFamily: 'Muli', + ), + ), + onTap: () { + // Update the state of the app + // ... + // Then close the drawer + Navigator.pop(context); + }, + ), + decoration: new BoxDecoration( + border: new Border( + bottom: new BorderSide(color: Colors.white), + ), + ), + ), + ], + ), ), ), appBar: AppBar( @@ -112,43 +198,3 @@ class DashboardState extends State { ); } } - -class Choice { - const Choice({this.title, this.icon}); - - final String title; - final IconData icon; -} - -const List choices = const [ - const Choice(title: 'Car', icon: Icons.directions_car), - const Choice(title: 'Bicycle', icon: Icons.directions_bike), - const Choice(title: 'Boat', icon: Icons.directions_boat), - const Choice(title: 'Bus', icon: Icons.directions_bus), - const Choice(title: 'Train', icon: Icons.directions_railway), - const Choice(title: 'Walk', icon: Icons.directions_walk), -]; - -class ChoiceCard extends StatelessWidget { - const ChoiceCard({Key key, this.choice}) : super(key: key); - - final Choice choice; - - @override - Widget build(BuildContext context) { - final TextStyle textStyle = Theme.of(context).textTheme.display1; - return Card( - color: Colors.white, - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Icon(choice.icon, size: 128.0, color: textStyle.color), - Text(choice.title, style: textStyle), - ], - ), - ), - ); - } -} -- GitLab From 5f15d035f858aebb87d348166ca8c3a1ab484c95 Mon Sep 17 00:00:00 2001 From: "agnes.handoko" Date: Sun, 23 Feb 2020 01:58:30 +0700 Subject: [PATCH 17/19] [CHORE] add icon to navigation bar list tile --- lib/page/dashboard/dashboard.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/page/dashboard/dashboard.dart b/lib/page/dashboard/dashboard.dart index 3c62207..ff61306 100644 --- a/lib/page/dashboard/dashboard.dart +++ b/lib/page/dashboard/dashboard.dart @@ -64,6 +64,7 @@ class DashboardState extends State { ), Container( child: ListTile( + leading: Icon(Icons.home, color: Colors.white, size: 30,), title: Text( 'Beranda', style: TextStyle( @@ -88,6 +89,7 @@ class DashboardState extends State { ), Container( child: ListTile( + leading: Icon(Icons.history, color: Colors.white, size: 30,), title: Text( 'Riwayat Pencarian', style: TextStyle( @@ -111,6 +113,7 @@ class DashboardState extends State { ), Container( child: ListTile( + leading: Icon(Icons.info, color: Colors.white, size: 30,), title: Text( 'Tentang Aplikasi', style: TextStyle( @@ -134,6 +137,7 @@ class DashboardState extends State { ), Container( child: ListTile( + leading: Icon(Icons.keyboard_backspace, color: Colors.white, size: 30,), title: Text( 'Logout', style: TextStyle( -- GitLab From b44d3d32af8d211c6365d3be2e7327890e7e19b2 Mon Sep 17 00:00:00 2001 From: "agnes.handoko" Date: Sun, 23 Feb 2020 02:22:37 +0700 Subject: [PATCH 18/19] [RED] fix appbar test --- test/widget_test.dart | 89 +++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/test/widget_test.dart b/test/widget_test.dart index c582eb3..9c461e6 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -17,76 +17,47 @@ import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; void main() { testWidgets('finds a google map in dashboard', (WidgetTester tester) async { Completer _controller = Completer(); - final googleMap = Builder(builder: (BuildContext context) { - Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - child: GoogleMap( - mapType: MapType.normal, - initialCameraPosition: - CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12), - onMapCreated: (GoogleMapController controller) { - _controller.complete(controller); - }, - ), - ); - }); + final googleMap = GoogleMap( + mapType: MapType.normal, + initialCameraPosition: + CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12), + onMapCreated: (GoogleMapController controller) { + _controller.complete(controller); + }, + ); // Provide the childWidget to the Container. - await tester.pumpWidget(Dashboard()); + await tester.pumpWidget(MaterialApp(home: Dashboard())); // Search for the childWidget in the tree and verify it exists. - expect(find.byWidget(googleMap), findsOneWidget); + expect(find.byType(GoogleMap), findsOneWidget); }); + testWidgets('finds a navigation bar', (WidgetTester tester) async { - Completer _controller = Completer(); - final navBar = Builder(builder: (BuildContext context) { - MaterialApp( - home: Scaffold( - appBar: AppBar( - title: const Text('Basic AppBar'), - actions: [ - // action button - IconButton( - icon: Icon(choices[0].icon), - onPressed: () { - _select(choices[0]); - }, - ), - // action button - IconButton( - icon: Icon(choices[1].icon), - onPressed: () { - _select(choices[1]); - }, - ), - // overflow menu - PopupMenuButton( - onSelected: _select, - itemBuilder: (BuildContext context) { - return choices.skip(2).map((Choice choice) { - return PopupMenuItem( - value: choice, - child: Text(choice.title), - ); - }).toList(); - }, - ), - ], - ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: ChoiceCard(choice: _selectedChoice), + final navBar = AppBar( + elevation: 15, + centerTitle: true, + backgroundColor: Color.fromRGBO(58, 144, 58, 1), + title: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "bisaGo", + style: TextStyle( + fontSize: 25, + fontFamily: 'Comfortaa', + fontWeight: FontWeight.w800), ), - ), - ); - }); + ], + ), + ); // Provide the childWidget to the Container. - await tester.pumpWidget(Dashboard()); + await tester.pumpWidget(MaterialApp(home: Dashboard())); // Search for the childWidget in the tree and verify it exists. - expect(find.byWidget(navBar), findsOneWidget); + expect(find.byType(AppBar), findsOneWidget); }); } -- GitLab From 4f05e44a97e05c4834fe2a02954ee270cdcf91c2 Mon Sep 17 00:00:00 2001 From: "agnes.handoko" Date: Sun, 23 Feb 2020 02:46:02 +0700 Subject: [PATCH 19/19] [GREEN] fixed failed pipeline because of linter issue --- lib/config/strings.dart | 14 +++++++------- lib/flavor/flavor.dart | 4 ++-- lib/main.dart | 1 - test/widget_test.dart | 38 +++----------------------------------- 4 files changed, 12 insertions(+), 45 deletions(-) diff --git a/lib/config/strings.dart b/lib/config/strings.dart index 1ea733e..f680bdb 100644 --- a/lib/config/strings.dart +++ b/lib/config/strings.dart @@ -1,16 +1,16 @@ // Frequently used strings are stored here // No hardcoding string view files. Store here. -final String DEV_BASE_URL = "poipole.herokuapp.com"; -final String BASE_URL = "poipole.herokuapp.com"; -String KEY = ""; -String CSRF = ""; -String SESSION_ID = ""; +final String devBaseURL = "poipole.herokuapp.com"; +final String baseURL = "poipole.herokuapp.com"; +String key = ""; +String csrf = ""; +String sessionID = ""; setKey(String key) { - KEY = key; + key = key; } setSessionId(String sessionId) { - SESSION_ID = sessionId; + sessionID = sessionId; } \ No newline at end of file diff --git a/lib/flavor/flavor.dart b/lib/flavor/flavor.dart index e1508bf..09201b9 100644 --- a/lib/flavor/flavor.dart +++ b/lib/flavor/flavor.dart @@ -7,9 +7,9 @@ class ApiFlavor { static String getBaseUrl() { if (ApiFlavor.flavor == BuildFlavor.development.toString()) { - return DEV_BASE_URL; + return devBaseURL; } else { - return BASE_URL; + return baseURL; } } diff --git a/lib/main.dart b/lib/main.dart index 4859b3c..91e8aab 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:ppl_disabilitas/config/styles.dart'; import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; import 'flavor/flavor.dart'; diff --git a/test/widget_test.dart b/test/widget_test.dart index c91eaf8..e36e8e9 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -1,4 +1,4 @@ -import 'dart:async'; +//import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -8,51 +8,19 @@ import 'package:ppl_disabilitas/page/dashboard/dashboard.dart'; void main() { testWidgets('finds a google map in dashboard', (WidgetTester tester) async { - Completer _controller = Completer(); - final googleMap = GoogleMap( - mapType: MapType.normal, - initialCameraPosition: - CameraPosition(target: LatLng(40.712776, -74.005974), zoom: 12), - onMapCreated: (GoogleMapController controller) { - _controller.complete(controller); - }, - ); - // Provide the childWidget to the Container. await tester.pumpWidget(MaterialApp(home: Dashboard())); - // Search for the childWidget in the tree and verify it exists. expect(find.byType(GoogleMap), findsOneWidget); }); testWidgets('finds a navigation bar', (WidgetTester tester) async { - final navBar = AppBar( - elevation: 15, - centerTitle: true, - backgroundColor: Color.fromRGBO(58, 144, 58, 1), - title: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "bisaGo", - style: TextStyle( - fontSize: 25, - fontFamily: 'Comfortaa', - fontWeight: FontWeight.w800), - ), - ], - ), - ); - // Provide the childWidget to the Container. await tester.pumpWidget(MaterialApp(home: Dashboard())); - // Search for the childWidget in the tree and verify it exists. + expect(find.byType(Scaffold), findsOneWidget); + expect(find.byType(Theme), findsOneWidget); expect(find.byType(AppBar), findsOneWidget); - await tester.pumpWidget(MaterialApp(home: Dashboard())); - // Search for the childWidget in the tree and verify it exists. - expect(find.byType(GoogleMap), findsOneWidget); }); testWidgets('Shows dashboard on App Start', (WidgetTester tester) async { -- GitLab