proxybuy-flutter/lib/screens/nearby/map.dart

471 lines
16 KiB
Dart

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/nearby/bestNearby.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<CustomMap>
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<LatLng> _centerAnimation;
late Animation<double> _rotationAnimation;
final List<MarkerData> _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<Marker> _markers = [];
int? _selectedMarkerIndex;
@override
void initState() {
super.initState();
_currentCenter = _defaultLocation;
_initializeMarkers();
_checkLocationServices();
// Initialize AnimationController
_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: Colors.red, width: 3.0),
)
: null,
child: SvgPicture.asset(
markerData.asset,
width: 40.0,
height: 40.0,
),
),
),
);
}).toList();
}
Future<void> _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<double>(
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: [
// Recenter Button
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: Colors.white,
foregroundColor: Colors.blue,
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: Colors.blue,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
child: Text("Best Nearby",style: TextStyle(fontSize: 15),),
),
],
),
),
// Marker Details
if (_selectedMarkerIndex == null)
Container(
height: 190,
width: double.infinity,
padding: const EdgeInsets.only(bottom: 25,left: 8),
child: Center(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _manualMarkers.length,
itemBuilder: (context, index) {
final marker = _manualMarkers[index];
return Container(
margin: const EdgeInsets.symmetric(horizontal: 5),
padding: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: LightAppColors.nearbyPopup,
border: Border.all(color: Colors.white, width: 2.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: Colors.black),
),
SizedBox(height: 5),
Text(
"${marker.place} ${marker.distance}",
style: TextStyle(
color: LightAppColors.nearbyPopuphint,
),
),
SizedBox(height: 5),
Text(
marker.description,
style: TextStyle(
color: LightAppColors.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),
),
],
),
],
),
),
),
);
},
),
),
)
else
Container(
margin: const EdgeInsets.symmetric(horizontal: 5),
padding: const EdgeInsets.all(8.0).copyWith(bottom: 15),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: LightAppColors.nearbyPopup,
border: Border.all(color: Colors.white, width: 2.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: Colors.black),
),
SizedBox(height: 5),
Text(
"${_manualMarkers[_selectedMarkerIndex!].place} ${_manualMarkers[_selectedMarkerIndex!].distance}",
style: TextStyle(
color: LightAppColors.nearbyPopuphint,
),
),
SizedBox(height: 5),
Text(
_manualMarkers[_selectedMarkerIndex!]
.description,
style: TextStyle(
color: LightAppColors.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),
),
],
),
],
),
),
),
),
],
),
);
}
@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://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.example.app',
),
MarkerLayer(markers: _markers),
],
),
_buildMarkerDetails(),
],
);
},
),
);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
}
// Helper class for animating LatLng
class LatLngTween extends Tween<LatLng> {
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,
);
}
}