From 24fda6e99a44a3c6b7c3472aff6f907bc027c25f Mon Sep 17 00:00:00 2001 From: alper-savas <alpersavas1998@gmail.com> Date: Wed, 15 Mar 2023 13:12:06 +0100 Subject: [PATCH] Add polyline, autocorrection and geolocation with google maps API --- android/app/src/main/AndroidManifest.xml | 4 + assets/destMarker.png | Bin 0 -> 7749 bytes assets/originMarker.png | Bin 0 -> 7869 bytes ios/Podfile.lock | 35 +++ ios/Runner.xcodeproj/project.pbxproj | 28 +- ios/Runner/AppDelegate.swift | 2 + ios/Runner/Info.plist | 14 +- lib/main.dart | 241 ++++++++++++++---- lib/widgets/directions.dart | 33 +++ lib/widgets/directionsRepo.dart | 35 +++ lib/widgets/map.dart | 49 ---- lib/widgets/returnDestination.dart | 186 ++++++++------ lib/widgets/returnOrigin.dart | 152 +++++++++++ lib/widgets/returnStarting.dart | 131 ---------- macos/Flutter/GeneratedPluginRegistrant.swift | 4 + pubspec.lock | 170 +++++++++++- pubspec.yaml | 14 +- .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + 19 files changed, 777 insertions(+), 325 deletions(-) create mode 100644 assets/destMarker.png create mode 100644 assets/originMarker.png create mode 100644 lib/widgets/directions.dart create mode 100644 lib/widgets/directionsRepo.dart delete mode 100644 lib/widgets/map.dart create mode 100644 lib/widgets/returnOrigin.dart delete mode 100644 lib/widgets/returnStarting.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4aced6f..89d872b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -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> diff --git a/assets/destMarker.png b/assets/destMarker.png new file mode 100644 index 0000000000000000000000000000000000000000..d41ee5806ea6b43c51c1582bea22131fc4152ef9 GIT binary patch literal 7749 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 X#cEsKe7TZ=fq}u()z4*}Q$iB}`q1#F literal 0 HcmV?d00001 diff --git a/assets/originMarker.png b/assets/originMarker.png new file mode 100644 index 0000000000000000000000000000000000000000..da3a41688f7a49b84d51c217ab2309897f6f4cf0 GIT binary patch literal 7869 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 DX!bP> literal 0 HcmV?d00001 diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2c081ca..2ab740a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -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 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index a6bced3..32a1b47 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -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; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 70693e4..828fbd3 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,4 +1,5 @@ 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) } diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index e44f1cd..648d01f 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -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> diff --git a/lib/main.dart b/lib/main.dart index b4a81bb..777ef3e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,14 @@ // 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)}...'; + // Format text. + String getFormattedText(String inputText) { + if (inputText != null) { + if (inputText.length > 15) { + return '${inputText.substring(0, 15)}...'; } } - return startingText; - } - - String get getDestinationText { - if (destinationText != null) { - if (destinationText.length > 15) { - return '${destinationText.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,11 +336,14 @@ class _MyHomePageState extends State<MyHomePage> { SizedBox( height: 45, child: Container( - padding: EdgeInsets.only(right: 17, left: 10), - child: Icon( - Icons.my_location_outlined, - size: 24, - color: Theme.of(context).primaryColor, + padding: EdgeInsets.only(right: 6, left: 10), + child: IconButton( + iconSize: 24, + icon: Icon( + Icons.my_location_outlined, + 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, ), diff --git a/lib/widgets/directions.dart b/lib/widgets/directions.dart new file mode 100644 index 0000000..b9ef276 --- /dev/null +++ b/lib/widgets/directions.dart @@ -0,0 +1,33 @@ +// 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']), + ); + } +} diff --git a/lib/widgets/directionsRepo.dart b/lib/widgets/directionsRepo.dart new file mode 100644 index 0000000..0766f12 --- /dev/null +++ b/lib/widgets/directionsRepo.dart @@ -0,0 +1,35 @@ +// 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(); + } + } +} diff --git a/lib/widgets/map.dart b/lib/widgets/map.dart deleted file mode 100644 index 7ce9366..0000000 --- a/lib/widgets/map.dart +++ /dev/null @@ -1,49 +0,0 @@ -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, - ), - ) - ]) - ], - ); - } -} diff --git a/lib/widgets/returnDestination.dart b/lib/widgets/returnDestination.dart index 8647b8e..b267502 100644 --- a/lib/widgets/returnDestination.dart +++ b/lib/widgets/returnDestination.dart @@ -1,4 +1,4 @@ -// 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,77 +40,110 @@ class _ReturnDestinationState extends State<ReturnDestination> { @override Widget build(BuildContext context) { return Scaffold( + 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).accentColor, + ), + onPressed: () { + Navigator.pop(context); + }, + ), + ), 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: 'Destination', - border: OutlineInputBorder( - borderSide: BorderSide(color: Colors.black), - borderRadius: - BorderRadius.all(Radius.circular(30))), + 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), + ), ), - 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, + 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.destinationText, + floatingLabelBehavior: FloatingLabelBehavior.never, ), - Expanded( - child: Container( - margin: EdgeInsets.all(10), - width: double.infinity, - child: Text( - textField.toString(), - style: TextStyle(fontSize: 20), - ), - ), + style: TextStyle( + fontSize: 22, + color: Theme.of(context).primaryColor, ), - ], - ); - }, - onSuggestionSelected: (suggestion) { - textFieldController.text = suggestion.toString(); - _sendDataBack(context); - }, + ), + 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); + }, + ), + ), ), - ), - ], + ], + ), ), ], ), diff --git a/lib/widgets/returnOrigin.dart b/lib/widgets/returnOrigin.dart new file mode 100644 index 0000000..67af48b --- /dev/null +++ b/lib/widgets/returnOrigin.dart @@ -0,0 +1,152 @@ +// 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); + }, + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/widgets/returnStarting.dart b/lib/widgets/returnStarting.dart deleted file mode 100644 index 7583496..0000000 --- a/lib/widgets/returnStarting.dart +++ /dev/null @@ -1,131 +0,0 @@ -// 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); - }, - ), - ), - ], - ), - ], - ), - ), - ); - } -} diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..b1d4adf 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -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")) } diff --git a/pubspec.lock b/pubspec.lock index 5b19a10..d038082 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -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" diff --git a/pubspec.yaml b/pubspec.yaml index ac917fa..306b871 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..1ece8f2 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,9 @@ #include "generated_plugin_registrant.h" +#include <geolocator_windows/geolocator_windows.h> void RegisterPlugins(flutter::PluginRegistry* registry) { + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..7f101a7 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + geolocator_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST -- GitLab