Created
February 12, 2022 15:03
-
-
Save Imperial-lord/af0eb96e183ed716fa37edbef3a462bf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:carousel_slider/carousel_slider.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_dotenv/flutter_dotenv.dart'; | |
import 'package:mapbox_gl/mapbox_gl.dart'; | |
import 'package:mapbox_navigation/constants/restaurants.dart'; | |
import 'package:mapbox_navigation/helpers/commons.dart'; | |
import 'package:mapbox_navigation/helpers/shared_prefs.dart'; | |
import 'package:mapbox_navigation/widgets/carousel_card.dart'; | |
class RestaurantsMap extends StatefulWidget { | |
const RestaurantsMap({Key? key}) : super(key: key); | |
@override | |
State<RestaurantsMap> createState() => _RestaurantsMapState(); | |
} | |
class _RestaurantsMapState extends State<RestaurantsMap> { | |
// Mapbox related | |
LatLng latLng = getLatLngFromSharedPrefs(); | |
late CameraPosition _initialCameraPosition; | |
late MapboxMapController controller; | |
late List<CameraPosition> _kRestaurantsList; | |
List<Map> carouselData = []; | |
// Carousel related | |
int pageIndex = 0; | |
late List<Widget> carouselItems; | |
@override | |
void initState() { | |
super.initState(); | |
_initialCameraPosition = CameraPosition(target: latLng, zoom: 15); | |
// Calculate the distance and time from data in SharedPreferences | |
for (int index = 0; index < restaurants.length; index++) { | |
num distance = getDistanceFromSharedPrefs(index) / 1000; | |
num duration = getDurationFromSharedPrefs(index) / 60; | |
carouselData | |
.add({'index': index, 'distance': distance, 'duration': duration}); | |
} | |
carouselData.sort((a, b) => a['duration'] < b['duration'] ? 0 : 1); | |
// Generate the list of carousel widgets | |
carouselItems = List<Widget>.generate( | |
restaurants.length, | |
(index) => carouselCard(carouselData[index]['index'], | |
carouselData[index]['distance'], carouselData[index]['duration'])); | |
// initialize map symbols in the same order as carousel widgets | |
_kRestaurantsList = List<CameraPosition>.generate( | |
restaurants.length, | |
(index) => CameraPosition( | |
target: getLatLngFromRestaurantData(carouselData[index]['index']), | |
zoom: 15)); | |
} | |
_addSourceAndLineLayer(int index, bool removeLayer) async { | |
// Can animate camera to focus on the item | |
controller.animateCamera( | |
CameraUpdate.newCameraPosition(_kRestaurantsList[index])); | |
// Add a polyLine between source and destination | |
Map geometry = getGeometryFromSharedPrefs(carouselData[index]['index']); | |
final _fills = { | |
"type": "FeatureCollection", | |
"features": [ | |
{ | |
"type": "Feature", | |
"id": 0, | |
"properties": <String, dynamic>{}, | |
"geometry": geometry, | |
}, | |
] | |
}; | |
// Remove lineLayer and source if it exists | |
if (removeLayer == true) { | |
await controller.removeLayer("lines"); | |
await controller.removeSource("fills"); | |
} | |
// Add new source and lineLayer | |
await controller.addSource("fills", GeojsonSourceProperties(data: _fills)); | |
await controller.addLineLayer( | |
"fills", | |
"lines", | |
LineLayerProperties( | |
lineColor: Colors.green.toHexStringRGB(), | |
lineCap: "round", | |
lineJoin: "round", | |
lineWidth: 2)); | |
} | |
_onMapCreated(MapboxMapController controller) async { | |
this.controller = controller; | |
} | |
_onStyleLoadedCallback() async { | |
for (CameraPosition _kRestaurant in _kRestaurantsList) { | |
await controller.addSymbol(SymbolOptions( | |
geometry: _kRestaurant.target, | |
iconSize: 0.2, | |
iconImage: "assets/icon/food.png", | |
)); | |
} | |
_addSourceAndLineLayer(0, false); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return Scaffold( | |
appBar: AppBar( | |
title: const Text('Restaurants Map'), | |
), | |
body: SafeArea( | |
child: Stack( | |
children: [ | |
SizedBox( | |
height: MediaQuery.of(context).size.height * 0.8, | |
child: MapboxMap( | |
accessToken: dotenv.env['MAPBOX_ACCESS_TOKEN'], | |
initialCameraPosition: _initialCameraPosition, | |
onMapCreated: _onMapCreated, | |
onStyleLoadedCallback: _onStyleLoadedCallback, | |
myLocationEnabled: true, | |
myLocationTrackingMode: MyLocationTrackingMode.TrackingGPS, | |
minMaxZoomPreference: const MinMaxZoomPreference(14, 17), | |
), | |
), | |
CarouselSlider( | |
items: carouselItems, | |
options: CarouselOptions( | |
height: 100, | |
viewportFraction: 0.6, | |
initialPage: 0, | |
enableInfiniteScroll: false, | |
scrollDirection: Axis.horizontal, | |
onPageChanged: | |
(int index, CarouselPageChangedReason reason) { | |
setState(() { | |
pageIndex = index; | |
}); | |
_addSourceAndLineLayer(index, true); | |
})), | |
], | |
), | |
), | |
floatingActionButton: FloatingActionButton( | |
onPressed: () { | |
controller.animateCamera( | |
CameraUpdate.newCameraPosition(_initialCameraPosition)); | |
}, | |
child: const Icon(Icons.my_location), | |
), | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment