Skip to content
Snippets Groups Projects
Commit 24fda6e9 authored by alper-savas's avatar alper-savas
Browse files

Add polyline, autocorrection and geolocation with google maps API

parent 24edb633
No related branches found
No related tags found
1 merge request!6final project merge into main
Showing
with 777 additions and 325 deletions
......@@ -30,5 +30,9 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data android:name="com.google.andoid.geo.API_KEY"
android:value="AIzaSyAzedQacDEZmyxAOUEEeocvehT8MEdMWys"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
</application>
</manifest>
assets/destMarker.png

7.57 KiB

assets/originMarker.png

7.68 KiB

......@@ -4,11 +4,33 @@ PODS:
- Flutter
- geocoder (0.0.1):
- Flutter
- geocoding_ios (1.0.5):
- Flutter
- geolocator_apple (1.2.0):
- Flutter
- google_maps_flutter_ios (0.0.1):
- Flutter
- GoogleMaps
- GoogleMaps (5.2.0):
- GoogleMaps/Maps (= 5.2.0)
- GoogleMaps/Base (5.2.0)
- GoogleMaps/Maps (5.2.0):
- GoogleMaps/Base
- location (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- geocoder (from `.symlinks/plugins/geocoder/ios`)
- geocoding_ios (from `.symlinks/plugins/geocoding_ios/ios`)
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/ios`)
- google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`)
- location (from `.symlinks/plugins/location/ios`)
SPEC REPOS:
trunk:
- GoogleMaps
EXTERNAL SOURCES:
Flutter:
......@@ -17,11 +39,24 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
geocoder:
:path: ".symlinks/plugins/geocoder/ios"
geocoding_ios:
:path: ".symlinks/plugins/geocoding_ios/ios"
geolocator_apple:
:path: ".symlinks/plugins/geolocator_apple/ios"
google_maps_flutter_ios:
:path: ".symlinks/plugins/google_maps_flutter_ios/ios"
location:
:path: ".symlinks/plugins/location/ios"
SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
geocoder: 3cfab70531a0b367e917bafe82df4c30f6d4c45a
geocoding_ios: a389ea40f6f548de6e63006a2e31bf66ff80769a
geolocator_apple: cc556e6844d508c95df1e87e3ea6fa4e58c50401
google_maps_flutter_ios: 3e0b99383a8003b8169d06e7e324170bd0424105
GoogleMaps: 025272d5876d3b32604e5c080dc25eaf68764693
location: 3a2eed4dd2fab25e7b7baf2a9efefe82b512d740
PODFILE CHECKSUM: ef19549a9bc3046e7bb7d2fab4d021637c0c58a3
......
......@@ -68,7 +68,6 @@
A7B92C277CEDD40DE17CA3E7 /* Pods-Runner.release.xcconfig */,
158D80A13A80AEF06A81D155 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
......@@ -140,6 +139,7 @@
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
2B9445729AF37972D8DF8E85 /* [CP] Embed Pods Frameworks */,
89B2A8318CC2B1F42C3CC7FF /* [CP] Copy Pods Resources */,
);
buildRules = (
);
......@@ -230,6 +230,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
89B2A8318CC2B1F42C3CC7FF /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
......@@ -358,13 +375,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = WQ97GY8U8F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.routerApp;
PRODUCT_BUNDLE_IDENTIFIER = com.testing.routerApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
......@@ -486,13 +504,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = WQ97GY8U8F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.routerApp;
PRODUCT_BUNDLE_IDENTIFIER = com.testing.routerApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
......@@ -508,13 +527,14 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = WQ97GY8U8F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.routerApp;
PRODUCT_BUNDLE_IDENTIFIER = com.testing.routerApp;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
......
import UIKit
import GoogleMaps
import Flutter
@UIApplicationMain
......@@ -7,6 +8,7 @@ import Flutter
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("AIzaSyAzedQacDEZmyxAOUEEeocvehT8MEdMWys")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
......
......@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
......@@ -24,6 +26,14 @@
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs access to location when open and in the background.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This app needs access to location when in the background.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs access to location when open.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
......@@ -43,9 +53,5 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
// 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
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart';
import './widgets/map.dart';
import 'widgets/returnStarting.dart';
import './widgets/returnDestination.dart';
import 'dart:async';
import 'widgets/returnOrigin.dart';
import 'widgets/returnDestination.dart';
import 'widgets/directionsRepo.dart';
import 'widgets/directions.dart';
import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() => runApp(MyApp());
......@@ -20,7 +23,7 @@ class MyApp extends StatelessWidget {
home: MyHomePage(),
theme: ThemeData(
fontFamily: 'Rubik',
primaryColor: Color.fromRGBO(22, 31, 68, 0.898),
primaryColor: Color.fromRGBO(22, 31, 68, 0.95),
accentColor: Color.fromRGBO(250, 250, 250, 0.85),
),
);
......@@ -35,82 +38,114 @@ class MyHomePage extends StatefulWidget {
}
class _MyHomePageState extends State<MyHomePage> {
String startingText = 'Starting Point';
String destinationText = 'Destination';
bool isDateChosen = false;
DateTimeRange dateRange = DateTimeRange(
// Initial map coords and map controller to control camera movements.
static const _initialCameraPosition =
CameraPosition(target: LatLng(52.5163, 13.3777), zoom: 12);
late GoogleMapController _mapController;
// Set origin/dest coords, respective markers, lat/lng coords between poits and polyline corresponding to coords.
late LatLng _originCoordinates;
late LatLng _destCoordinates;
final Set<Marker> _markers = {};
late Directions _info;
final Set<Polyline> _polyline = {};
// Input field texts for origin/dest points.
String originText = 'Starting Point...';
String destinationText = 'Destination...';
// Variables for calendar
DateTimeRange _dateRange = DateTimeRange(
start: DateTime.now(),
end: DateTime.now(),
);
bool _isDateChosen = false;
FloatingActionButtonLocation _floatingActionButtonLocation =
FloatingActionButtonLocation.centerFloat;
String get getStartingText {
if (startingText != null) {
if (startingText.length > 15) {
return '${startingText.substring(0, 15)}...';
}
}
return startingText;
}
String get getDestinationText {
if (destinationText != null) {
if (destinationText.length > 15) {
return '${destinationText.substring(0, 15)}...';
// Format text.
String getFormattedText(String inputText) {
if (inputText != null) {
if (inputText.length > 15) {
return '${inputText.substring(0, 15)}...';
}
}
return destinationText;
return inputText;
}
// Wait return value of input page to take origin point and update it's coords.
void _awaitStartingPointReturnValue(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ReturnStarting(),
builder: (context) => ReturnOrigin(originText),
),
);
if (result != null) {
List<Location> originLoc = await locationFromAddress(result);
setState(() {
startingText = result;
originText = result;
_originCoordinates =
LatLng(originLoc[0].latitude, originLoc[0].longitude);
});
}
// Toggle keyboard
FocusManager.instance.primaryFocus?.unfocus();
// Animate camera to the starting point.
_mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(target: _originCoordinates, zoom: 14),
),
);
}
// Wait return value of input page to take dest point and update it's coords.
void _awaitDestinationPointReturnValue(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ReturnDestination(),
builder: (context) => ReturnDestination(destinationText),
),
);
if (result != null) {
List<Location> destLoc = await locationFromAddress(result);
setState(
() {
destinationText = result;
_destCoordinates = LatLng(destLoc[0].latitude, destLoc[0].longitude);
},
);
}
// Toggle keyboard
FocusManager.instance.primaryFocus?.unfocus();
// Animate camera to the destination point.
_mapController.animateCamera(
CameraUpdate.newCameraPosition(
CameraPosition(target: _destCoordinates, zoom: 14),
),
);
}
// Pick date
_rangeDatePicker(BuildContext ctx) async {
DateTimeRange? newDateTimeRange = await showDateRangePicker(
initialEntryMode: DatePickerEntryMode.calendarOnly,
context: context,
firstDate: DateTime.now(),
lastDate: DateTime(DateTime.now().year + 2),
initialDateRange: dateRange,
initialDateRange: _dateRange,
builder: (context, child) {
return Theme(
data: Theme.of(context).copyWith(
colorScheme: ColorScheme.light(
primary: Theme.of(context).primaryColor, // <-- SEE HERE
onPrimary: Theme.of(context).accentColor, // <-- SEE HERE
onSurface: Theme.of(context).accentColor, // <-- SEE HERE
primary: Theme.of(context).primaryColor,
onPrimary: Theme.of(context).accentColor,
onSurface: Theme.of(context).accentColor,
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
primary: Theme.of(context).accentColor, // button text color
primary: Theme.of(context).accentColor, // Button text color
),
),
),
......@@ -119,13 +154,15 @@ class _MyHomePageState extends State<MyHomePage> {
},
);
// Update chosen date of global date variable.
if (newDateTimeRange == null) return;
setState(() {
dateRange = newDateTimeRange;
isDateChosen = true;
_dateRange = newDateTimeRange;
_isDateChosen = true;
});
}
// Format and display date.
String convertDateFormat(date) {
DateFormat formatter = DateFormat('dd/MM');
String formatted = formatter.format(date);
......@@ -133,18 +170,117 @@ class _MyHomePageState extends State<MyHomePage> {
}
String displayDate() {
if (isDateChosen) {
return "${convertDateFormat(dateRange.start)} - ${convertDateFormat(dateRange.end)}";
if (_isDateChosen) {
return "${convertDateFormat(_dateRange.start)} - ${convertDateFormat(_dateRange.end)}";
}
return '';
}
// Get shortest path.
void _getShortestPath() async {
_addMarker();
_getDirections();
_drawPolyline();
// Animate camera to the shortest path.
_mapController.animateCamera(
CameraUpdate.newLatLngBounds(_info.bounds, 100.0),
);
}
// Add markers for origin/dest coords.
void _addMarker() {
_markers.add(
Marker(
markerId: MarkerId('origin'),
infoWindow: InfoWindow(title: 'Origin'),
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueAzure),
position: _originCoordinates,
),
);
_markers.add(
Marker(
markerId: MarkerId('destination'),
infoWindow: InfoWindow(title: 'Destination'),
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueRed),
position: _destCoordinates,
),
);
setState(() {
_markers;
});
}
// Get coords between origin/dest points corresponding to shortest path and update _info.
// This part is going to be updated to take directions from backend instead of Direction API.
void _getDirections() async {
final directions = await DirectionsRepo().getDirections(
origin: _originCoordinates, destination: _destCoordinates);
setState(() {
_info = directions;
});
}
// Draw Polyline between given list of coordinates and update _polyline..
void _drawPolyline() {
_polyline.add(Polyline(
polylineId: PolylineId("polylineId"),
color: Theme.of(context).primaryColor,
width: 4,
points: _info.polylinePoints
.map((e) => LatLng(e.latitude, e.longitude))
.toList(),
));
setState(() {
_polyline;
});
}
// Get user location info with geolocation.
_getCurrentLocation() async {
await Geolocator.requestPermission().then(
(value) => {
Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best,
forceAndroidLocationManager: true)
.then(
(Position position) async {
final url = Uri.parse(
'https://maps.googleapis.com/maps/api/geocode/json?latlng=${position.latitude},${position.longitude}&key=');
final response = await http.get(url);
setState(() {
originText =
json.decode(response.body)['results'][0]['formatted_address'];
});
},
).catchError(
(e) {
throw Error();
},
),
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Map(),
GoogleMap(
initialCameraPosition: _initialCameraPosition,
myLocationButtonEnabled: false,
zoomControlsEnabled: false,
onMapCreated: (controller) => _mapController = controller,
markers: _markers,
polylines: _polyline,
),
Column(
children: [
// Starting Input
......@@ -184,8 +320,8 @@ class _MyHomePageState extends State<MyHomePage> {
color: Color.fromRGBO(20, 20, 20, 1),
),
border: InputBorder.none,
prefixText: getStartingText,
labelText: getStartingText,
prefixText: getFormattedText(originText),
labelText: getFormattedText(originText),
floatingLabelBehavior: FloatingLabelBehavior.never,
),
style: TextStyle(
......@@ -200,12 +336,15 @@ class _MyHomePageState extends State<MyHomePage> {
SizedBox(
height: 45,
child: Container(
padding: EdgeInsets.only(right: 17, left: 10),
child: Icon(
padding: EdgeInsets.only(right: 6, left: 10),
child: IconButton(
iconSize: 24,
icon: Icon(
Icons.my_location_outlined,
size: 24,
color: Theme.of(context).primaryColor,
),
onPressed: _getCurrentLocation,
),
),
),
],
......@@ -247,8 +386,8 @@ class _MyHomePageState extends State<MyHomePage> {
color: Color.fromRGBO(20, 20, 20, 1),
),
border: InputBorder.none,
prefixText: getDestinationText,
labelText: getDestinationText,
prefixText: getFormattedText(destinationText),
labelText: getFormattedText(destinationText),
floatingLabelBehavior: FloatingLabelBehavior.never,
),
style: TextStyle(
......@@ -276,7 +415,6 @@ class _MyHomePageState extends State<MyHomePage> {
],
),
),
// Insert Date to Map
],
),
DraggableScrollableSheet(
......@@ -287,7 +425,10 @@ class _MyHomePageState extends State<MyHomePage> {
return Container(
margin: EdgeInsets.only(top: 0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
topLeft: Radius.circular(20),
),
color: Theme.of(context).primaryColor,
),
child: NotificationListener(
......@@ -340,9 +481,9 @@ class _MyHomePageState extends State<MyHomePage> {
floatingActionButton: Container(
padding: EdgeInsets.only(bottom: 50),
child: FloatingActionButton.extended(
onPressed: () {},
onPressed: _getShortestPath,
label: Text(
'Get route',
'Get Route',
style: TextStyle(
fontSize: 18,
),
......
// ignore_for_file: import_of_legacy_library_into_null_safe
import 'package:flutter_polyline_points/flutter_polyline_points.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
class Directions {
final LatLngBounds bounds;
final List<PointLatLng> polylinePoints;
const Directions({
required this.bounds,
required this.polylinePoints,
});
factory Directions.fromMap(Map<String, dynamic> map) {
// Get route information
final data = Map<String, dynamic>.from(map['routes'][0]);
// Bounds
final northeast = data['bounds']['northeast'];
final southwest = data['bounds']['southwest'];
final bounds = LatLngBounds(
northeast: LatLng(northeast['lat'], northeast['lng']),
southwest: LatLng(southwest['lat'], southwest['lng']),
);
return Directions(
bounds: bounds,
polylinePoints:
PolylinePoints().decodePolyline(data['overview_polyline']['points']),
);
}
}
// ignore_for_file: file_names
import 'package:dio/dio.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import './directions.dart';
class DirectionsRepo {
static const String _baseUrl =
'https://maps.googleapis.com/maps/api/directions/json?';
final Dio _dio;
DirectionsRepo({Dio? dio}) : _dio = dio ?? Dio();
Future<Directions> getDirections({
required LatLng origin,
required LatLng destination,
}) async {
final response = await _dio.get(
_baseUrl,
queryParameters: {
'origin': '${origin.latitude},${origin.longitude}',
'destination': '${destination.latitude},${destination.longitude}',
'key': '',
},
);
// Check if response is successful
if (response.statusCode == 200) {
return Directions.fromMap(response.data);
} else {
throw Error();
}
}
}
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong/latlong.dart';
import 'package:flutter_map/plugin_api.dart'; // Only import if required functionality is not exposed by default
import 'package:intl/intl.dart';
class Map extends StatefulWidget {
const Map({super.key});
@override
State<Map> createState() => _MapState();
}
class _MapState extends State<Map> {
LatLng markerPoint = LatLng(52.5163, 13.3777);
@override
Widget build(BuildContext context) {
return FlutterMap(
options: MapOptions(
onTap: (p) {
setState(() {
markerPoint = p;
});
},
center: LatLng(52.5163, 13.3777),
zoom: 13,
),
layers: [
TileLayerOptions(
urlTemplate:
'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{@2x}.png',
subdomains: ['a', 'b', 'c'],
),
MarkerLayerOptions(markers: [
Marker(
width: 200,
height: 200,
point: markerPoint,
builder: (context) => const Icon(
Icons.location_on,
color: Colors.red,
),
)
])
],
);
}
}
// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors
// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors, avoid_print, prefer_is_not_empty
import 'dart:convert';
......@@ -7,6 +7,8 @@ import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:http/http.dart' as http;
class ReturnDestination extends StatefulWidget {
String destinationText;
ReturnDestination(this.destinationText);
@override
State<ReturnDestination> createState() => _ReturnDestinationState();
}
......@@ -16,28 +18,15 @@ class _ReturnDestinationState extends State<ReturnDestination> {
List<String> suggestions = [];
Future<List<String>> fetchLocation(String query) async {
final cityResponse = await http.get(
final response = await http.get(
Uri.parse(
'https://api.geoapify.com/v1/geocode/autocomplete?text=$query&type=city&format=json&apiKey=bc28b0ffd28a458c866bf21813ada611',
'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=$query&radius=500&key=',
),
);
final streetResponse = await http.get(
Uri.parse(
'https://api.geoapify.com/v1/geocode/autocomplete?text=$query&type=street&format=json&apiKey=bc28b0ffd28a458c866bf21813ada611',
),
);
var jsonDataCity = jsonDecode(cityResponse.body);
var jsonDataStreet = jsonDecode(streetResponse.body);
var jsonData = jsonDecode(response.body);
suggestions = [];
suggestions.add(
jsonDataCity['results'][0]['formatted'].toString(),
);
for (var i = 0; i < 6; i++) {
suggestions.add(
jsonDataStreet['results'][i]['formatted'].toString(),
);
for (int i = 0; i < 10; i++) {
suggestions.add(jsonData['predictions'][i]['description'].toString());
}
return suggestions;
}
......@@ -51,22 +40,46 @@ class _ReturnDestinationState extends State<ReturnDestination> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.only(top: 60, right: 35),
child: Column(
children: [
Row(
children: [
IconButton(
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColor,
title: Text(
'Destination Point',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 24,
),
),
leading: IconButton(
iconSize: 26,
icon: Icon(
Icons.arrow_back_ios_rounded,
color: Theme.of(context).primaryColor,
color: Theme.of(context).accentColor,
),
onPressed: () {
Navigator.pop(context);
},
),
),
body: Container(
child: Column(
children: [
Container(
margin: EdgeInsets.only(top: 15, right: 20, left: 20),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 20),
decoration: BoxDecoration(
border: Border.all(
width: 1.5,
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.all(
Radius.circular(30),
),
),
height: 50,
child: TypeAheadField(
animationStart: 0,
animationDuration: Duration.zero,
......@@ -77,14 +90,16 @@ class _ReturnDestinationState extends State<ReturnDestination> {
controller: textFieldController,
autofocus: false,
decoration: InputDecoration(
labelText: 'Destination',
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
borderRadius:
BorderRadius.all(Radius.circular(30))),
border: InputBorder.none,
labelStyle: TextStyle(
color: Theme.of(context).primaryColor,
),
labelText: widget.destinationText,
floatingLabelBehavior: FloatingLabelBehavior.never,
),
style: TextStyle(
fontSize: 20,
fontSize: 22,
color: Theme.of(context).primaryColor,
),
),
suggestionsBoxDecoration:
......@@ -94,13 +109,14 @@ class _ReturnDestinationState extends State<ReturnDestination> {
return suggestions;
},
itemBuilder: (context, textField) {
return Row(
return Container(
padding: EdgeInsets.only(top: 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
child: Icon(
Icons.location_city_rounded,
),
child: Icon(Icons.location_city_rounded,
color: Theme.of(context).primaryColor),
),
Expanded(
child: Container(
......@@ -108,11 +124,15 @@ class _ReturnDestinationState extends State<ReturnDestination> {
width: double.infinity,
child: Text(
textField.toString(),
style: TextStyle(fontSize: 20),
style: TextStyle(
fontSize: 21,
color: Theme.of(context).primaryColor,
),
),
),
),
],
),
);
},
onSuggestionSelected: (suggestion) {
......@@ -121,8 +141,10 @@ class _ReturnDestinationState extends State<ReturnDestination> {
},
),
),
),
],
),
),
],
),
),
......
// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors, avoid_print, prefer_is_not_empty
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:http/http.dart' as http;
class ReturnOrigin extends StatefulWidget {
String originText;
ReturnOrigin(this.originText);
@override
State<ReturnOrigin> createState() => _ReturnOriginState();
}
class _ReturnOriginState extends State<ReturnOrigin> {
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=',
),
);
var jsonData = jsonDecode(response.body);
suggestions = [];
for (int i = 0; i < 10; i++) {
suggestions.add(jsonData['predictions'][i]['description'].toString());
}
return suggestions;
}
void _sendDataBack(BuildContext context) {
String textToSendBack = textFieldController.text;
if (textToSendBack.isEmpty) return;
Navigator.pop(context, textToSendBack);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).primaryColor,
title: Text(
'Starting Point',
style: TextStyle(
color: Theme.of(context).accentColor,
fontSize: 24,
),
),
leading: IconButton(
iconSize: 26,
icon: Icon(
Icons.arrow_back_ios_rounded,
color: Theme.of(context).accentColor,
),
onPressed: () {
Navigator.pop(context);
},
),
),
body: Container(
child: Column(
children: [
Container(
margin: EdgeInsets.only(top: 15, right: 20, left: 20),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.only(left: 20),
decoration: BoxDecoration(
border: Border.all(
width: 1.5,
color: Theme.of(context).primaryColor,
),
borderRadius: BorderRadius.all(
Radius.circular(30),
),
),
height: 50,
child: TypeAheadField(
animationStart: 0,
animationDuration: Duration.zero,
textFieldConfiguration: TextFieldConfiguration(
onSubmitted: (_) {
_sendDataBack(context);
},
controller: textFieldController,
autofocus: false,
decoration: InputDecoration(
border: InputBorder.none,
labelStyle: TextStyle(
color: Theme.of(context).primaryColor,
),
labelText: widget.originText,
floatingLabelBehavior: FloatingLabelBehavior.never,
),
style: TextStyle(
fontSize: 22,
color: Theme.of(context).primaryColor,
),
),
suggestionsBoxDecoration:
SuggestionsBoxDecoration(elevation: 0),
suggestionsCallback: (pattern) {
fetchLocation(pattern);
return suggestions;
},
itemBuilder: (context, textField) {
return Container(
padding: EdgeInsets.only(top: 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
child: Icon(Icons.location_city_rounded,
color: Theme.of(context).primaryColor),
),
Expanded(
child: Container(
margin: EdgeInsets.all(10),
width: double.infinity,
child: Text(
textField.toString(),
style: TextStyle(
fontSize: 21,
color: Theme.of(context).primaryColor,
),
),
),
),
],
),
);
},
onSuggestionSelected: (suggestion) {
textFieldController.text = suggestion.toString();
_sendDataBack(context);
},
),
),
),
],
),
),
],
),
),
);
}
}
// ignore_for_file: prefer_const_constructors, use_key_in_widget_constructors, avoid_print, prefer_is_not_empty
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_typeahead/flutter_typeahead.dart';
import 'package:http/http.dart' as http;
class ReturnStarting extends StatefulWidget {
@override
State<ReturnStarting> createState() => _ReturnStartingState();
}
class _ReturnStartingState extends State<ReturnStarting> {
TextEditingController textFieldController = TextEditingController();
List<String> suggestions = [];
Future<List<String>> fetchLocation(String query) async {
final cityResponse = await http.get(
Uri.parse(
'https://api.geoapify.com/v1/geocode/autocomplete?text=$query&type=city&format=json&apiKey=bc28b0ffd28a458c866bf21813ada611',
),
);
final streetResponse = await http.get(
Uri.parse(
'https://api.geoapify.com/v1/geocode/autocomplete?text=$query&type=street&format=json&apiKey=bc28b0ffd28a458c866bf21813ada611',
),
);
var jsonDataCity = jsonDecode(cityResponse.body);
var jsonDataStreet = jsonDecode(streetResponse.body);
suggestions = [];
suggestions.add(
jsonDataCity['results'][0]['formatted'].toString(),
);
for (var i = 0; i < 6; i++) {
suggestions.add(
jsonDataStreet['results'][i]['formatted'].toString(),
);
}
return suggestions;
}
void _sendDataBack(BuildContext context) {
String textToSendBack = textFieldController.text;
if (textToSendBack.isEmpty) return;
Navigator.pop(context, textToSendBack);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
margin: EdgeInsets.only(top: 60, right: 35),
child: Column(
children: [
Row(
children: [
IconButton(
icon: Icon(
Icons.arrow_back_ios_rounded,
color: Theme.of(context).primaryColor,
),
onPressed: () {
Navigator.pop(context);
},
),
Expanded(
child: TypeAheadField(
animationStart: 0,
animationDuration: Duration.zero,
textFieldConfiguration: TextFieldConfiguration(
onSubmitted: (_) {
_sendDataBack(context);
},
controller: textFieldController,
autofocus: false,
decoration: InputDecoration(
labelText: 'Starting Point',
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black),
borderRadius:
BorderRadius.all(Radius.circular(30))),
),
style: TextStyle(
fontSize: 20,
),
),
suggestionsBoxDecoration:
SuggestionsBoxDecoration(elevation: 0),
suggestionsCallback: (pattern) {
fetchLocation(pattern);
return suggestions;
},
itemBuilder: (context, textField) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
child: Icon(
Icons.location_city_rounded,
),
),
Expanded(
child: Container(
margin: EdgeInsets.all(10),
width: double.infinity,
child: Text(
textField.toString(),
style: TextStyle(fontSize: 20),
),
),
),
],
);
},
onSuggestionSelected: (suggestion) {
textFieldController.text = suggestion.toString();
_sendDataBack(context);
},
),
),
],
),
],
),
),
);
}
}
......@@ -5,6 +5,10 @@
import FlutterMacOS
import Foundation
import geolocator_apple
import location
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
}
......@@ -65,6 +65,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
dio:
dependency: "direct main"
description:
name: dio
sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8"
url: "https://pub.dev"
source: hosted
version: "4.0.6"
fake_async:
dependency: transitive
description:
......@@ -150,6 +158,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.12.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf
url: "https://pub.dev"
source: hosted
version: "2.0.9"
flutter_polyline_points:
dependency: "direct main"
description:
name: flutter_polyline_points
sha256: "1544a383c30dfa0117b02785a28da8b27dc595897a2f1f90980a2a6276e6c0e3"
url: "https://pub.dev"
source: hosted
version: "0.2.6"
flutter_test:
dependency: "direct dev"
description: flutter
......@@ -176,6 +200,118 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.1"
geocoding:
dependency: "direct main"
description:
name: geocoding
sha256: b34c0501bbbaf3190b85bef3078b27cf66c28a8915c6d3af50d67f356aa7da31
url: "https://pub.dev"
source: hosted
version: "2.1.0"
geocoding_android:
dependency: transitive
description:
name: geocoding_android
sha256: "5a1fc0cec9b0497b44ca31c1fa8d1c891f3aded1053e6bb2eac075d3bd1bf046"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
geocoding_ios:
dependency: transitive
description:
name: geocoding_ios
sha256: c85495ce8fb34e4fbd2dd8fc5f79263d622d9f88c4af948c965daf6b27a7f3a1
url: "https://pub.dev"
source: hosted
version: "2.1.0"
geocoding_platform_interface:
dependency: transitive
description:
name: geocoding_platform_interface
sha256: "8848605d307d844d89937cdb4b8ad7dfa880552078f310fa24d8a460f6dddab4"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
geolocator:
dependency: "direct main"
description:
name: geolocator
sha256: "5c23f3613f50586c0bbb2b8f970240ae66b3bd992088cf60dd5ee2e6f7dde3a8"
url: "https://pub.dev"
source: hosted
version: "9.0.2"
geolocator_android:
dependency: transitive
description:
name: geolocator_android
sha256: "2ba24690aee0a3e1b6b7bd47c2711a50c874e95e4c758346589d35194adf6d6a"
url: "https://pub.dev"
source: hosted
version: "4.1.7"
geolocator_apple:
dependency: transitive
description:
name: geolocator_apple
sha256: "22b60ca3b8c0f58e6a9688ff855ee39ab813ca3f0c0609a48d282f6631266f2e"
url: "https://pub.dev"
source: hosted
version: "2.2.5"
geolocator_platform_interface:
dependency: transitive
description:
name: geolocator_platform_interface
sha256: af4d69231452f9620718588f41acc4cb58312368716bfff2e92e770b46ce6386
url: "https://pub.dev"
source: hosted
version: "4.0.7"
geolocator_web:
dependency: transitive
description:
name: geolocator_web
sha256: f68a122da48fcfff68bbc9846bb0b74ef651afe84a1b1f6ec20939de4d6860e1
url: "https://pub.dev"
source: hosted
version: "2.1.6"
geolocator_windows:
dependency: transitive
description:
name: geolocator_windows
sha256: f5911c88e23f48b598dd506c7c19eff0e001645bdc03bb6fecb9f4549208354d
url: "https://pub.dev"
source: hosted
version: "0.1.1"
google_maps_flutter:
dependency: "direct main"
description:
name: google_maps_flutter
sha256: "24392ef192f3b00bcd93151375676805a9933574423a5bd5509a0ead2e8a4215"
url: "https://pub.dev"
source: hosted
version: "2.2.5"
google_maps_flutter_android:
dependency: transitive
description:
name: google_maps_flutter_android
sha256: a8ee18649a67750cbd477a6867a1bf9c4154c5e9f69d722c8b53a627a6d58303
url: "https://pub.dev"
source: hosted
version: "2.4.9"
google_maps_flutter_ios:
dependency: transitive
description:
name: google_maps_flutter_ios
sha256: e9ad74415a222573625a2c1717adc1e375b18e8ce660fc12db734d1bda1132d4
url: "https://pub.dev"
source: hosted
version: "2.2.1"
google_maps_flutter_platform_interface:
dependency: transitive
description:
name: google_maps_flutter_platform_interface
sha256: a07811d2b82055815ede75e1fe4b7b76f71a0b4820b26f71bdaddd157d6a3e20
url: "https://pub.dev"
source: hosted
version: "2.2.6"
http:
dependency: "direct main"
description:
......@@ -240,6 +376,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.1.6"
location:
dependency: "direct main"
description:
name: location
sha256: "9051959f6f2ccadd887b28b66e9cbbcc25b6838e37cf9e894c421ccc0ebf80b5"
url: "https://pub.dev"
source: hosted
version: "4.4.0"
location_platform_interface:
dependency: transitive
description:
name: location_platform_interface
sha256: "62eeaf1658e92e4459b727f55a3c328eccbac8ba043fa6d262ac5286ad48384c"
url: "https://pub.dev"
source: hosted
version: "2.3.0"
location_web:
dependency: transitive
description:
name: location_web
sha256: "6c08c408a040534c0269c4ff9fe17eebb5a36dea16512fbaf116b9c8bc21545b"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
logging:
dependency: transitive
description:
......@@ -349,6 +509,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
stream_transform:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
string_scanner:
dependency: transitive
description:
......@@ -431,4 +599,4 @@ packages:
version: "1.0.7"
sdks:
dart: ">=2.19.2 <3.0.0"
flutter: ">=2.0.0"
flutter: ">=3.3.0"
......@@ -32,15 +32,22 @@ dependencies:
sdk: flutter
flutter_typeahead: ^4.3.7
dio: ^4.0.0
flutter_polyline_points: ^0.2.6
google_maps_flutter: ^2.0.2
geocoding: ^2.1.0
location: ^4.2.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
http: ^0.13.5
flutter_map: ^0.12.0
geocoder: ^0.2.1
tuple: ^1.0.2
latlong: ^0.6.1
latlong2: ^0.8.1
geolocator: ^9.0.2
geocoder: ^0.2.1
dev_dependencies:
flutter_test:
......@@ -64,9 +71,8 @@ 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/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
......
......@@ -6,6 +6,9 @@
#include "generated_plugin_registrant.h"
#include <geolocator_windows/geolocator_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
GeolocatorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GeolocatorWindows"));
}
......@@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
geolocator_windows
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment