diff --git a/lib/config/config.dart b/lib/config/config.dart new file mode 100644 index 0000000000000000000000000000000000000000..a62b33aba5da0a656d9b2908999e3101d895af4b --- /dev/null +++ b/lib/config/config.dart @@ -0,0 +1,4 @@ +class Config { + final String GOOGLE_API = ''; + final String WEATHER_API = ''; +} diff --git a/lib/main.dart b/lib/main.dart index 154184723adf4c8160e8d21b09e5e648c9428e0b..f08931d2e2ee9afd59de05176ad46f9d7c26efdc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,4 @@ -// ignore_for_file: prefer_const_constructors, sort_child_properties_last, import_of_legacy_library_into_null_safe, prefer_is_not_empty, unnecessary_null_comparison, deprecated_member_use, depend_on_referenced_packages, avoid_function_literals_in_foreach_calls +// ignore_for_file: prefer_const_constructors, sort_child_properties_last, import_of_legacy_library_into_null_safe, prefer_is_not_empty, unnecessary_null_comparison, deprecated_member_use, depend_on_referenced_packages, avoid_function_literals_in_foreach_calls, prefer_final_fields import 'package:flutter/material.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:intl/intl.dart'; @@ -11,6 +11,7 @@ import 'package:geolocator/geolocator.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'package:weather_icons/weather_icons.dart'; +import 'config/config.dart'; void main() => runApp(MyApp()); @@ -20,12 +21,15 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( + debugShowCheckedModeBanner: false, title: 'Flutter App', home: MyHomePage(), theme: ThemeData( fontFamily: 'Rubik', - primaryColor: Color.fromRGBO(22, 31, 68, 1), - accentColor: Color.fromRGBO(250, 250, 250, 0.85), + // Color.fromRGBO(23, 26, 32, 1), + // Color.fromRGBO(13, 108, 114, 1) + primaryColor: Color.fromRGBO(23, 26, 32, 1), + accentColor: Color.fromRGBO(250, 250, 250, 1), ), ); } @@ -39,6 +43,7 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State<MyHomePage> { + Config config = Config(); // Initial map coords and map controller to control camera movements. static const _initialCameraPosition = CameraPosition(target: LatLng(52.5163, 13.3777), zoom: 12); @@ -52,9 +57,11 @@ class _MyHomePageState extends State<MyHomePage> { late LatLng _originCoordinates; late LatLng _destCoordinates; int _markerCounter = 0; - final Set<Marker> _markers = {}; + Set<Marker> _markers = {}; late Directions _info; Set<Polyline> _polyline = {}; + String _totalDuration = ''; + String _totalDistance = ''; // Variables for calendar and weather filter DateTimeRange _dateRange = DateTimeRange( @@ -64,6 +71,12 @@ class _MyHomePageState extends State<MyHomePage> { bool _isDateChosen = false; bool _showAdditionalButtons = false; List<String> _selectedOptions = []; + var _dateRangeArray = []; + var _availableDatesForTrip = []; + + // Weather API + var _forecastList = []; + bool _isCollapsed = false; // Format input text. String getFormattedText(String inputText) { @@ -100,6 +113,9 @@ class _MyHomePageState extends State<MyHomePage> { CameraPosition(target: _originCoordinates, zoom: 14), ), ); + setState(() { + _markers = {}; + }); _addOriginMarker(); _resetPolyline(); } @@ -129,6 +145,12 @@ class _MyHomePageState extends State<MyHomePage> { CameraPosition(target: _destCoordinates, zoom: 14), ), ); + if (_markers.length > 1) { + _markers.remove(_markers.last); + } + setState(() { + _markers; + }); _addDestinationMarker(); _resetPolyline(); } @@ -136,6 +158,7 @@ class _MyHomePageState extends State<MyHomePage> { // -----------Section For Map Operations, Coords, Polyline..---------------- // Get shortest path. void _getShortestPath() async { + _getWeather(); _resetPolyline(); _drawPolyline(); } @@ -195,8 +218,12 @@ class _MyHomePageState extends State<MyHomePage> { .map((e) => LatLng(e.latitude, e.longitude)) .toList(), )); + _totalDuration = value.totalDuration; + _totalDistance = value.totalDistance; setState(() { _polyline; + _totalDuration; + _totalDistance; }); // Animate camera to the shortest path. _mapController.animateCamera( @@ -213,6 +240,14 @@ class _MyHomePageState extends State<MyHomePage> { }); } + // Helper function to reset marker. + void _resetOriginMarker() { + _markers = {}; + setState(() { + _markers; + }); + } + // Get user location info with geolocation. _getCurrentLocation() async { await Geolocator.requestPermission().then( @@ -223,7 +258,7 @@ class _MyHomePageState extends State<MyHomePage> { .then( (Position position) async { final url = Uri.parse( - 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${position.latitude},${position.longitude}&key='); + 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${position.latitude},${position.longitude}&key=${config.GOOGLE_API}'); final response = await http.get(url); setState(() { originText = @@ -248,8 +283,10 @@ class _MyHomePageState extends State<MyHomePage> { ); } + // Add origin marker on touch. void _appearOriginMarkerOnTouch(LatLng pos) async { _resetPolyline(); + _resetOriginMarker(); _markers.add( Marker( markerId: MarkerId('origin'), @@ -259,7 +296,7 @@ class _MyHomePageState extends State<MyHomePage> { ), ); final url = Uri.parse( - 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${pos.latitude},${pos.longitude}&key='); + 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${pos.latitude},${pos.longitude}&key=${config.GOOGLE_API}'); final response = await http.get(url); originText = json.decode(response.body)['results'][0]['formatted_address']; setState(() { @@ -270,8 +307,10 @@ class _MyHomePageState extends State<MyHomePage> { }); } + // Add destination marker on touch. void _appearDestMarkerOnTouch(LatLng pos) async { _resetPolyline(); + _markers.add( Marker( markerId: MarkerId('dest'), @@ -281,7 +320,7 @@ class _MyHomePageState extends State<MyHomePage> { ), ); final url = Uri.parse( - 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${pos.latitude},${pos.longitude}&key='); + 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${pos.latitude},${pos.longitude}&key=${config.GOOGLE_API}'); final response = await http.get(url); destinationText = json.decode(response.body)['results'][0]['formatted_address']; @@ -327,11 +366,21 @@ class _MyHomePageState extends State<MyHomePage> { _dateRange = newDateTimeRange; _isDateChosen = true; }); + _updateDateRange(); + } + + // Update Data Range Array + void _updateDateRange() { + DateFormat formatter = DateFormat('y-MM-dd'); + String formattedStart = formatter.format(_dateRange.start); + String formattedEnd = formatter.format(_dateRange.end); + _dateRangeArray.add(formattedStart); + _dateRangeArray.add(formattedEnd); } // Format and display date. String convertDateFormat(date) { - DateFormat formatter = DateFormat('dd/MM'); + DateFormat formatter = DateFormat('MM/dd'); String formatted = formatter.format(date); return formatted; } @@ -350,7 +399,7 @@ class _MyHomePageState extends State<MyHomePage> { }); } - // Show weather options in bottom sheet + // Show weather options as modal bottom sheet void _showOptions(BuildContext context) { showModalBottomSheet( context: context, @@ -473,6 +522,85 @@ class _MyHomePageState extends State<MyHomePage> { } } + // ----------Section For Getting Weather Data------------ + // Create weather query to the external weather API + void _getWeather() async { + _forecastList = []; + setState(() { + _forecastList; + }); + final response = await http.get( + Uri.parse( + 'http://api.weatherapi.com/v1/forecast.json?key=${config.WEATHER_API}&q=${_destCoordinates.latitude},${_destCoordinates.longitude}&days=14', + ), + ); + + // Get weather information for destination point and update list for available dates of trip. + var data = jsonDecode(response.body); + var forecast = data['forecast']['forecastday']; + forecast.forEach( + (item) => { + _forecastList.add( + { + 'date': item['date'], + 'chanceOfRain': item['day']['daily_chance_of_rain'], + 'chanceOfSnow': item['day']['daily_chance_of_snow'], + 'condition': item['day']['condition']['text'], + }, + ) + }, + ); + _getAvailableDates(); + } + + void _getAvailableDates() { + _availableDatesForTrip = []; + setState(() { + _availableDatesForTrip; + }); + var format = DateFormat('y-dd-mm'); + var sinceEpochStart = + format.parse(_dateRangeArray[0], true).millisecondsSinceEpoch; + var sinceEpochEnd = + format.parse(_dateRangeArray[1], true).millisecondsSinceEpoch; + _forecastList.forEach((element) { + final dt = format.parse(element['date'], true).millisecondsSinceEpoch; + if (sinceEpochStart < dt && dt < sinceEpochEnd) { + if (_selectedOptions.contains('Rain') && + _selectedOptions.contains('Snow')) { + if ((element['chanceOfRain'].toInt() < 87) && + (element['chanceOfSnow'].toInt() < 85)) { + _availableDatesForTrip.add(element['date']); + } + } else if (_selectedOptions.contains('Rain')) { + if (element['chanceOfRain'].toInt() < 87) { + _availableDatesForTrip.add(element['date']); + } + } else if (_selectedOptions.contains('Snow')) { + if (element['chanceOfSnow'].toInt() < 85) { + _availableDatesForTrip.add(element['date']); + } + } else { + _availableDatesForTrip.add(element['date']); + } + } + setState(() { + _availableDatesForTrip; + }); + }); + } + + void _collapse() { + if (_isCollapsed) { + _isCollapsed = false; + } else { + _isCollapsed = true; + } + setState(() { + _isCollapsed; + }); + } + // Main App @override Widget build(BuildContext context) { @@ -626,7 +754,7 @@ class _MyHomePageState extends State<MyHomePage> { CircleAvatar( radius: 23, backgroundColor: - Theme.of(context).primaryColor, + Color.fromRGBO(9, 89, 95, 1), child: IconButton( onPressed: _toggleAdditionalButtons, icon: Icon(Icons.menu), @@ -640,7 +768,7 @@ class _MyHomePageState extends State<MyHomePage> { children: [ CircleAvatar( backgroundColor: - Theme.of(context).primaryColor, + Color.fromRGBO(9, 89, 95, 1), radius: 20, child: IconButton( onPressed: () { @@ -655,7 +783,7 @@ class _MyHomePageState extends State<MyHomePage> { SizedBox(width: 10), CircleAvatar( backgroundColor: - Theme.of(context).primaryColor, + Color.fromRGBO(9, 89, 95, 1), radius: 20, child: IconButton( onPressed: () { @@ -668,17 +796,6 @@ class _MyHomePageState extends State<MyHomePage> { ), ), SizedBox(width: 10), - CircleAvatar( - backgroundColor: - Theme.of(context).primaryColor, - radius: 20, - child: IconButton( - onPressed: () {}, - icon: Icon(Icons.car_crash), - color: - Theme.of(context).accentColor, - ), - ), ], ), ), @@ -693,7 +810,7 @@ class _MyHomePageState extends State<MyHomePage> { child: RawMaterialButton( onPressed: _getShortestPath, elevation: 5, - fillColor: Theme.of(context).primaryColor, + fillColor: Color.fromRGBO(9, 89, 95, 1), child: Icon( Icons.navigation_rounded, color: Theme.of(context).accentColor, @@ -714,7 +831,6 @@ class _MyHomePageState extends State<MyHomePage> { maxChildSize: 0.2, builder: (BuildContext context, ScrollController scrollController) { return Container( - margin: EdgeInsets.only(top: 0), decoration: BoxDecoration( borderRadius: BorderRadius.only( topRight: Radius.circular(20), @@ -725,46 +841,42 @@ class _MyHomePageState extends State<MyHomePage> { child: ListView.builder( controller: scrollController, itemCount: 1, - padding: EdgeInsets.all(30), + padding: EdgeInsets.all(20), itemBuilder: (BuildContext context, int index) { - return Container( - width: double.infinity, - height: 150, + return Expanded( child: Column( children: [ Container( - margin: EdgeInsets.only(bottom: 15), - padding: EdgeInsets.only(bottom: 15), + margin: EdgeInsets.only(bottom: 15, top: 5), decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - color: Theme.of(context).accentColor, - width: 0.4), - ), - ), + color: Color.fromRGBO(53, 56, 63, 1), + borderRadius: + BorderRadius.all(Radius.circular(25))), + padding: + EdgeInsets.only(bottom: 15, top: 15, left: 20), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - padding: EdgeInsets.only(right: 3, top: 4), + padding: EdgeInsets.only(right: 5, top: 2), child: Icon( - Icons.double_arrow_rounded, + Icons.calendar_month, color: Theme.of(context).accentColor, - size: 18, + size: 20, ), ), Text( - 'Picked Date ', + 'Picked Date: ', style: TextStyle( letterSpacing: 0.6, - fontSize: 22, + fontSize: 21, fontWeight: FontWeight.w500, color: Theme.of(context).accentColor), ), Text( displayDate(), style: TextStyle( - fontSize: 21, + fontSize: 20, fontWeight: FontWeight.w400, color: Theme.of(context).accentColor), ), @@ -773,29 +885,33 @@ class _MyHomePageState extends State<MyHomePage> { ), Container( margin: EdgeInsets.only(bottom: 10), - padding: EdgeInsets.only(bottom: 20), + padding: EdgeInsets.only(bottom: 15), + decoration: BoxDecoration( + color: Color.fromRGBO(53, 56, 63, 1), + borderRadius: + BorderRadius.all(Radius.circular(25))), child: Column( children: [ Container( - margin: EdgeInsets.only(bottom: 5), + padding: EdgeInsets.only( + bottom: 5, top: 15, left: 17), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( - padding: - EdgeInsets.only(right: 3, top: 4), + padding: EdgeInsets.only(right: 8), child: Icon( - Icons.double_arrow_rounded, + WeatherIcons.cloudy, color: Theme.of(context).accentColor, size: 18, ), ), Text( - 'Undesired Weather', + 'Undesired Weather: ', style: TextStyle( letterSpacing: 0.6, - fontSize: 22, + fontSize: 21, fontWeight: FontWeight.w500, color: Theme.of(context).accentColor), @@ -807,7 +923,7 @@ class _MyHomePageState extends State<MyHomePage> { crossAxisAlignment: CrossAxisAlignment.end, children: [ SizedBox( - width: 10, + width: 20, ), if (!_selectedOptions.isEmpty) ...returnWidget(), @@ -816,6 +932,192 @@ class _MyHomePageState extends State<MyHomePage> { ], ), ), + Container( + padding: EdgeInsets.only(top: 7, bottom: 7), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: _collapse, + child: Container( + padding: EdgeInsets.only( + top: 10, + bottom: 10, + left: 135, + right: 135), + child: Text( + 'Info', + style: TextStyle(fontSize: 20), + ), + ), + style: ButtonStyle( + backgroundColor: MaterialStatePropertyAll( + Color.fromRGBO(13, 108, 114, 1), + ), + shape: MaterialStateProperty.all< + RoundedRectangleBorder>( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + ), + ), + ), + ], + ), + ), + if (_availableDatesForTrip != null && _isCollapsed) + Container( + decoration: BoxDecoration( + color: Color.fromRGBO(53, 56, 63, 1), + borderRadius: + BorderRadius.all(Radius.circular(25))), + padding: EdgeInsets.only( + top: 15, left: 20, bottom: 15), + margin: EdgeInsets.only(top: 10, bottom: 10), + child: Column( + children: [ + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Container( + padding: + EdgeInsets.only(right: 5, top: 2), + child: Icon( + Icons.access_time_filled_outlined, + color: Theme.of(context).accentColor, + size: 20, + ), + ), + Text( + 'Duration: ', + style: TextStyle( + letterSpacing: 0.6, + fontSize: 21, + fontWeight: FontWeight.w500, + color: + Theme.of(context).accentColor), + ), + Text( + _totalDuration, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w400, + color: + Theme.of(context).accentColor), + ), + ], + ), + SizedBox( + height: 15, + ), + Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Container( + padding: + EdgeInsets.only(right: 5, top: 2), + child: Icon( + Icons.directions_car_rounded, + color: Theme.of(context).accentColor, + size: 20, + ), + ), + Text( + 'Distance: ', + style: TextStyle( + letterSpacing: 0.6, + fontSize: 21, + fontWeight: FontWeight.w500, + color: + Theme.of(context).accentColor), + ), + Text( + _totalDistance, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w400, + color: + Theme.of(context).accentColor), + ), + ], + ) + ], + ), + ), + if (_availableDatesForTrip != null && _isCollapsed) + Container( + margin: EdgeInsets.only(top: 10), + padding: EdgeInsets.only(left: 5, top: 10), + decoration: BoxDecoration( + color: Color.fromRGBO(53, 56, 63, 1), + borderRadius: + BorderRadius.all(Radius.circular(25))), + child: Column( + children: [ + Row(children: [ + Container( + padding: EdgeInsets.only( + right: 3, + top: 4, + bottom: 7, + left: 15), + child: Icon( + Icons.event_available, + color: Theme.of(context).accentColor, + size: 24, + ), + ), + Container( + padding: EdgeInsets.only( + top: 5, left: 5, bottom: 10), + child: Text( + 'Available Dates:', + style: TextStyle( + letterSpacing: 0.6, + fontSize: 21, + fontWeight: FontWeight.w500, + color: + Theme.of(context).accentColor), + ), + ), + ]), + for (var i = 0; + i < _availableDatesForTrip.length; + i++) + Container( + padding: const EdgeInsets.only( + top: 5, bottom: 15, left: 5), + child: Row( + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Container( + padding: EdgeInsets.only( + right: 6, left: 12), + child: Icon( + Icons.check_rounded, + color: + Theme.of(context).accentColor, + size: 20, + ), + ), + Text( + _availableDatesForTrip[i], + style: TextStyle( + letterSpacing: 0.6, + fontSize: 20, + fontWeight: FontWeight.w400, + color: Theme.of(context) + .accentColor), + ), + ], + ), + ) + ], + ), + ), ], ), ); diff --git a/lib/widgets/directions.dart b/lib/widgets/directions.dart index b9ef276dffc5ba99b7caee1299cc911a41256052..6ad96b69445e179c02ae652343166dc915be0426 100644 --- a/lib/widgets/directions.dart +++ b/lib/widgets/directions.dart @@ -6,10 +6,14 @@ import 'package:google_maps_flutter/google_maps_flutter.dart'; class Directions { final LatLngBounds bounds; final List<PointLatLng> polylinePoints; + final String totalDistance; + final String totalDuration; const Directions({ required this.bounds, required this.polylinePoints, + required this.totalDistance, + required this.totalDuration, }); factory Directions.fromMap(Map<String, dynamic> map) { @@ -24,10 +28,21 @@ class Directions { southwest: LatLng(southwest['lat'], southwest['lng']), ); + // Distance and Duration + String distance = ''; + String duration = ''; + if ((data['legs'] as List).isNotEmpty) { + final leg = data['legs'][0]; + distance = leg['distance']['text']; + duration = leg['duration']['text']; + } + return Directions( bounds: bounds, polylinePoints: PolylinePoints().decodePolyline(data['overview_polyline']['points']), + totalDistance: distance, + totalDuration: duration, ); } } diff --git a/lib/widgets/directionsRepo.dart b/lib/widgets/directionsRepo.dart index 0766f121cdcd6dae0e3c6f90bf61e67caf8446ef..b9ec6bfb1cb53d913483fdb3e4ef4ac7888abc08 100644 --- a/lib/widgets/directionsRepo.dart +++ b/lib/widgets/directionsRepo.dart @@ -3,13 +3,13 @@ import 'package:dio/dio.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import './directions.dart'; +import '../config/config.dart'; class DirectionsRepo { + Config config = Config(); static const String _baseUrl = 'https://maps.googleapis.com/maps/api/directions/json?'; - final Dio _dio; - DirectionsRepo({Dio? dio}) : _dio = dio ?? Dio(); Future<Directions> getDirections({ @@ -21,7 +21,7 @@ class DirectionsRepo { queryParameters: { 'origin': '${origin.latitude},${origin.longitude}', 'destination': '${destination.latitude},${destination.longitude}', - 'key': '', + 'key': config.GOOGLE_API, }, ); diff --git a/lib/widgets/getStreetNumber.dart b/lib/widgets/getStreetNumber.dart new file mode 100644 index 0000000000000000000000000000000000000000..a69e45efdcc61e4e3ffe666df969f637cfc14eeb --- /dev/null +++ b/lib/widgets/getStreetNumber.dart @@ -0,0 +1,195 @@ +// ignore_for_file: prefer_const_literals_to_create_immutables, prefer_const_constructors, sort_child_properties_last, must_be_immutable, use_key_in_widget_constructors, avoid_unnecessary_containers, deprecated_member_use + +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:flutter_typeahead/flutter_typeahead.dart'; +import 'package:http/http.dart' as http; +import '../config/config.dart'; + +class GetStreetNumber extends StatefulWidget { + String currentAddress; + GetStreetNumber(this.currentAddress); + + @override + State<GetStreetNumber> createState() => _GetStreetNumberState(); +} + +class _GetStreetNumberState extends State<GetStreetNumber> { + Config config = Config(); + TextEditingController textFieldController = TextEditingController(); + List<String> suggestions = []; + + Future<List<String>> fetchLocation(String query) async { + query = widget.currentAddress + query; + final response = await http.get( + Uri.parse( + 'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$query&radius=500&key=${config.GOOGLE_API}', + ), + ); + var jsonData = jsonDecode(response.body); + suggestions = []; + for (int i = 0; i < jsonData['predictions'][i].length; i++) { + suggestions.add(jsonData['predictions'][i]['description'].toString()); + } + return suggestions; + } + + void _sendDataBack(BuildContext context) { + Navigator.pop(context, textFieldController.text); + } + + void _skip(BuildContext context) { + Navigator.pop(context, widget.currentAddress); + } + + void _back(BuildContext context) { + Navigator.pop(context, textFieldController.text); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Color.fromRGBO(9, 89, 95, 1), + title: Text( + 'House Number', + style: TextStyle( + color: Theme.of(context).accentColor, + fontSize: 22, + ), + ), + leading: IconButton( + iconSize: 26, + icon: Icon( + Icons.arrow_back_ios_rounded, + color: Theme.of(context).accentColor, + ), + onPressed: () => _back(context), + ), + ), + body: Container( + color: Theme.of(context).primaryColor, + child: Column( + children: [ + Container( + margin: EdgeInsets.only(top: 15, right: 20, left: 10), + child: Row( + children: [ + Expanded( + child: Container( + padding: EdgeInsets.only(left: 10, right: 0), + decoration: BoxDecoration( + border: Border.all( + width: 1.5, + color: Color.fromRGBO(9, 89, 95, 1), + ), + borderRadius: BorderRadius.all( + Radius.circular(30), + ), + ), + height: 45, + child: TypeAheadField( + animationStart: 1, + animationDuration: Duration.zero, + textFieldConfiguration: TextFieldConfiguration( + onSubmitted: (_) { + _sendDataBack(context); + }, + controller: textFieldController, + autofocus: false, + decoration: InputDecoration( + border: InputBorder.none, + labelStyle: TextStyle( + color: Theme.of(context).accentColor, + ), + labelText: 'House number..', + floatingLabelBehavior: FloatingLabelBehavior.never, + ), + style: TextStyle( + fontSize: 21, + color: Theme.of(context).accentColor, + ), + ), + suggestionsBoxDecoration: SuggestionsBoxDecoration( + color: Theme.of(context).primaryColor, + ), + suggestionsCallback: (pattern) { + fetchLocation(pattern); + return suggestions; + }, + itemBuilder: (context, textField) { + return Container( + decoration: BoxDecoration( + color: Color.fromRGBO(53, 56, 63, 1), + borderRadius: BorderRadius.all( + Radius.circular(25), + ), + ), + margin: EdgeInsets.only(top: 5, bottom: 5), + padding: + EdgeInsets.only(top: 5, bottom: 5, left: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + child: Icon(Icons.location_city_rounded, + color: Theme.of(context).accentColor), + ), + Expanded( + child: Container( + margin: EdgeInsets.only( + top: 10, + bottom: 10, + left: 10, + ), + width: double.infinity, + child: Text( + textField.toString(), + style: TextStyle( + fontSize: 20, + color: Theme.of(context).accentColor, + ), + ), + ), + ), + ], + ), + ); + }, + onSuggestionSelected: (suggestion) { + textFieldController.text = suggestion.toString(); + _sendDataBack(context); + }, + ), + ), + ), + ], + ), + ), + ], + ), + ), + floatingActionButton: ElevatedButton( + onPressed: () => _skip(context), + child: Container( + child: Text( + 'Skip', + style: TextStyle(fontSize: 20), + ), + padding: EdgeInsets.all(10), + ), + style: ButtonStyle( + backgroundColor: MaterialStatePropertyAll( + Color.fromRGBO(13, 108, 114, 1), + ), + shape: MaterialStateProperty.all<RoundedRectangleBorder>( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(20), + ), + ), + ), + ), + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + ); + } +} diff --git a/lib/widgets/returnDestination.dart b/lib/widgets/returnDestination.dart index de579e3bbfdd6206df54d01aea1ffc8e02bfa888..2b7681e0f3de959ba6ce13f5867baf37a0215298 100644 --- a/lib/widgets/returnDestination.dart +++ b/lib/widgets/returnDestination.dart @@ -1,10 +1,11 @@ -// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors, avoid_print, prefer_is_not_empty +// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors, avoid_print, prefer_is_not_empty, use_build_context_synchronously import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:http/http.dart' as http; +import 'getStreetNumber.dart'; +import '../config/config.dart'; class ReturnDestination extends StatefulWidget { String destinationText; @@ -14,13 +15,14 @@ class ReturnDestination extends StatefulWidget { } class _ReturnDestinationState extends State<ReturnDestination> { + Config config = Config(); TextEditingController textFieldController = TextEditingController(); List<String> suggestions = []; Future<List<String>> fetchLocation(String query) async { final response = await http.get( Uri.parse( - 'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$query&radius=500&key=', + 'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$query&radius=500&key=${config.GOOGLE_API}', ), ); var jsonData = jsonDecode(response.body); @@ -31,7 +33,16 @@ class _ReturnDestinationState extends State<ReturnDestination> { return suggestions; } - void _sendDataBack(BuildContext context) { + void _sendDataBack(BuildContext context) async { + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => GetStreetNumber(textFieldController.text), + ), + ); + if (result != null) { + textFieldController.text = result; + } String textToSendBack = textFieldController.text; if (textToSendBack.isEmpty) return; Navigator.pop(context, textToSendBack); @@ -41,7 +52,7 @@ class _ReturnDestinationState extends State<ReturnDestination> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - backgroundColor: Theme.of(context).primaryColor, + backgroundColor: Color.fromRGBO(9, 89, 95, 1), title: Text( 'Destination Point', style: TextStyle( @@ -61,19 +72,20 @@ class _ReturnDestinationState extends State<ReturnDestination> { ), ), body: Container( + color: Theme.of(context).primaryColor, child: Column( children: [ Container( - margin: EdgeInsets.only(top: 15, right: 20, left: 20), + margin: EdgeInsets.only(top: 15, right: 10, left: 10), child: Row( children: [ Expanded( child: Container( - padding: EdgeInsets.only(left: 20), + padding: EdgeInsets.only(left: 10, right: 5), decoration: BoxDecoration( border: Border.all( width: 1.5, - color: Theme.of(context).primaryColor, + color: Color.fromRGBO(9, 89, 95, 1), ), borderRadius: BorderRadius.all( Radius.circular(30), @@ -81,7 +93,7 @@ class _ReturnDestinationState extends State<ReturnDestination> { ), height: 45, child: TypeAheadField( - animationStart: 0, + animationStart: 1, animationDuration: Duration.zero, textFieldConfiguration: TextFieldConfiguration( onSubmitted: (_) { @@ -92,41 +104,55 @@ class _ReturnDestinationState extends State<ReturnDestination> { decoration: InputDecoration( border: InputBorder.none, labelStyle: TextStyle( - color: Theme.of(context).primaryColor, + fontSize: 21, + color: Theme.of(context).accentColor, ), labelText: widget.destinationText, floatingLabelBehavior: FloatingLabelBehavior.never, ), style: TextStyle( - fontSize: 20, - color: Theme.of(context).primaryColor, + fontSize: 21, + color: Theme.of(context).accentColor, ), ), - suggestionsBoxDecoration: - SuggestionsBoxDecoration(elevation: 0), + suggestionsBoxDecoration: SuggestionsBoxDecoration( + color: Theme.of(context).primaryColor, + ), suggestionsCallback: (pattern) { fetchLocation(pattern); return suggestions; }, itemBuilder: (context, textField) { return Container( - padding: EdgeInsets.only(top: 1), + decoration: BoxDecoration( + color: Color.fromRGBO(53, 56, 63, 1), + borderRadius: BorderRadius.all( + Radius.circular(25), + ), + ), + margin: EdgeInsets.only(top: 5, bottom: 5), + padding: + EdgeInsets.only(top: 5, bottom: 5, left: 10), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( child: Icon(Icons.location_city_rounded, - color: Theme.of(context).primaryColor), + color: Theme.of(context).accentColor), ), Expanded( child: Container( - margin: EdgeInsets.all(10), + margin: EdgeInsets.only( + top: 10, + bottom: 10, + left: 10, + ), width: double.infinity, child: Text( textField.toString(), style: TextStyle( fontSize: 20, - color: Theme.of(context).primaryColor, + color: Theme.of(context).accentColor, ), ), ), diff --git a/lib/widgets/returnOrigin.dart b/lib/widgets/returnOrigin.dart index 03f285c022b90eb765dae9b1bac0e8253d51b8d4..6ea59f9294ffea50c56494c3e7a454b5afacd605 100644 --- a/lib/widgets/returnOrigin.dart +++ b/lib/widgets/returnOrigin.dart @@ -1,9 +1,11 @@ -// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors, avoid_print, prefer_is_not_empty +// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors, avoid_print, prefer_is_not_empty, use_build_context_synchronously import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:http/http.dart' as http; +import 'getStreetNumber.dart'; +import '../config/config.dart'; class ReturnOrigin extends StatefulWidget { String originText; @@ -13,13 +15,14 @@ class ReturnOrigin extends StatefulWidget { } class _ReturnOriginState extends State<ReturnOrigin> { + Config config = Config(); TextEditingController textFieldController = TextEditingController(); List<String> suggestions = []; Future<List<String>> fetchLocation(String query) async { final response = await http.get( Uri.parse( - 'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$query&radius=500&key=', + 'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$query&radius=500&key=${config.GOOGLE_API}', ), ); var jsonData = jsonDecode(response.body); @@ -30,7 +33,16 @@ class _ReturnOriginState extends State<ReturnOrigin> { return suggestions; } - void _sendDataBack(BuildContext context) { + void _sendDataBack(BuildContext context) async { + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => GetStreetNumber(textFieldController.text), + ), + ); + if (result != null) { + textFieldController.text = result; + } String textToSendBack = textFieldController.text; if (textToSendBack.isEmpty) return; Navigator.pop(context, textToSendBack); @@ -40,7 +52,7 @@ class _ReturnOriginState extends State<ReturnOrigin> { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - backgroundColor: Theme.of(context).primaryColor, + backgroundColor: Color.fromRGBO(9, 89, 95, 1), title: Text( 'Starting Point', style: TextStyle( @@ -60,19 +72,20 @@ class _ReturnOriginState extends State<ReturnOrigin> { ), ), body: Container( + color: Theme.of(context).primaryColor, child: Column( children: [ Container( - margin: EdgeInsets.only(top: 15, right: 20, left: 20), + margin: EdgeInsets.only(top: 15, right: 10, left: 10), child: Row( children: [ Expanded( child: Container( - padding: EdgeInsets.only(left: 20), + padding: EdgeInsets.only(left: 10, right: 5), decoration: BoxDecoration( border: Border.all( width: 1.5, - color: Theme.of(context).primaryColor, + color: Color.fromRGBO(9, 89, 95, 1), ), borderRadius: BorderRadius.all( Radius.circular(30), @@ -80,7 +93,7 @@ class _ReturnOriginState extends State<ReturnOrigin> { ), height: 45, child: TypeAheadField( - animationStart: 0, + animationStart: 1, animationDuration: Duration.zero, textFieldConfiguration: TextFieldConfiguration( onSubmitted: (_) { @@ -91,41 +104,54 @@ class _ReturnOriginState extends State<ReturnOrigin> { decoration: InputDecoration( border: InputBorder.none, labelStyle: TextStyle( - color: Theme.of(context).primaryColor, + color: Theme.of(context).accentColor, ), labelText: widget.originText, floatingLabelBehavior: FloatingLabelBehavior.never, ), style: TextStyle( fontSize: 20, - color: Theme.of(context).primaryColor, + color: Theme.of(context).accentColor, ), ), - suggestionsBoxDecoration: - SuggestionsBoxDecoration(elevation: 0), + suggestionsBoxDecoration: SuggestionsBoxDecoration( + color: Theme.of(context).primaryColor, + ), suggestionsCallback: (pattern) { fetchLocation(pattern); return suggestions; }, itemBuilder: (context, textField) { return Container( - padding: EdgeInsets.only(top: 1), + decoration: BoxDecoration( + color: Color.fromRGBO(53, 56, 63, 1), + borderRadius: BorderRadius.all( + Radius.circular(25), + ), + ), + margin: EdgeInsets.only(top: 5, bottom: 5), + padding: + EdgeInsets.only(top: 5, bottom: 5, left: 10), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( child: Icon(Icons.location_city_rounded, - color: Theme.of(context).primaryColor), + color: Theme.of(context).accentColor), ), Expanded( child: Container( - margin: EdgeInsets.all(10), + margin: EdgeInsets.only( + top: 10, + bottom: 10, + left: 10, + ), width: double.infinity, child: Text( textField.toString(), style: TextStyle( fontSize: 20, - color: Theme.of(context).primaryColor, + color: Theme.of(context).accentColor, ), ), ),