import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; import 'package:lba/gen/assets.gen.dart'; import 'package:lba/res/colors.dart'; import 'package:lba/screens/mains/nearby/bestNearby.dart'; import 'package:lba/screens/product/productdetail.dart'; import 'package:location/location.dart'; import 'package:flutter_svg/flutter_svg.dart'; class MarkerData { final LatLng point; final String type; final String asset; final String name; final String place; final String distance; final String description; MarkerData({ required this.point, required this.type, required this.asset, required this.name, required this.place, required this.distance, required this.description, }); } class CustomMap extends StatefulWidget { const CustomMap({super.key}); @override _CustomMapState createState() => _CustomMapState(); } class _CustomMapState extends State with SingleTickerProviderStateMixin { Location location = Location(); late bool _serviceEnabled; late PermissionStatus _permissionGranted; late LocationData _locationData; late LatLng _currentCenter; final LatLng _defaultLocation = const LatLng(25.1972, 55.2744); // Burj Khalifa final MapController _mapController = MapController(); late AnimationController _animationController; late Animation _centerAnimation; late Animation _rotationAnimation; final List _manualMarkers = [ MarkerData( point: const LatLng(25.2399, 55.2744), type: 'air', asset: Assets.icons.materialSymbolsLocationAir.path, name: "McDonald's", place: "Mall of the Emirates", distance: "(3.2 Km away)", description: "Momos, Fast Food, Chinese", ), MarkerData( point: const LatLng(25.1950, 55.2399), type: 'ent', asset: Assets.icons.materialSymbolsLocationEnt.path, name: "Chattels & More", place: "Mall of the Emirates ", distance: "(1 Km away)", description: "Furniture and Home Store", ), MarkerData( point: const LatLng(25.1990, 55.2720), type: 'health', asset: Assets.icons.materialSymbolsLocationHealth.path, name: "McDonald's", place: "Mall of the Emirates", distance: "(3.2 Km away)", description: "Momos, Fast Food, Chinese", ), ]; List _markers = []; int? _selectedMarkerIndex; @override void initState() { super.initState(); _currentCenter = _defaultLocation; _initializeMarkers(); _checkLocationServices(); _animationController = AnimationController( duration: const Duration(milliseconds: 500), vsync: this, ); } void _initializeMarkers() { _markers = _manualMarkers.asMap().entries.map((entry) { int index = entry.key; MarkerData markerData = entry.value; bool isSelected = _selectedMarkerIndex == index; return Marker( width: 60.0, height: 60.0, point: markerData.point, child: GestureDetector( onTap: () { setState(() { _selectedMarkerIndex = index; }); }, child: Container( decoration: isSelected ? BoxDecoration( shape: BoxShape.circle, border: Border.all(color: AppColors.offerTimer, width: 3.0), ) : null, child: SvgPicture.asset( markerData.asset, width: 40.0, height: 40.0, ), ), ), ); }).toList(); } Future _checkLocationServices() async { _serviceEnabled = await location.serviceEnabled(); if (!_serviceEnabled) { _serviceEnabled = await location.requestService(); if (!_serviceEnabled) { setState(() { _currentCenter = _defaultLocation; }); _mapController.move(_currentCenter, 13.0); return; } } _permissionGranted = await location.hasPermission(); if (_permissionGranted == PermissionStatus.denied) { _permissionGranted = await location.requestPermission(); if (_permissionGranted != PermissionStatus.granted) { setState(() { _currentCenter = _defaultLocation; }); _mapController.move(_currentCenter, 13.0); return; } } try { _locationData = await location.getLocation(); setState(() { _currentCenter = LatLng( _locationData.latitude!, _locationData.longitude!, ); }); _mapController.move(_currentCenter, 13.0); } catch (e) { print('Error getting location: $e'); setState(() { _currentCenter = _defaultLocation; }); _mapController.move(_currentCenter, 13.0); } } void _recenterMap() { final currentCenter = _mapController.camera.center; final currentRotation = _mapController.camera.rotation; _centerAnimation = LatLngTween( begin: currentCenter, end: _currentCenter, ).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _rotationAnimation = Tween( begin: currentRotation, end: 0.0, ).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _animationController.addListener(() { _mapController.move(_centerAnimation.value, 13.0); _mapController.rotate(_rotationAnimation.value); }); _animationController.reset(); _animationController.forward(); } Widget _buildMarkerDetails() { return Positioned( bottom: 10, left: 0, right: 0, child: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.all(8.0), child: ElevatedButton( onPressed: _recenterMap, style: ElevatedButton.styleFrom( backgroundColor: AppColors.surface, foregroundColor: AppColors.primary, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), ), child: Row( children: [ SvgPicture.asset(Assets.icons.recenter.path,), SizedBox(width: 5,), Text('Re-Center',style: TextStyle(fontSize: 15),), ], ), ), ), ElevatedButton( onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) => Bestnearby(),)); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: AppColors.surface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.0), ), ), child: Text("Best Nearby",style: TextStyle(fontSize: 15),), ), ], ), ), if (_selectedMarkerIndex == null) Container( height: 245, width: double.infinity, padding: const EdgeInsets.only(bottom: 90,left: 0), child: Center( child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: _manualMarkers.length, itemBuilder: (context, index) { final marker = _manualMarkers[index]; return GestureDetector( onTap: () { Navigator.of(context).push(MaterialPageRoute(builder: (context) => Productdetail(),)); }, child: CustomCard(marker: marker), ); }, ), ), ) else Padding( padding: const EdgeInsets.only(bottom: 90,right: 8,left: 8,), child: Container( margin: const EdgeInsets.symmetric(horizontal: 5), padding: const EdgeInsets.all(8.0).copyWith(bottom: 15), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: AppColors.nearbyPopup, border: Border.all(color: AppColors.surface, width: 4.0), ), child: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(11), ), child: Image.asset(Assets.images.image.path), ), Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _manualMarkers[_selectedMarkerIndex!].name, style: TextStyle(color: AppColors.textPrimary), ), SizedBox(height: 5), Text( "${_manualMarkers[_selectedMarkerIndex!].place} ${_manualMarkers[_selectedMarkerIndex!].distance}", style: TextStyle( color: AppColors.nearbyPopuphint, ), ), SizedBox(height: 5), Text( _manualMarkers[_selectedMarkerIndex!] .description, style: TextStyle( color: AppColors.nearbyPopuphint, fontSize: 10, ), ), ], ), ), ], ), SizedBox(height: 10), Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ SvgPicture.asset(Assets.icons.mDSPublicTWTag.path, color: AppColors.isDarkMode ? AppColors.textPrimary : null), SizedBox(width: 10), Text( "(15%) 43 - 36.55 AED ", style: TextStyle(fontWeight: FontWeight.bold), ), ], ), ], ), ), ), ), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( body: OrientationBuilder( builder: (context, orientation) { if (orientation == Orientation.portrait) { WidgetsBinding.instance.addPostFrameCallback((_) { _recenterMap(); }); } return Stack( children: [ FlutterMap( mapController: _mapController, options: MapOptions( initialCenter: _defaultLocation, initialZoom: 13.0, ), children: [ TileLayer( urlTemplate: 'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png', userAgentPackageName: 'com.example.lba', subdomains: const ['a', 'b', 'c', 'd'], additionalOptions: const { 'attribution': '© CARTO © OpenStreetMap contributors', }, ), MarkerLayer(markers: _markers), ], ), _buildMarkerDetails(), ], ); }, ), ); } @override void dispose() { _animationController.dispose(); super.dispose(); } } class CustomCard extends StatelessWidget { const CustomCard({ super.key, required this.marker, }); final MarkerData marker; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only(left: 8), child: Container( margin: const EdgeInsets.symmetric(horizontal: 5), padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: AppColors.nearbyPopup, border: Border.all(color: AppColors.surface, width: 4.0), ), child: Padding( padding: const EdgeInsets.all(8.0), child: Center( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(11), ), child: Image.asset(Assets.images.image.path), ), Padding( padding: const EdgeInsets.all(8.0), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( marker.name, style: TextStyle(color: AppColors.textPrimary), ), SizedBox(height: 5), Text( "${marker.place} ${marker.distance}", style: TextStyle( color: AppColors.nearbyPopuphint, ), ), SizedBox(height: 5), Text( marker.description, style: TextStyle( color: AppColors.nearbyPopuphint, fontSize: 10, ), ), ], ), ), ], ), SizedBox(height: 10), Row( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ SvgPicture.asset( Assets.icons.mDSPublicTWTag.path, ), SizedBox(width: 10), Text( "(15%) 43 - 36.55 AED ", style: TextStyle(fontWeight: FontWeight.bold,), ), ], ), ], ), ), ), ), ); } } class LatLngTween extends Tween { LatLngTween({required LatLng begin, required LatLng end}) : super(begin: begin, end: end); @override LatLng lerp(double t) { return LatLng( begin!.latitude + (end!.latitude - begin!.latitude) * t, begin!.longitude + (end!.longitude - begin!.longitude) * t, ); } }