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

4
.gitignore vendored
View File

@@ -42,3 +42,7 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
lib/constant/credential.dart

View File

@@ -1,33 +1,24 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="ride"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application android:label="ride" android:name="${applicationName}" android:icon="@mipmap/ic_launcher">
<activity android:name=".MainActivity" android:exported="true" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<meta-data android:name="com.google.android.geo.API_KEY" android:value="AIzaSyCyfwRXTwSTLOFQSQgN5p7QZgGJVZnEKq0" />
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data android:name="flutterEmbedding" android:value="2" />
</application>
</manifest>

View File

@@ -1,5 +1,5 @@
buildscript {
ext.kotlin_version = '1.7.10'
ext.kotlin_version = '1.9.0'
repositories {
google()
mavenCentral()

BIN
assets/images/picker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

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(),
),
);
},
),
)
],
),
),
],
),
),
);
}
}

View File

@@ -8,7 +8,7 @@ import Foundation
import firebase_core
import firebase_messaging
import flutter_local_notifications
import geolocator_apple
import location
import path_provider_foundation
import sqflite
import url_launcher_macos
@@ -17,7 +17,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
LocationPlugin.register(with: registry.registrar(forPlugin: "LocationPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))

View File

@@ -97,6 +97,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.5"
custom_searchable_dropdown:
dependency: "direct main"
description:
name: custom_searchable_dropdown
sha256: c2676b1ee55f0b71a7cd890ae473cf97651f018b2695b3bf57c8c28a14e2fa95
url: "https://pub.dev"
source: hosted
version: "2.1.1"
dbus:
dependency: transitive
description:
@@ -214,14 +222,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.15"
flutter_polyline_points:
dependency: "direct main"
description:
name: flutter_polyline_points
sha256: "02699e69142f51a248d784b6e3eec524194467fca5f7c4da19699ce2368b6980"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -232,54 +232,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
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: "835ff5b4888a2f8eba128996494faf9c5d422785322a81dc0565b99e0f6c379d"
url: "https://pub.dev"
source: hosted
version: "4.2.2"
geolocator_apple:
dependency: transitive
description:
name: geolocator_apple
sha256: "36527c555f4c425f7d8fa8c7c07d67b78e3ff7590d40448051959e1860c1cfb4"
url: "https://pub.dev"
source: hosted
version: "2.2.7"
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"
get:
dependency: "direct main"
description:
@@ -360,6 +312,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.3"
google_polyline_algorithm:
dependency: "direct main"
description:
name: google_polyline_algorithm
sha256: "357874f00d3f93c3ba1bf4b4d9a154aa9ee87147c068238c1e8392012b686a03"
url: "https://pub.dev"
source: hosted
version: "3.1.0"
google_sign_in:
dependency: "direct main"
description:
@@ -456,6 +416,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
location:
dependency: "direct main"
description:
name: location
sha256: c8e0c8cd92c6ce8b42760f9aafd6d80592459e2e0cd702bc336061c738ec4715
url: "https://pub.dev"
source: hosted
version: "5.0.2+1"
location_platform_interface:
dependency: transitive
description:
name: location_platform_interface
sha256: a211a41b1fdfaddaf02996750dd703abcc7ac1d4fd90e978c8773ccf2260af68
url: "https://pub.dev"
source: hosted
version: "3.1.1"
location_web:
dependency: transitive
description:
name: location_web
sha256: acde3e95c4dec2b82cbdc3490bf010eeaf66e793e20f62364887e072bd701d49
url: "https://pub.dev"
source: hosted
version: "4.1.1"
lottie:
dependency: "direct main"
description:
@@ -757,14 +741,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.7"
uuid:
dependency: transitive
description:
name: uuid
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
vector_math:
dependency: transitive
description:

View File

@@ -38,9 +38,7 @@ dependencies:
firebase_messaging: ^14.6.5
firebase_core: ^2.15.0
flutter_local_notifications: ^15.1.0+1
geolocator: ^9.0.2
google_maps_flutter: ^2.4.0
flutter_polyline_points: ^1.0.0
sqflite: ^2.3.0
path: ^1.8.3
google_sign_in: ^6.1.4
@@ -51,6 +49,9 @@ dependencies:
get: ^4.6.5
get_storage: ^2.1.1
url_launcher: ^6.1.12
location: ^5.0.2+1
google_polyline_algorithm: ^3.1.0
custom_searchable_dropdown: ^2.1.1
dev_dependencies:
flutter_test:

View File

@@ -7,14 +7,11 @@
#include "generated_plugin_registrant.h"
#include <firebase_core/firebase_core_plugin_c_api.h>
#include <geolocator_windows/geolocator_windows.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
FirebaseCorePluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
GeolocatorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("GeolocatorWindows"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

@@ -4,7 +4,6 @@
list(APPEND FLUTTER_PLUGIN_LIST
firebase_core
geolocator_windows
url_launcher_windows
)