This commit is contained in:
Hamza-Ayed
2023-08-06 18:06:28 +03:00
parent 5a7c09eb06
commit f051d47402
16 changed files with 497 additions and 108 deletions

View File

@@ -1,12 +0,0 @@
import 'dart:convert';
class AppCredintials {
static const String basicAuthCredentials = 'hamzaayedphp:malDEV@2101';
static const String serverAPI =
'AAAAinYllCo:APA91bF1shTpzSsSxqbfY6c60D8zs1ZsdIsl9ix6nl7GDdjCqWPRK0G0ub5SqFdb1jDpQDvQPxGg-697MWLo0sy3oYImBwBLObyhk0GjtNzyr0PbE3hI-pOvhf8Vp1xgUgBmofbZYXkH';
// static const String mapAPIKEY = 'AIzaSyC1pjEgB78OFz_-2nwTvGltHjXho0y99MY';
static const String mapAPIKEY = 'AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0';
String getBasicAuthCredentials() {
return base64Encode(utf8.encode(basicAuthCredentials));
}
}

View File

@@ -1,5 +1,6 @@
class AppLink {
static const String server = 'https://ride.mobile-app.store/';
static const String googleMapsLink = 'https://maps.googleapis.com/maps/api/';
static const String test = "$server/test.php";

View File

@@ -38,6 +38,7 @@ class CRUD {
'Basic ${base64Encode(utf8.encode(AppCredintials.basicAuthCredentials))}',
},
);
if (response.statusCode == 200) {
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == 'success') {
@@ -55,6 +56,26 @@ class CRUD {
return (response.body);
}
Future<dynamic> getGoogleApi({
required String link,
Map<String, dynamic>? payload,
}) async {
var url = Uri.parse(
link,
);
var response = await http.post(
url,
body: payload,
);
print(response.request);
var jsonData = jsonDecode(response.body);
// print(jsonData);
if (jsonData['status'] == 'OK') {
return jsonData;
}
return (jsonData['status']);
}
Future<dynamic> update({
required String endpoint,
required Map<String, dynamic> data,

View File

@@ -0,0 +1,273 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'dart:math' as math;
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:google_polyline_algorithm/google_polyline_algorithm.dart';
import 'package:ride/constant/colors.dart';
import 'package:ride/constant/credential.dart';
import 'package:ride/constant/links.dart';
import 'package:ride/constant/style.dart';
import 'package:ride/controller/functions/crud.dart';
class MapController extends GetxController {
bool isloading = true;
TextEditingController placeController = TextEditingController();
List data = [];
List<LatLng> bounds = [];
List places = [];
LatLngBounds? boundsdata;
List<Marker> markers = [];
List<Polyline> polylines = [];
LatLng mylocation = const LatLng(32.111965, 36.067427);
LatLng mydestination = const LatLng(32.115295, 36.064773);
final List<LatLng> polylineCoordinates = [];
BitmapDescriptor markerIcon = BitmapDescriptor.defaultMarker;
double height = 200;
changeHeight() {
if (places.isEmpty) {
height = 0;
update();
}
height = 200;
update();
}
hidePlaces() {
height = 0;
update();
}
Future getPlaces() async {
var url =
'${AppLink.googleMapsLink}place/nearbysearch/json?keyword=${placeController.text}&location=32.111946,${mylocation.longitude}&radius=10000&type=restaurant&language=ar&key=${AppCredintials.mapAPIKEY}';
var response = await CRUD().getGoogleApi(link: url, payload: {});
places = response['results'];
print(places);
update();
}
LatLng fromString(String location) {
List<String> parts = location.split(',');
double lat = double.parse(parts[0]);
double lng = double.parse(parts[1]);
return LatLng(lat, lng);
}
void clearpolyline() {
polylines = [];
polylineCoordinates.clear();
update();
}
void addCustomPicker() {
ImageConfiguration config = const ImageConfiguration(
size: Size(20, 20),
// scale: 1.0,
);
BitmapDescriptor.fromAssetImage(config, 'assets/images/picker.png')
.then((value) {
markerIcon = value;
update();
});
}
GoogleMapController? mapController;
void onMapCreated(GoogleMapController controller) {
mapController = controller;
controller.getVisibleRegion();
update();
}
getMap(String origin, destination) async {
var origin1 = fromString(origin);
var destination1 = fromString(destination);
isloading = false;
mydestination = destination1;
mylocation = origin1;
update();
var url =
('${AppLink.googleMapsLink}directions/json?&language=en&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AppCredintials.mapAPIKEY}');
var response = await CRUD().getGoogleApi(link: url, payload: {});
data = response['routes'][0]['legs'];
final points =
decodePolyline(response["routes"][0]["overview_polyline"]["points"]);
for (int i = 0; i < points.length; i++) {
double lat = points[i][0].toDouble();
double lng = points[i][1].toDouble();
polylineCoordinates.add(LatLng(lat, lng));
}
// // Define the northeast and southwest coordinates
final bounds = response["routes"][0]["bounds"];
// LatLng northeast =
// LatLng(bounds['northeast']['lat'], bounds['northeast']['lng']);
// LatLng southwest =
// LatLng(bounds['southwest']['lat'], bounds['southwest']['lng']);
// // Create the LatLngBounds using the coordinates
// boundsdata = LatLngBounds(northeast: northeast, southwest: southwest);
// update();
// print(boundsdata);
////////////////////////////////////////////
// Create the northeast and southwest LatLng objects
LatLng northeast =
LatLng(bounds['northeast']['lat'], bounds['northeast']['lng']);
LatLng southwest =
LatLng(bounds['southwest']['lat'], bounds['southwest']['lng']);
// Create the LatLngBounds object
LatLngBounds boundsData =
LatLngBounds(northeast: northeast, southwest: southwest);
// Calculate padding for the bounding box
double distance = math.sqrt(
math.pow(northeast.latitude - southwest.latitude, 2) +
math.pow(northeast.longitude - southwest.longitude, 2),
);
// Define the map padding
final double padding = 50.0;
// Get the screen dimensions
final screenSize = Get.size;
print(screenSize.width);
print('================');
// Adjust the bounding box to include padding
LatLngBounds adjustedBounds = LatLngBounds(
southwest: LatLng(boundsData.southwest.latitude - padding,
boundsData.southwest.longitude - padding),
northeast: LatLng(boundsData.northeast.latitude + padding,
boundsData.northeast.longitude + padding),
);
// Calculate the zoom level based on the distance and screen size
double zoomLevel = getZoomLevel(distance, screenSize.width);
// Animate the camera to the adjusted bounds
mapController!.animateCamera(CameraUpdate.newLatLngBounds(
adjustedBounds,
screenSize.width,
));
if (polylines.isNotEmpty) {
clearpolyline();
} else {
var polyline = Polyline(
polylineId: PolylineId(response["routes"][0]["summary"]),
points: polylineCoordinates,
width: 10,
color: Colors.blue,
);
polylines.add(polyline);
update();
}
}
double getZoomLevel(double distance, double screenWidth) {
const double zoomFactor = 15.0;
const double pixelRatio =
156543.03392; // Earth circumference in pixels at zoom level 0
double zoomLevel =
(math.log(pixelRatio * screenWidth / (distance * zoomFactor))) /
math.log(2);
return zoomLevel;
}
double getDistanceFromText(String distanceText) {
// Remove any non-digit characters from the distance text
String distanceValue = distanceText.replaceAll(RegExp(r'[^0-9.]+'), '');
// Parse the extracted numerical value as a double
double distance = double.parse(distanceValue);
return distance;
}
void bottomSheet() {
String distanceText = data[0]['distance']['text'];
String durationText = data[0]['duration']['text'];
double distance = getDistanceFromText(distanceText);
double duration = getDistanceFromText(durationText);
double cost = distance * 0.21;
double costDuration = duration * 0.05;
double totalPassenger = cost + costDuration;
Get.bottomSheet(
Container(
height: 130,
color: AppColor.secondaryColor,
child: data.isEmpty
? Center(
child: Text(
'Where are you want to go..',
style: AppStyle.title,
))
: Center(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
'distance is ${data[0]['distance']['text']}',
style: AppStyle.title,
),
Text(
'duration is ${data[0]['duration']['text']}',
style: AppStyle.title,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
'Cost for .21/km $cost ',
style: AppStyle.title,
),
Text(
'Cost duration .05/m $costDuration ',
style: AppStyle.title,
),
],
),
Text(
'Total cost $totalPassenger ',
style: AppStyle.title,
),
],
),
),
),
elevation: 6,
enableDrag: true,
isDismissible: true,
useRootNavigator: true,
backgroundColor: AppColor.secondaryColor,
barrierColor: AppColor.accentColor.withOpacity(.4),
persistent: true,
);
}
List<LatLng> polylineCoordinate = [];
double calculateCost(double distance) {
const double costRate = 0.27;
// double distanceInKm = distance / 1000; // convert distance to kilometers
double cost = costRate * distance;
return cost;
}
@override
void onInit() {
// getPolyLine();
// getMap();
addCustomPicker();
super.onInit();
}
}

View File

@@ -8,7 +8,7 @@ import 'constant/box_name.dart';
import 'controller/local/local_controller.dart';
import 'controller/local/translations.dart';
import 'firebase_options.dart';
import 'views/home/auth/login_page.dart';
import 'views/home/map_page.dart';
final box = GetStorage();
void main() async {
@@ -30,7 +30,7 @@ class MyApp extends StatelessWidget {
LocaleController controller = Get.put(LocaleController());
return GetMaterialApp(
title: 'Fleek-tech',
title: 'Ride',
translations: MyTranslation(),
debugShowCheckedModeBanner: false,
locale: controller.language,
@@ -40,6 +40,6 @@ class MyApp extends StatelessWidget {
home: box.read(BoxName.lang).toString() != 'ar' &&
box.read(BoxName.lang).toString() != 'en'
? const Language()
: LoginPage());
: const MapPage());
}
}

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../controller/auth/login_controller.dart';
import '../../controller/auth/login_controller.dart';
class LoginPage extends StatelessWidget {
final controller = Get.put(LoginController());

View File

@@ -0,0 +1,138 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:ride/constant/colors.dart';
import 'package:ride/controller/home/map_page_controller.dart';
class MapPage extends StatelessWidget {
const MapPage({super.key});
@override
Widget build(BuildContext context) {
Get.put(MapController());
return Scaffold(
body: GetBuilder<MapController>(
builder: (controller) => Stack(
children: [
GoogleMap(
onMapCreated: controller.onMapCreated,
cameraTargetBounds: CameraTargetBounds(controller.boundsdata),
minMaxZoomPreference: const MinMaxZoomPreference(12, 18),
onLongPress: (argument) {
Get.defaultDialog(
title: 'Are you want to go to this site',
content: Column(
children: [
Text('${argument.latitude},${argument.longitude}'),
],
),
onConfirm: () {
controller.clearpolyline();
controller.getMap('32.111946, 36.067396',
'${argument.latitude.toString()},${argument.longitude.toString()}');
Get.back();
controller.bottomSheet();
},
);
},
onTap: (argument) {
controller.hidePlaces();
controller.bottomSheet();
},
initialCameraPosition: CameraPosition(
target: controller.mylocation,
zoom: 15,
),
markers: {
Marker(
markerId: const MarkerId('MyLocation'),
position: controller.mylocation,
draggable: true,
icon: controller.markerIcon,
onDragEnd: (value) {
print(value);
},
infoWindow: const InfoWindow(title: 'my location'),
),
Marker(
markerId: const MarkerId('destination'),
position: controller.mydestination),
},
polylines: {
Polyline(
polylineId: const PolylineId('route'),
points: controller.polylineCoordinates,
color: AppColor.primaryColor,
width: 3,
)
},
mapType: MapType.normal,
myLocationButtonEnabled: true,
indoorViewEnabled: true,
trafficEnabled: true,
),
Positioned(
top: 10,
left: 0,
right: 0,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(16),
child: Container(
decoration:
const BoxDecoration(color: AppColor.secondaryColor),
child: TextField(
decoration: const InputDecoration(
suffixIcon: Icon(Icons.search)),
controller: controller.placeController,
onChanged: (value) {
if (controller.placeController.text.length > 6) {
controller.getPlaces();
controller.changeHeight();
}
},
// onEditingComplete: () => controller.changeHeight(),
),
),
),
Container(
height:
controller.places.isNotEmpty ? controller.height : 0,
color: AppColor.secondaryColor,
child: ListView.builder(
itemCount: controller.places.length,
itemBuilder: (BuildContext context, int index) {
var res = controller.places[index];
return TextButton(
onPressed: () {
controller.changeHeight();
Get.defaultDialog(
title: 'Are You sure to ride to ${res['name']}',
middleText: '',
onConfirm: () {
controller.getMap(
'${controller.mylocation.latitude.toString()},${controller.mylocation.longitude.toString()}',
"${res['geometry']['location']['lat']},${res['geometry']['location']['lng']}");
controller.places = [];
Get.back();
},
);
},
child: Text(
res['name'].toString(),
),
);
},
),
)
],
),
),
],
),
),
);
}
}