From 8d5fefc9e36a8a3dcb58184e4093d4865e479999 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Sat, 4 Apr 2026 14:08:07 +0300 Subject: [PATCH] 2026-04-03-maplibra primary succsess --- assets/style.json | 1801 +++++++++++++++++ ios/Podfile.lock | 27 +- ios/Runner.xcodeproj/project.pbxproj | 39 +- ios/Runner/AppDelegate.swift | 15 +- lib/constant/country_polygons.dart | 2 +- lib/constant/links.dart | 4 +- lib/constant/univeries_polygon.dart | 2 +- .../functions/location_controller.dart | 1 - .../home/decode_polyline_isolate.dart | 2 +- .../home/map_passenger_controller.dart | 989 +++------ .../home/points_for_rider_controller.dart | 2 +- .../home/trip_monitor_controller.dart | 99 +- lib/print.dart | 2 +- .../trip_monitor/trip_link_monitor.dart | 25 +- .../HomePage/trip_monitor/trip_monitor.dart | 24 +- .../form_search_places_destenation.dart | 2 +- .../map_widget.dart/form_search_start.dart | 2 +- .../google_map_passenger_widget.dart | 115 +- .../map_widget.dart/left_main_menu_icons.dart | 2 +- .../map_widget.dart/main_bottom_Menu_map.dart | 4 +- lib/views/home/profile/order_history.dart | 49 +- pubspec.lock | 64 +- pubspec.yaml | 6 +- 23 files changed, 2331 insertions(+), 947 deletions(-) create mode 100644 assets/style.json diff --git a/assets/style.json b/assets/style.json new file mode 100644 index 0000000..880fe53 --- /dev/null +++ b/assets/style.json @@ -0,0 +1,1801 @@ +{ + "version": 8, + "name": "Intaleq Premium Map Style", + "metadata": { + "brand": "Intaleq", + "version": "2.0.0", + "description": "Google + OSM hybrid style with 3D buildings, railways, subway, waterways, and Intaleq brand palette" + }, + "center": [ + 36.276008, + 33.513685 + ], + "zoom": 15, + "glyphs": "https://cdn.protomaps.com/fonts/pbf/{fontstack}/{range}.pbf", + "sprite": "https://demotiles.maplibre.org/styles/osm-bright-gl-style/sprite", + "sources": { + "local-osm-polygons": { + "type": "vector", + "tiles": [ + "https://tiles.intaleqapp.com/planet_osm_polygon/{z}/{x}/{y}" + ], + "maxzoom": 14, + "attribution": "© Intaleq | © OpenStreetMap contributors" + }, + "local-osm-lines": { + "type": "vector", + "tiles": [ + "https://tiles.intaleqapp.com/planet_osm_line/{z}/{x}/{y}" + ], + "maxzoom": 14 + }, + "local-osm-points": { + "type": "vector", + "tiles": [ + "https://tiles.intaleqapp.com/planet_osm_point/{z}/{x}/{y}" + ], + "maxzoom": 14 + }, + "places_egypt": { + "type": "vector", + "tiles": [ + "https://tiles.intaleqapp.com/places_egypt/{z}/{x}/{y}" + ], + "maxzoom": 14 + } + }, + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "#EEF2F7" + } + }, + { + "id": "landuse-residential", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "==", + "landuse", + "residential" + ], + "paint": { + "fill-color": "#F0F4F8", + "fill-opacity": 1 + } + }, + { + "id": "landuse-commercial", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "==", + "landuse", + "commercial" + ], + "paint": { + "fill-color": "#FAF5EE", + "fill-opacity": 1 + } + }, + { + "id": "landuse-industrial", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "in", + "landuse", + "industrial", + "railway" + ], + "paint": { + "fill-color": "#E4E8EE", + "fill-opacity": 1 + } + }, + { + "id": "landuse-cemetery", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "==", + "landuse", + "cemetery" + ], + "paint": { + "fill-color": "#B8D4BA", + "fill-opacity": 0.9 + } + }, + { + "id": "landuse-military", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "==", + "landuse", + "military" + ], + "paint": { + "fill-color": "#E2D9CC", + "fill-opacity": 0.8 + } + }, + { + "id": "park-layer", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "any", + [ + "in", + "leisure", + "park", + "garden", + "nature_reserve", + "pitch", + "playground" + ], + [ + "in", + "landuse", + "grass", + "meadow", + "forest" + ], + [ + "in", + "natural", + "wood", + "scrub", + "heath" + ] + ], + "paint": { + "fill-color": [ + "match", + [ + "get", + "leisure" + ], + "pitch", + "#9ED4A0", + "playground", + "#B8E6B8", + "#C5E8C5" + ], + "fill-opacity": 0.85 + } + }, + { + "id": "park-outline", + "type": "line", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "in", + "leisure", + "park", + "garden", + "nature_reserve" + ], + "paint": { + "line-color": "#94D4A0", + "line-width": 0.8, + "line-opacity": 0.7 + } + }, + { + "id": "water-polygon", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "any", + [ + "in", + "natural", + "water", + "lake", + "bay" + ], + [ + "==", + "waterway", + "riverbank" + ], + [ + "in", + "landuse", + "basin", + "reservoir" + ], + [ + "==", + "amenity", + "fountain" + ] + ], + "paint": { + "fill-color": "#9ECFE8", + "fill-opacity": 0.95 + } + }, + { + "id": "water-polygon-outline", + "type": "line", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "any", + [ + "in", + "natural", + "water", + "lake", + "bay" + ], + [ + "==", + "waterway", + "riverbank" + ], + [ + "in", + "landuse", + "basin", + "reservoir" + ] + ], + "paint": { + "line-color": "#6BB8D8", + "line-width": 0.8, + "line-opacity": 0.8 + } + }, + { + "id": "waterway-river", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "all", + [ + "in", + "waterway", + "river", + "canal" + ], + [ + "!=", + "intermittent", + "yes" + ], + [ + "!=", + "seasonal", + "yes" + ], + [ + "!=", + "tunnel", + "yes" + ] + ], + "paint": { + "line-color": "#6BB8D8", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 1.5, + 14, + 4, + 16, + 7 + ], + "line-opacity": 0.95 + } + }, + { + "id": "waterway-stream-drain", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "all", + [ + "in", + "waterway", + "stream", + "drain", + "ditch" + ], + [ + "!=", + "intermittent", + "yes" + ], + [ + "!=", + "seasonal", + "yes" + ], + [ + "!=", + "tunnel", + "yes" + ] + ], + "minzoom": 13, + "paint": { + "line-color": "#7FBFD8", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 0.8, + 16, + 2.5 + ], + "line-opacity": 0.85 + } + }, + { + "id": "railway-area", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "==", + "landuse", + "railway" + ], + "paint": { + "fill-color": "#DDE2EA", + "fill-opacity": 0.9 + } + }, + { + "id": "railway-rail-casing", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "all", + [ + "in", + "railway", + "rail", + "narrow_gauge", + "preserved" + ], + [ + "!=", + "service", + "yard" + ], + [ + "!=", + "service", + "siding" + ] + ], + "minzoom": 8, + "paint": { + "line-color": "#B0B8C5", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 2, + 12, + 4, + 16, + 8 + ] + } + }, + { + "id": "railway-rail-core", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "all", + [ + "in", + "railway", + "rail", + "narrow_gauge", + "preserved" + ], + [ + "!=", + "service", + "yard" + ], + [ + "!=", + "service", + "siding" + ] + ], + "minzoom": 8, + "paint": { + "line-color": "#6B7A8E", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 8, + 1, + 12, + 2.5, + 16, + 5 + ], + "line-dasharray": [ + 6, + 4 + ] + } + }, + { + "id": "railway-subway-casing", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "railway", + "subway", + "light_rail", + "tram", + "monorail" + ], + "minzoom": 10, + "paint": { + "line-color": [ + "match", + [ + "get", + "railway" + ], + "subway", + "#CC2233", + "light_rail", + "#0066CC", + "tram", + "#8833BB", + "monorail", + "#008855", + "#BB3344" + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 3, + 14, + 6, + 16, + 10 + ] + } + }, + { + "id": "railway-subway-core", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "railway", + "subway", + "light_rail", + "tram", + "monorail" + ], + "minzoom": 10, + "paint": { + "line-color": [ + "match", + [ + "get", + "railway" + ], + "subway", + "#FF3347", + "light_rail", + "#2288FF", + "tram", + "#AA44EE", + "monorail", + "#00BB66", + "#FF4455" + ], + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 1.5, + 14, + 3.5, + 16, + 6 + ] + } + }, + { + "id": "road-casing-track-path", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "track", + "path", + "footway", + "cycleway", + "steps" + ], + "minzoom": 14, + "paint": { + "line-color": "#C8CDD6", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 1, + 16, + 4 + ], + "line-dasharray": [ + 4, + 3 + ] + } + }, + { + "id": "road-casing-minor", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "residential", + "service", + "unclassified", + "living_street", + "pedestrian" + ], + "paint": { + "line-color": "#D4D8DF", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12, + 1.5, + 16, + 10 + ], + "line-opacity": 0.7 + } + }, + { + "id": "road-core-minor", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "residential", + "service", + "unclassified", + "living_street", + "pedestrian" + ], + "paint": { + "line-color": "#FFFFFF", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12, + 0.8, + 16, + 8 + ] + } + }, + { + "id": "road-casing-tertiary", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "tertiary", + "tertiary_link" + ], + "paint": { + "line-color": "#C9CED8", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 11, + 2, + 16, + 14 + ], + "line-opacity": 0.75 + } + }, + { + "id": "road-core-tertiary", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "tertiary", + "tertiary_link" + ], + "paint": { + "line-color": "#FFFFFF", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 11, + 1.2, + 16, + 11 + ] + } + }, + { + "id": "road-casing-secondary", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "secondary", + "secondary_link" + ], + "paint": { + "line-color": "#C4CFDE", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 11, + 2.5, + 16, + 16 + ], + "line-opacity": 0.8 + } + }, + { + "id": "road-core-secondary", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "secondary", + "secondary_link" + ], + "paint": { + "line-color": "#F8FBFF", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 11, + 1.8, + 16, + 13 + ] + } + }, + { + "id": "road-casing-primary", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "primary", + "primary_link" + ], + "paint": { + "line-color": "#C8B868", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 3, + 16, + 18 + ], + "line-opacity": 0.7 + } + }, + { + "id": "road-core-primary", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "primary", + "primary_link" + ], + "paint": { + "line-color": "#EDD870", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 2, + 16, + 14 + ] + } + }, + { + "id": "road-casing-motorway-trunk", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "motorway", + "motorway_link", + "trunk", + "trunk_link" + ], + "paint": { + "line-color": "#C8A84B", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 4, + 16, + 20 + ], + "line-opacity": 0.75 + } + }, + { + "id": "road-core-motorway-trunk", + "type": "line", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "motorway", + "motorway_link", + "trunk", + "trunk_link" + ], + "paint": { + "line-color": "#F0C040", + "line-width": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 9, + 2.5, + 16, + 16 + ] + } + }, + { + "id": "building-fill-flat", + "type": "fill", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "filter": [ + "has", + "building" + ], + "maxzoom": 14, + "paint": { + "fill-color": "#DDD8D0", + "fill-opacity": 0.85, + "fill-outline-color": "#C4BEB4" + } + }, + { + "id": "building-3d", + "type": "fill-extrusion", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "minzoom": 14, + "filter": [ + "has", + "building" + ], + "paint": { + "fill-extrusion-color": [ + "match", + [ + "get", + "building" + ], + "commercial", + "#DDD5C5", + "retail", + "#E5D8C8", + "industrial", + "#D2D8E0", + "church", + "#DDD4EE", + "mosque", + "#CCE4D0", + "hospital", + "#EDD8D8", + "school", + "#E0E6CC", + "university", + "#D8E0C8", + "hotel", + "#D8DCF0", + "apartments", + "#E0DCD4", + "#DDD8D2" + ], + "fill-extrusion-height": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + [ + "*", + [ + "coalesce", + [ + "to-number", + [ + "get", + "building:levels" + ], + null + ], + 3 + ], + 2.5 + ], + 17, + [ + "coalesce", + [ + "to-number", + [ + "get", + "height" + ], + null + ], + [ + "*", + [ + "to-number", + [ + "get", + "building:levels" + ], + 3 + ], + 3.5 + ], + 12 + ] + ], + "fill-extrusion-base": [ + "coalesce", + [ + "to-number", + [ + "get", + "min_height" + ], + null + ], + 0 + ], + "fill-extrusion-opacity": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 14, + 0.6, + 16, + 0.88 + ], + "fill-extrusion-vertical-gradient": true + } + }, + { + "id": "railway-label", + "type": "symbol", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "railway", + "rail", + "subway", + "light_rail", + "tram" + ], + "minzoom": 13, + "layout": { + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 10, + "symbol-placement": "line", + "text-padding": 6, + "text-allow-overlap": false + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "railway" + ], + "subway", + "#CC2233", + "light_rail", + "#0055BB", + "tram", + "#7722AA", + "#4A5568" + ], + "text-halo-color": "rgba(255,255,255,0.9)", + "text-halo-width": 2 + } + }, + { + "id": "waterway-label", + "type": "symbol", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "all", + [ + "in", + "waterway", + "river", + "canal" + ], + [ + "!=", + "intermittent", + "yes" + ], + [ + "has", + "name" + ] + ], + "minzoom": 12, + "layout": { + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 11, + "symbol-placement": "line", + "text-letter-spacing": 0.1 + }, + "paint": { + "text-color": "#2E86AB", + "text-halo-color": "rgba(255,255,255,0.85)", + "text-halo-width": 2 + } + }, + { + "id": "building-number-polygon", + "type": "symbol", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "minzoom": 17, + "filter": [ + "has", + "addr:housenumber" + ], + "layout": { + "text-field": "{addr:housenumber}", + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 10, + "text-allow-overlap": false, + "text-ignore-placement": false + }, + "paint": { + "text-color": "#5A5048", + "text-halo-color": "rgba(255,255,255,0.95)", + "text-halo-width": 1.5 + } + }, + { + "id": "building-number-point", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 17, + "filter": [ + "has", + "addr:housenumber" + ], + "layout": { + "text-field": "{addr:housenumber}", + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 10, + "text-allow-overlap": false + }, + "paint": { + "text-color": "#5A5048", + "text-halo-color": "rgba(255,255,255,0.95)", + "text-halo-width": 1.5 + } + }, + { + "id": "road-labels-minor", + "type": "symbol", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "residential", + "service", + "unclassified", + "living_street" + ], + "minzoom": 16, + "layout": { + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 11, + "symbol-placement": "line", + "text-letter-spacing": 0.04, + "text-padding": 4, + "text-allow-overlap": false + }, + "paint": { + "text-color": "#4A5568", + "text-halo-color": "rgba(255,255,255,0.85)", + "text-halo-width": 1.5 + } + }, + { + "id": "road-labels-major", + "type": "symbol", + "source": "local-osm-lines", + "source-layer": "planet_osm_line", + "filter": [ + "in", + "highway", + "primary", + "secondary", + "tertiary", + "motorway", + "trunk" + ], + "minzoom": 13, + "layout": { + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 13, + 11, + 16, + 14 + ], + "symbol-placement": "line", + "text-letter-spacing": 0.05, + "text-padding": 5, + "text-allow-overlap": false + }, + "paint": { + "text-color": "#2D3748", + "text-halo-color": "rgba(255,255,255,0.9)", + "text-halo-width": 2 + } + }, + { + "id": "poi-hospital", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 13, + "filter": [ + "==", + "amenity", + "hospital" + ], + "layout": { + "icon-image": "hospital", + "icon-size": 1, + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 11, + "text-offset": [ + 0, + 1.2 + ], + "text-anchor": "top", + "text-allow-overlap": false + }, + "paint": { + "text-color": "#C0392B", + "text-halo-color": "white", + "text-halo-width": 2 + } + }, + { + "id": "poi-pharmacy", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 15, + "filter": [ + "==", + "amenity", + "pharmacy" + ], + "layout": { + "icon-image": "pharmacy", + "icon-size": 0.8, + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 10, + "text-offset": [ + 0, + 1.2 + ], + "text-anchor": "top" + }, + "paint": { + "text-color": "#1A7A3C", + "text-halo-color": "white", + "text-halo-width": 1.5 + } + }, + { + "id": "poi-place-of-worship", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 14, + "filter": [ + "==", + "amenity", + "place_of_worship" + ], + "layout": { + "icon-image": "tourist", + "icon-size": 0.8, + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 11, + "text-offset": [ + 0, + 1.2 + ], + "text-anchor": "top" + }, + "paint": { + "text-color": "#1A6B3A", + "text-halo-color": "white", + "text-halo-width": 2 + } + }, + { + "id": "poi-restaurant-cafe", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 16, + "filter": [ + "in", + "amenity", + "restaurant", + "cafe", + "fast_food" + ], + "layout": { + "icon-image": [ + "match", + [ + "get", + "amenity" + ], + "cafe", + "cafe", + "restaurant" + ], + "icon-size": 0.8, + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 10, + "text-offset": [ + 0, + 1.2 + ], + "text-anchor": "top" + }, + "paint": { + "text-color": "#3D4A5C", + "text-halo-color": "white", + "text-halo-width": 1.5 + } + }, + { + "id": "poi-school", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 14, + "filter": [ + "in", + "amenity", + "school", + "university", + "college" + ], + "layout": { + "icon-image": "college", + "icon-size": 0.8, + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 11, + "text-offset": [ + 0, + 1.2 + ], + "text-anchor": "top" + }, + "paint": { + "text-color": "#5A4A8A", + "text-halo-color": "white", + "text-halo-width": 2 + } + }, + { + "id": "poi-transit-station", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 12, + "filter": [ + "any", + [ + "==", + "railway", + "station" + ], + [ + "==", + "railway", + "halt" + ], + [ + "==", + "railway", + "tram_stop" + ], + [ + "==", + "station", + "subway" + ], + [ + "==", + "amenity", + "bus_station" + ] + ], + "layout": { + "icon-image": "rail", + "icon-size": 1, + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": 11, + "text-offset": [ + 0, + 1.4 + ], + "text-anchor": "top", + "text-allow-overlap": false + }, + "paint": { + "text-color": "#CC2233", + "text-halo-color": "rgba(255,255,255,0.95)", + "text-halo-width": 2 + } + }, + { + "id": "place-labels-area", + "type": "symbol", + "source": "local-osm-polygons", + "source-layer": "planet_osm_polygon", + "minzoom": 10, + "filter": [ + "has", + "name" + ], + "layout": { + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + 10, + 14, + 13 + ], + "text-padding": 8, + "text-allow-overlap": false, + "text-ignore-placement": false + }, + "paint": { + "text-color": "#34495E", + "text-halo-color": "rgba(255,255,255,0.85)", + "text-halo-width": 2 + } + }, + { + "id": "place-labels-point", + "type": "symbol", + "source": "local-osm-points", + "source-layer": "planet_osm_point", + "minzoom": 10, + "filter": [ + "any", + [ + "in", + "place", + "city", + "town", + "village", + "suburb", + "neighbourhood", + "hamlet", + "locality", + "quarter" + ], + [ + "in", + "natural", + "peak", + "spring" + ] + ], + "layout": { + "text-field": [ + "coalesce", + [ + "get", + "name:ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Regular" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 10, + [ + "match", + [ + "get", + "place" + ], + "city", + 16, + "town", + 14, + 11 + ], + 14, + [ + "match", + [ + "get", + "place" + ], + "city", + 20, + "town", + 16, + 13 + ], + 17, + 14 + ], + "text-letter-spacing": [ + "match", + [ + "get", + "place" + ], + "city", + 0.08, + "town", + 0.05, + 0.02 + ], + "text-anchor": "center", + "text-padding": 10, + "text-allow-overlap": false + }, + "paint": { + "text-color": [ + "match", + [ + "get", + "place" + ], + "city", + "#1A2740", + "town", + "#2C3E50", + "village", + "#3D4F62", + "suburb", + "#4A5568", + "neighbourhood", + "#556677", + "#607080" + ], + "text-halo-color": "rgba(255,255,255,0.92)", + "text-halo-width": [ + "match", + [ + "get", + "place" + ], + "city", + 3, + "town", + 2.5, + 2 + ] + } + }, + { + "id": "places-egypt-labels", + "type": "symbol", + "source": "places_egypt", + "source-layer": "places_egypt", + "minzoom": 12, + "layout": { + "text-field": [ + "coalesce", + [ + "get", + "name_ar" + ], + [ + "get", + "name" + ], + "" + ], + "text-font": [ + "Noto Sans Bold" + ], + "text-size": [ + "interpolate", + [ + "linear" + ], + [ + "zoom" + ], + 12, + 9, + 16, + 13 + ], + "text-offset": [ + 0, + 1.5 + ], + "text-anchor": "top", + "text-padding": 8, + "text-allow-overlap": false + }, + "paint": { + "text-color": "#2D3748", + "text-halo-color": "rgba(255, 255, 255, 0.9)", + "text-halo-width": 2 + } + } + ] +} \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 025a10b..5063dee 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -84,12 +84,6 @@ PODS: - geolocator_apple (1.2.0): - Flutter - FlutterMacOS - - Google-Maps-iOS-Utils (6.1.3): - - GoogleMaps (~> 10.0) - - google_maps_flutter_ios (0.0.1): - - Flutter - - Google-Maps-iOS-Utils (< 7.0, >= 5.0) - - GoogleMaps (< 11.0, >= 8.4) - google_sign_in_ios (0.0.1): - Flutter - FlutterMacOS @@ -98,9 +92,6 @@ PODS: - GoogleDataTransport (10.1.0): - nanopb (~> 3.30910.0) - PromisesObjC (~> 2.4) - - GoogleMaps (10.8.0): - - GoogleMaps/Maps (= 10.8.0) - - GoogleMaps/Maps (10.8.0) - GoogleSignIn (9.1.0): - AppAuth (~> 2.0) - AppCheckCore (~> 11.0) @@ -157,6 +148,10 @@ PODS: - FlutterMacOS - location (0.0.1): - Flutter + - MapLibre (6.19.1) + - maplibre_gl (0.25.0): + - Flutter + - MapLibre (= 6.19.1) - nanopb (3.30910.0): - nanopb/decode (= 3.30910.0) - nanopb/encode (= 3.30910.0) @@ -268,7 +263,6 @@ DEPENDENCIES: - flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`) - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) - geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`) - - google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`) - google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`) - image_cropper (from `.symlinks/plugins/image_cropper/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) @@ -277,6 +271,7 @@ DEPENDENCIES: - live_activities (from `.symlinks/plugins/live_activities/ios`) - local_auth_darwin (from `.symlinks/plugins/local_auth_darwin/darwin`) - location (from `.symlinks/plugins/location/ios`) + - maplibre_gl (from `.symlinks/plugins/maplibre_gl/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - quick_actions_ios (from `.symlinks/plugins/quick_actions_ios/ios`) @@ -304,14 +299,13 @@ SPEC REPOS: - FirebaseCoreInternal - FirebaseInstallations - FirebaseMessaging - - Google-Maps-iOS-Utils - GoogleDataTransport - - GoogleMaps - GoogleSignIn - GoogleUtilities - GTMAppAuth - GTMSessionFetcher - IOSSecuritySuite + - MapLibre - nanopb - PromisesObjC - RecaptchaInterop @@ -355,8 +349,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_tts/ios" geolocator_apple: :path: ".symlinks/plugins/geolocator_apple/darwin" - google_maps_flutter_ios: - :path: ".symlinks/plugins/google_maps_flutter_ios/ios" google_sign_in_ios: :path: ".symlinks/plugins/google_sign_in_ios/darwin" image_cropper: @@ -373,6 +365,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/local_auth_darwin/darwin" location: :path: ".symlinks/plugins/location/ios" + maplibre_gl: + :path: ".symlinks/plugins/maplibre_gl/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" permission_handler_apple: @@ -426,11 +420,8 @@ SPEC CHECKSUMS: flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23 flutter_tts: 35ac3c7d42412733e795ea96ad2d7e05d0a75113 geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e - Google-Maps-iOS-Utils: bed22fa703c919259b3901449434d60d994fae20 - google_maps_flutter_ios: 0cf046caf50b00d95071f79e8031fcd5ef902beb google_sign_in_ios: 000870aa06da9b28d1d0bf7ef70ff0213059dd28 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 - GoogleMaps: fe4035acb768ed14ce732811363f232550ba55af GoogleSignIn: fcee2257188d5eda57a5e2b6a715550ffff9206d GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GTMAppAuth: 217a876b249c3c585a54fd6f73e6b58c4f5c4238 @@ -443,6 +434,8 @@ SPEC CHECKSUMS: live_activities: 4dfa736d0736e1c77866a2f9c056a76513cc9e7b local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb location: 155caecf9da4f280ab5fe4a55f94ceccfab838f8 + MapLibre: 7f24faba45439f80ccb0f83393c29fa32cb81952 + maplibre_gl: a2114567cbd1065866614fbd34dfb75ab782aaa2 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 6efba93..8856d00 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 70; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -121,7 +121,7 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - C663DBEB2F50907200D79908 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + C663DBEB2F50907200D79908 /* Exceptions for "RideWidget" folder in "RideWidgetExtension" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( Info.plist, @@ -131,7 +131,18 @@ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ - C663DBD82F50907000D79908 /* RideWidget */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (C663DBEB2F50907200D79908 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = RideWidget; sourceTree = ""; }; + C663DBD82F50907000D79908 /* RideWidget */ = { + isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + C663DBEB2F50907200D79908 /* Exceptions for "RideWidget" folder in "RideWidgetExtension" target */, + ); + explicitFileTypes = { + }; + explicitFolders = ( + ); + path = RideWidget; + sourceTree = ""; + }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -295,6 +306,7 @@ C663DBE72F50907200D79908 /* Embed Foundation Extensions */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 9DE0D475D98797EEBEE003BD /* [CP] Copy Pods Resources */, + B77A6F719CDC97DC7270EA70 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -469,19 +481,32 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; showEnvVarsInLog = 0; }; + B77A6F719CDC97DC7270EA70 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; C6C3FB403E5DB104310DE9A1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 158c3db..74b5428 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -1,7 +1,6 @@ import UIKit import Flutter import FirebaseCore -import GoogleMaps @main @objc class AppDelegate: FlutterAppDelegate { @@ -11,11 +10,7 @@ import GoogleMaps didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { - // --- 1. تهيئة خرائط جوجل --- - // يتأكد من وجود ملف Config.plist ويقرأ المفتاح منه - if let config = loadConfig(), let apiKey = config["APIKey"] as? String { - GMSServices.provideAPIKey(apiKey) - } + // --- 2. تهيئة Firebase --- FirebaseApp.configure() @@ -87,13 +82,7 @@ import GoogleMaps } } - func loadConfig() -> [String: Any]? { - guard let path = Bundle.main.path(forResource: "Config", ofType: "plist"), - let config = NSDictionary(contentsOfFile: path) as? [String: Any] else { - fatalError("Couldn't find Config.plist file. Please add it to your project.") - } - return config - } + } // --- الامتدادات (Extensions) من الكود القديم --- diff --git a/lib/constant/country_polygons.dart b/lib/constant/country_polygons.dart index be919af..fa17cf2 100644 --- a/lib/constant/country_polygons.dart +++ b/lib/constant/country_polygons.dart @@ -1,6 +1,6 @@ // في ملف: constant/country_polygons.dart -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; class CountryPolygons { // ========================================================== diff --git a/lib/constant/links.dart b/lib/constant/links.dart index 3ecb583..9b31c27 100644 --- a/lib/constant/links.dart +++ b/lib/constant/links.dart @@ -11,7 +11,7 @@ class AppLink { /// هذا الرابط خاص برحلات الركاب، ويستخدمه السيرفر الجانبي للرحلات (Ride Server Side) للتعامل مع عمليات إلغاء الرحلات وتحديث حالة الرحلات وغيرها من العمليات المتعلقة بالرحلات. /// https://routesy.intaleq.xyz for syria /// for jordan https://routesjo.intaleq.xyz - static String routesOsm = 'https://routesy.intaleq.xyz'; + static String routesOsm = 'https://routesjo.intaleq.xyz'; ///https://location.intaleq.xyz/intaleq/ride/location ///locationServerSide هو السيرفر الجانبي الخاص بموقع السائقين، حيث يتم إرسال تحديثات الموقع من التطبيق إلى هذا السيرفر، ومن ثم يقوم هذا السيرفر بتوزيع هذه التحديثات إلى الركاب المتصلين الذين يتابعون السائق في الوقت الحقيقي. @@ -42,7 +42,7 @@ class AppLink { static String test = "$server/test.php"; //===============firebase========================== - static String getTokens = "$server/ride/firebase/getTokensPassenger.php.php"; + static String getTokens = "$server/ride/firebase/getTokensPassenger.php"; static String getTokenParent = "$server/ride/firebase/getTokenParent.php"; static String addTokens = "$server/ride/firebase/add.php"; static String addFingerPrint = "$paymentServer/ride/firebase/add.php"; diff --git a/lib/constant/univeries_polygon.dart b/lib/constant/univeries_polygon.dart index 8358b9f..e1ab94c 100644 --- a/lib/constant/univeries_polygon.dart +++ b/lib/constant/univeries_polygon.dart @@ -1,4 +1,4 @@ -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; class UniversitiesPolygons { // AUC polygon points diff --git a/lib/controller/functions/location_controller.dart b/lib/controller/functions/location_controller.dart index d559fd0..641083a 100644 --- a/lib/controller/functions/location_controller.dart +++ b/lib/controller/functions/location_controller.dart @@ -1,7 +1,6 @@ // import 'dart:async'; // import 'package:get/get.dart'; -// import 'package:google_maps_flutter/google_maps_flutter.dart'; // import 'package:location/location.dart'; // import 'package:Intaleq/constant/box_name.dart'; // import 'package:Intaleq/constant/links.dart'; diff --git a/lib/controller/home/decode_polyline_isolate.dart b/lib/controller/home/decode_polyline_isolate.dart index 8abad06..41bc638 100644 --- a/lib/controller/home/decode_polyline_isolate.dart +++ b/lib/controller/home/decode_polyline_isolate.dart @@ -1,4 +1,4 @@ -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; List decodePolylineIsolate(String encoded) { List points = []; diff --git a/lib/controller/home/map_passenger_controller.dart b/lib/controller/home/map_passenger_controller.dart index 98d37e6..a4eab5e 100644 --- a/lib/controller/home/map_passenger_controller.dart +++ b/lib/controller/home/map_passenger_controller.dart @@ -11,6 +11,7 @@ import 'package:Intaleq/views/Rate/rate_captain.dart'; import 'package:Intaleq/views/Rate/rating_driver_bottom.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:Intaleq/constant/univeries_polygon.dart'; @@ -26,7 +27,7 @@ import 'package:Intaleq/views/widgets/my_textField.dart'; import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; // import 'package:google_polyline_algorithm/google_polyline_algorithm.dart'; import 'package:intl/intl.dart'; import 'package:location/location.dart'; @@ -121,8 +122,12 @@ class MapPassengerController extends GetxController { formSearchPlaces(3), ]; LatLngBounds? boundsdata; - List markers = []; - List polyLines = []; + List markers = []; + List polyLines = []; + List polyLinesLight = []; + Map _activeSymbols = {}; + Map _activeLines = {}; + Map _activeFills = {}; late LatLng passengerLocation = const LatLng(32, 34); late LatLng newMyLocation = const LatLng(32.115295, 36.064773); late LatLng newStartPointLocation = const LatLng(32.115295, 36.064773); @@ -141,13 +146,13 @@ class MapPassengerController extends GetxController { List> polylineCoordinatesPointsAll = []; List carsLocationByPassenger = []; List driverCarsLocationToPassengerAfterApplied = []; - BitmapDescriptor markerIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor tripIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor startIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor endIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor motoIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor ladyIcon = BitmapDescriptor.defaultMarker; + String markerIcon = "marker_icon"; + String tripIcon = "trip_icon"; + String startIcon = "start_icon"; + String endIcon = "end_icon"; + String carIcon = "car_icon"; + String motoIcon = "moto_icon"; + String ladyIcon = "lady_icon"; double height = 150; DateTime currentTime = DateTime.now(); final location = Location(); @@ -630,20 +635,16 @@ class MapPassengerController extends GetxController { // حفظ نسخة للمقارنة _currentDriverRoutePoints = decodedPoints; // إزالة خط مسار السائق القديم فقط - polyLines - .removeWhere((p) => p.polylineId.value == 'driver_track_line'); + polyLines = polyLines.where((p) => p.lineOpacity != 0.999).toList(); // إضافة الخط الجديد (بستايل مميز للسائق) - polyLines.add(Polyline( - polylineId: const PolylineId('driver_track_line'), - points: decodedPoints, - color: Colors.black87, // لون مختلف عن مسار الرحلة الأساسي - width: 5, - jointType: JointType.round, - startCap: Cap.roundCap, - endCap: Cap.roundCap, - patterns: [PatternItem.dash(10), PatternItem.gap(10)], // خط منقط + polyLines.add(LineOptions( + geometry: decodedPoints, + lineColor: '#333333', // لون مختلف عن مسار الرحلة الأساسي + lineWidth: 5, + lineOpacity: 0.999, // acting as ID )); + refreshMapElements(); } // 4. ضبط الكاميرا لتشمل السائق والراكب @@ -1108,27 +1109,29 @@ class MapPassengerController extends GetxController { // دالة مساعدة لتحديث ماركر السائق void _updateDriverMarker(LatLng position, double heading) { - final markerId = MarkerId('driver_location'); + // In MapLibre, we'll manage this via the markers list and refresh + // For specific high-frequency updates, we could use updateSymbol, + // but for now, we'll stick to the list-based approach for consistency. - int existingIndex = markers.indexWhere((m) => m.markerId == markerId); + int existingIndex = + markers.indexWhere((m) => m.textField == 'driver_location'); - BitmapDescriptor icon = carIcon; // أو حسب نوع السيارة + final options = SymbolOptions( + geometry: position, + iconImage: carIcon, + iconRotate: heading, + textField: 'driver_location', // Use textField as a temporary ID if needed + textOpacity: 0, // Hide the ID text + ); if (existingIndex != -1) { - markers[existingIndex] = markers[existingIndex].copyWith( - positionParam: position, - rotationParam: heading, - ); + markers[existingIndex] = options; } else { - markers.add(Marker( - markerId: markerId, - position: position, - rotation: heading, - icon: icon, - anchor: const Offset(0.5, 0.5), - infoWindow: InfoWindow(title: passengerName), - )); + markers.add(options); } + + refreshMapElements(); // Sync to map + update(); } // === إضافة متغير للتحكم === @@ -1219,12 +1222,12 @@ class MapPassengerController extends GetxController { polylineCoordinates.addAll(points); polyLines.clear(); - polyLines.add(Polyline( - polylineId: PolylineId('restored_trip'), - points: polylineCoordinates, - width: 10, - color: Colors.blue, + polyLines.add(LineOptions( + geometry: polylineCoordinates, + lineWidth: 6, + lineColor: '#2196F3', )); + refreshMapElements(); update(); } catch (e) { @@ -2866,14 +2869,14 @@ class MapPassengerController extends GetxController { for (int i = 0; i < decodedPoints.length; i++) { polylineCoordinates.add(decodedPoints[i]); } - var polyline = Polyline( - polylineId: const PolylineId('begin trip'), - points: polylineCoordinates, - width: 10, - color: Colors.blue, + var polyline = LineOptions( + geometry: polylineCoordinates, + lineWidth: 6, + lineColor: '#2196F3', ); polyLines.add(polyline); + refreshMapElements(); timeToPassengerFromDriverAfterApplied = 0; remainingTime = 0; remainingTimeToPassengerFromDriverAfterApplied = 0; @@ -3472,23 +3475,16 @@ class MapPassengerController extends GetxController { await compute(decodePolylineIsolate, pointsString); // إزالة خط مسار السائق القديم فقط - polyLines - .removeWhere((p) => p.polylineId.value == 'driver_track_line'); + polyLines = polyLines.where((p) => p.lineOpacity != 0.999).toList(); // إضافة الخط الجديد - polyLines.add(Polyline( - polylineId: const PolylineId('driver_track_line'), - points: decodedPoints, - color: Colors.black87, // لون مميز لمسار السائق - width: 5, - jointType: JointType.round, - startCap: Cap.roundCap, - endCap: Cap.roundCap, - patterns: [ - PatternItem.dash(10), - PatternItem.gap(10) - ], // جعله منقطاً + polyLines.add(LineOptions( + geometry: decodedPoints, + lineColor: '#333333', // لون مميز لمسار السائق + lineWidth: 5, + lineOpacity: 0.999, // acting as ID )); + refreshMapElements(); // لا تستدعي update هنا، سيتم استدعاؤها في الدالة الأب (getDriverCars...) لتقليل عدد التحديثات } @@ -3545,7 +3541,10 @@ class MapPassengerController extends GetxController { southwest: LatLng(minLat, minLng), northeast: LatLng(maxLat, maxLng), ), - padding, + left: padding, + top: padding, + right: padding, + bottom: padding, ), ); } catch (e) { @@ -4021,7 +4020,7 @@ class MapPassengerController extends GetxController { if (lat == 0.0 || lng == 0.0) continue; _updateOrCreateMarker( - MarkerId(carData['id'].toString()).toString(), + carData['id'].toString(), LatLng(lat, lng), heading, // الدالة هذه تقرر شكل الأيقونة بناءً على نوع السيارة القادم من السيرفر @@ -4068,7 +4067,7 @@ class MapPassengerController extends GetxController { for (var carData in fakeCarData) { _updateOrCreateMarker( - MarkerId(carData['id']).toString(), + carData['id'].toString(), LatLng(carData['latitude'], carData['longitude']), carData['heading'], _getIconForCar(carData), @@ -4076,7 +4075,7 @@ class MapPassengerController extends GetxController { } } - BitmapDescriptor _getIconForCar(Map carData) { + String _getIconForCar(Map carData) { if (carData['model'].toString().contains('دراجة')) { return motoIcon; } else if (carData['gender'] == 'Female') { @@ -4086,23 +4085,22 @@ class MapPassengerController extends GetxController { } } - void _updateOrCreateMarker(String markerId, LatLng newPosition, - double newHeading, BitmapDescriptor icon) { - Marker? existingMarker = markers.cast().firstWhere( - (m) => m?.markerId == MarkerId(markerId), - orElse: () => null, - ); + void _updateOrCreateMarker( + String markerId, LatLng newPosition, double newHeading, String icon) { + int existingIndex = markers.indexWhere((m) => m.textField == markerId); - if (existingMarker == null) { - markers.add(Marker( - markerId: MarkerId(markerId), - position: newPosition, - rotation: newHeading, - icon: icon, + if (existingIndex == -1) { + markers.add(SymbolOptions( + geometry: newPosition, + iconRotate: newHeading, + iconImage: icon, + textField: markerId, + textOpacity: 0, )); } else { + final existingMarker = markers[existingIndex]; double distance = - _calculateDistance(existingMarker.position, newPosition); + _calculateDistance(existingMarker.geometry!, newPosition); if (distance >= minMovementThreshold) { _smoothlyUpdateMarker(existingMarker, newPosition, newHeading, icon); } @@ -4474,24 +4472,25 @@ Intaleq Team'''; print(passengerLocationStringUnvirsity); } - var polygons = {}.obs; + var polygons = [].obs; // Initialize polygons from UniversitiesPolygons void _initializePolygons() { List> universityPolygons = UniversitiesPolygons.universityPolygons; - List universityNames = UniversitiesPolygons.universityNames; for (int i = 0; i < universityPolygons.length; i++) { - Polygon polygon = Polygon( - polygonId: PolygonId(universityNames[i]), - points: universityPolygons[i], - strokeColor: Colors.blueAccent, - fillColor: Colors.blueAccent.withOpacity(0.2), - strokeWidth: 2, + FillOptions polygon = FillOptions( + geometry: [ + universityPolygons[i] + ], // MapLibre Fill expects List> + fillColor: '#448AFF', // blueAccent hex + fillOpacity: 0.2, + fillOutlineColor: '#448AFF', ); - polygons.add(polygon); // Add polygon to observable set + polygons.add(polygon); } + refreshMapElements(); } LatLng driverLocationToPassenger = const LatLng(32, 35); @@ -4597,7 +4596,7 @@ Intaleq Team'''; // 1.0; // Minimum movement in meters to trigger update void clearMarkersExceptStartEndAndDriver() { markers.removeWhere((marker) { - String id = marker.markerId.value; + String id = marker.textField ?? ''; // لا تحذف نقطة البداية if (id == 'start') return false; // لا تحذف نقطة النهاية @@ -4613,15 +4612,11 @@ Intaleq Team'''; } void clearMarkersExceptStartEnd() { - Set markersToRemove = markers - .where((marker) => - marker.markerId != const MarkerId("start") && - marker.markerId != const MarkerId("end")) - .toSet(); - - for (Marker marker in markersToRemove) { - markers.remove(marker); - } + markers.removeWhere((marker) { + String id = marker.textField ?? ''; + return id != 'start' && id != 'end'; + }); + refreshMapElements(); update(); } @@ -4646,7 +4641,7 @@ Intaleq Team'''; double.tryParse(driverData['heading'].toString()) ?? 0.0; // تحديد الأيقونة - BitmapDescriptor icon; + String icon; if (driverData['model'].toString().contains('دراجة') || driverData['make'].toString().contains('دراجة')) { icon = motoIcon; @@ -4656,43 +4651,44 @@ Intaleq Team'''; icon = carIcon; } - // 2. البحث عن الماركر القديم وتحديثه أو إنشاء جديد - final MarkerId markerId = MarkerId(currentDriverMarkerId); + // 2. البحث عن الماركر الجديد وتحديثه أو إنشاء جديد + final String markerId = currentDriverMarkerId; // التحقق هل الماركر موجود مسبقاً؟ - final int existingIndex = markers.indexWhere((m) => m.markerId == markerId); + final int existingIndex = + markers.indexWhere((m) => m.textField == markerId); if (existingIndex != -1) { // الماركر موجود، نقوم بتحريكه (Animation) - Marker oldMarker = markers[existingIndex]; + SymbolOptions oldMarker = markers[existingIndex]; _smoothlyUpdateMarker(oldMarker, newPosition, newHeading, icon); } else { // الماركر غير موجود، نقوم بإنشائه - markers.add(Marker( - markerId: markerId, - position: newPosition, - rotation: newHeading, - icon: icon, - anchor: const Offset(0.5, 0.5), // مهم لكي تدور السيارة حول مركزها - infoWindow: InfoWindow(title: driverName), + markers.add(SymbolOptions( + geometry: newPosition, + iconRotate: newHeading, + iconImage: icon, + textField: markerId, + textOpacity: 0, )); - update(); // تحديث الخريطة + refreshMapElements(); // تحديث الخريطة + update(); } } // التأكد من دالة التحريك السلس - void _smoothlyUpdateMarker(Marker oldMarker, LatLng newPosition, - double newHeading, BitmapDescriptor icon) { + void _smoothlyUpdateMarker(SymbolOptions oldMarker, LatLng newPosition, + double newHeading, String icon) { // إذا كانت المسافة صغيرة جداً لا داعي للتحريك (لتقليل الوميض) double distance = Geolocator.distanceBetween( - oldMarker.position.latitude, - oldMarker.position.longitude, + oldMarker.geometry!.latitude, + oldMarker.geometry!.longitude, newPosition.latitude, newPosition.longitude); if (distance < 2.0) return; - final String markerIdKey = oldMarker.markerId.value; + final String markerIdKey = oldMarker.textField!; // إلغاء أي أنيميشن سابق لنفس الماركر _animationTimers[markerIdKey]?.cancel(); @@ -4702,18 +4698,19 @@ Intaleq Team'''; const int stepDuration = 50; // سرعة التحديث بالميلي ثانية (المجموع 1 ثانية) double latStep = - (newPosition.latitude - oldMarker.position.latitude) / totalSteps; + (newPosition.latitude - oldMarker.geometry!.latitude) / totalSteps; double lngStep = - (newPosition.longitude - oldMarker.position.longitude) / totalSteps; - double headingStep = (newHeading - oldMarker.rotation) / totalSteps; + (newPosition.longitude - oldMarker.geometry!.longitude) / totalSteps; + double headingStep = + (newHeading - (oldMarker.iconRotate ?? 0.0)) / totalSteps; // معالجة مشكلة الدوران (مثلاً الانتقال من 350 درجة إلى 10 درجات) if (headingStep.abs() > 180) { // منطق لضبط الدوران في الاتجاه الأقرب (اختياري) } - LatLng currentPos = oldMarker.position; - double currentHeading = oldMarker.rotation; + LatLng currentPos = oldMarker.geometry!; + double currentHeading = oldMarker.iconRotate ?? 0.0; _animationTimers[markerIdKey] = Timer.periodic(const Duration(milliseconds: stepDuration), (timer) { @@ -4724,13 +4721,16 @@ Intaleq Team'''; currentHeading += headingStep; // تحديث القائمة - int index = markers.indexWhere((m) => m.markerId.value == markerIdKey); + int index = markers.indexWhere((m) => m.textField == markerIdKey); if (index != -1) { - markers[index] = oldMarker.copyWith( - positionParam: currentPos, - rotationParam: currentHeading, - iconParam: icon, // تحديث الأيقونة في حال تغيرت + markers[index] = SymbolOptions( + geometry: currentPos, + iconRotate: currentHeading, + iconImage: icon, + textField: markerIdKey, + textOpacity: 0, ); + refreshMapElements(); update(); // تحديث الواجهة في كل خطوة } @@ -4742,26 +4742,25 @@ Intaleq Team'''; } void _updateMarkerPosition( - LatLng newPosition, double newHeading, BitmapDescriptor icon) { + LatLng newPosition, double newHeading, String icon) { const String markerId = 'driverToPassengers'; - Marker? existingMarker = markers.cast().firstWhere( - (m) => m?.markerId == const MarkerId(markerId), - orElse: () => null, - ); - if (existingMarker == null) { - // If the marker doesn't exist, create it at the new position - markers.add(Marker( - markerId: const MarkerId(markerId), - position: newPosition, - rotation: newHeading, - icon: icon, + int existingIndex = markers.indexWhere((m) => m.textField == markerId); + + if (existingIndex == -1) { + markers.add(SymbolOptions( + geometry: newPosition, + iconRotate: newHeading, + iconImage: icon, + textField: markerId, + textOpacity: 0, )); + refreshMapElements(); update(); } else { - // If the marker exists, check if the movement is significant enough to update + final existingMarker = markers[existingIndex]; double distance = - _calculateDistance(existingMarker.position, newPosition); + _calculateDistance(existingMarker.geometry!, newPosition); if (distance >= minMovementThreshold) { _smoothlyUpdateMarker(existingMarker, newPosition, newHeading, icon); } @@ -5701,62 +5700,7 @@ Intaleq Team'''; }); } -// تهيئة polylines خفيفة (استدعها بعد جلب المسار) - Set polyLinesLight = {}; - List simplifyPolyline(List pts, double epsilonMeters) { - if (pts.length <= 2) return pts; - double _perpDist(LatLng p, LatLng a, LatLng b) { - // مسافة عمودية تقريبية بالأمتار - double _toRad(double d) => d * math.pi / 180.0; - // تحويل بسيط للمتر (تقريبي) - final x1 = a.longitude, y1 = a.latitude; - final x2 = b.longitude, y2 = b.latitude; - final x0 = p.longitude, y0 = p.latitude; - final num = ((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1).abs(); - final den = math.sqrt(math.pow(y2 - y1, 2) + math.pow(x2 - x1, 2)); - // تحويل درجات -> أمتار تقريبي (1 درجة ~ 111km) - final degDist = den == 0 ? 0 : num / den; - return degDist * 111000; // متر - } - - List dp(int start, int end) { - double maxDist = 0; - int index = start; - for (int i = start + 1; i < end; i++) { - final d = _perpDist(pts[i], pts[start], pts[end]); - if (d > maxDist) { - maxDist = d; - index = i; - } - } - if (maxDist > epsilonMeters) { - final r1 = dp(start, index); - final r2 = dp(index, end); - return [...r1.sublist(0, r1.length - 1), ...r2]; - } else { - return [pts[start], pts[end]]; - } - } - - return dp(0, pts.length - 1); - } - - void buildLightPolylines(List originalPoints) { - final simplified = simplifyPolyline(originalPoints, lowPerf ? 12 : 3); - polyLinesLight = { - Polyline( - polylineId: const PolylineId('route_light'), - points: simplified, - width: lowPerf ? 4 : 6, - geodesic: true, - color: AppColor.primaryColor, - endCap: Cap.roundCap, - startCap: Cap.roundCap, - jointType: JointType.round, - ), - }; - update(); - } +// Removed legacy light polylines since MapLibre vectors handle high-point geometries natively. Future savePlaceToServer( String latitude, String longitude, String name, String rate) async { @@ -5807,101 +5751,6 @@ Intaleq Team'''; update(); } - void addCustomPicker() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio - // scale: 1.0, - ); - BitmapDescriptor.asset( - config, - 'assets/images/picker.png', - // mipmaps: false, - ).then((value) { - markerIcon = value; - update(); - }); - } - - void addCustomStartIcon() async { -// Create the marker with the resized image - - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.asset( - config, - 'assets/images/A.png', - // mipmaps: false, - ).then((value) { - startIcon = value; - update(); - }); - } - - void addCustomEndIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.asset( - config, - 'assets/images/b.png', - // mipmaps: false, - ).then((value) { - endIcon = value; - update(); - }); - } - - void addCustomCarIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 35), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.asset( - config, - 'assets/images/car.png', - // mipmaps: false, - ).then((value) { - carIcon = value; - update(); - }); - } - - void addCustomMotoIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.asset( - config, - 'assets/images/moto1.png', - // mipmaps: false, - ).then((value) { - motoIcon = value; - update(); - }); - } - - void addCustomLadyIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.asset( - config, - 'assets/images/lady1.png', - // mipmaps: false, - ).then((value) { - ladyIcon = value; - update(); - }); - } - - void addCustomStepIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.asset( - config, - 'assets/images/brand.png', - // mipmaps: false, - ).then((value) { - tripIcon = value; - update(); - }); - } - dialoge() { Get.defaultDialog( title: 'Location '.tr, @@ -5969,6 +5818,8 @@ Intaleq Team'''; // Log.print('BoxName.serverChosen: ${box.read(BoxName.serverChosen)}'); newStartPointLocation = passengerLocation; + newMyLocation = + passengerLocation; // 🔥 Ensure map center starts at user location // Log.print('passengerLocation: $passengerLocation'); speed = _locationData.speed!; // //print location details @@ -6010,20 +5861,84 @@ Intaleq Team'''; ); } - GoogleMapController? mapController; - void onMapCreated(GoogleMapController controller) { - // myLocation = Get.find().location as LatLng; - // myLocation = myLocation; + MapLibreMapController? mapController; + bool isStyleLoaded = false; + + void onMapCreated(MapLibreMapController controller) { mapController = controller; - controller.getVisibleRegion(); - controller.animateCamera( + update(); + } + + void onStyleLoaded() async { + Log.print('🗺️ MapLibre Style Loaded. Syncing markers and layers...'); + isStyleLoaded = true; + await _loadMapIcons(); + await refreshMapElements(); + + // Initial camera set + mapController?.animateCamera( CameraUpdate.newLatLng(passengerLocation), ); - // Future.delayed(const Duration(milliseconds: 500), () { - // markers.forEach((marker) { - // controller.showMarkerInfoWindow(marker.markerId); - // }); - // }); + update(); + } + + Future _loadMapIcons() async { + await _addMapImage(startIcon, 'assets/images/A.png'); + await _addMapImage(endIcon, 'assets/images/b.png'); + await _addMapImage(carIcon, 'assets/images/car.png'); + await _addMapImage(motoIcon, 'assets/images/moto.png'); + await _addMapImage(ladyIcon, 'assets/images/lady.png'); + await _addMapImage('picker_icon', 'assets/images/picker.png'); + } + + Future _addMapImage(String id, String path) async { + try { + final ByteData bytes = await rootBundle.load(path); + await mapController?.addImage(id, bytes.buffer.asUint8List()); + } catch (e) { + Log.print('Error loading map icon $id: $e'); + } + } + + Future refreshMapElements() async { + if (mapController == null || !isStyleLoaded) return; + + await mapController!.clearSymbols(); + await mapController!.clearLines(); + await mapController!.clearFills(); + + _activeSymbols.clear(); + _activeLines.clear(); + _activeFills.clear(); + + for (var options in markers) { + await mapController!.addSymbol(options); + } + for (var options in polyLines) { + await mapController!.addLine(options); + } + for (var options in polygons) { + await mapController!.addFill(options); + } + } + + void updateCurrentLocationFromCamera(LatLng target) { + newMyLocation = target; + + if (startLocationFromMap == true) { + newStartPointLocation = target; + } else if (passengerStartLocationFromMap == true) { + newStartPointLocation = target; + } + + int waypointsLength = Get.find().wayPoints.length; + if (waypointsLength > 0 && + wayPointIndex >= 0 && + wayPointIndex < placesCoordinate.length) { + placesCoordinate[wayPointIndex] = + '${target.latitude},${target.longitude}'; + } + update(); } @@ -6650,43 +6565,37 @@ Intaleq Team'''; minutes = (durationToAdd.inMinutes % 60).round(); markers.clear(); - markers.add(Marker( - markerId: const MarkerId('start'), - position: startLoc, - icon: startIcon, - infoWindow: InfoWindow(title: startNameAddress), + markers.add(SymbolOptions( + geometry: startLoc, + iconImage: startIcon, + textField: 'start_point', + textOpacity: 0, )); - markers.add(Marker( - markerId: const MarkerId('end'), - position: endLoc, - icon: endIcon, - infoWindow: InfoWindow( - title: endNameAddress, - snippet: - '$distance ${'KM'.tr} ⌛ ${hours > 0 ? '$hours H $minutes m' : '$minutes m'}'), + markers.add(SymbolOptions( + geometry: endLoc, + iconImage: endIcon, + textField: 'end_point', + textOpacity: 0, + // snippet and distance text can be handled via symbols or separate UI )); - // 6b. Add waypoint markers (amber for stop 1, deep purple for stop 2) + // 6b. Add waypoint markers for (int i = 0; i < activeMenuWaypointCount; i++) { final wp = menuWaypoints[i]; if (wp != null) { - markers.add(Marker( - markerId: MarkerId('waypoint_$i'), - position: wp, - icon: BitmapDescriptor.defaultMarkerWithHue( - i == 0 - ? BitmapDescriptor.hueOrange - : BitmapDescriptor.hueViolet, - ), - infoWindow: InfoWindow( - title: '${'Stop'.tr} ${i + 1}', - snippet: menuWaypointNames[i]), + markers.add(SymbolOptions( + geometry: wp, + iconImage: i == 0 + ? 'orange_marker' + : 'violet_marker', // placeholders or specific icons + textField: 'waypoint_$i', + textOpacity: 0, )); } } - // 7. رسم الخط (النظام الجديد لجميع الأجهزة) + // 7. رسم الخط if (polyLines.isNotEmpty) clearPolyline(); rideConfirm = false; @@ -6736,26 +6645,27 @@ Intaleq Team'''; Color darkColor = Colors.grey.shade700; for (int i = 0; i < 4; i++) { - polyLines.removeWhere((p) => p.polylineId.value.startsWith('route_')); - polyLines.add(Polyline( - polylineId: const PolylineId('route_solid'), - points: coords, - width: 5, - color: i.isEven ? lightColor : darkColor, - endCap: Cap.roundCap, - startCap: Cap.roundCap, - jointType: JointType.round, - zIndex: 1, + polyLines = polyLines + .where((p) => p.lineOpacity != 0.99) + .toList(); // Simple filter for non-animated + + polyLines.add(LineOptions( + geometry: coords, + lineColor: i.isEven ? '#BDBDBD' : '#616161', + lineWidth: 5, + lineOpacity: 0.99, // tag for removal )); + + refreshMapElements(); update(); await Future.delayed(const Duration(milliseconds: 250)); } - // After animation: draw coloured segments if we have waypoints - polyLines.removeWhere((p) => p.polylineId.value.startsWith('route_')); + // After animation: draw coloured segments + polyLines = polyLines.where((p) => p.lineOpacity != 0.99).toList(); if (activeMenuWaypointCount > 0) { - // Find split indices: closest polyline point to each active waypoint + // ... split indices logic remains valid as it is math-based ... List splitIndices = []; for (int w = 0; w < activeMenuWaypointCount; w++) { final wp = menuWaypoints[w]; @@ -6775,48 +6685,41 @@ Intaleq Team'''; } splitIndices.sort(); - // Build segments: [0..split0], [split0..split1], ..., [splitN..end] List boundaries = [0, ...splitIndices, coords.length - 1]; for (int s = 0; s < boundaries.length - 1; s++) { int from = boundaries[s]; - int to = boundaries[s + 1] + 1; // inclusive end + int to = boundaries[s + 1] + 1; if (to > coords.length) to = coords.length; - if (from >= to - 1) continue; // skip empty + if (from >= to - 1) continue; final segCoords = coords.sublist(from, to); if (segCoords.length < 2) continue; final color = segmentColors[s % segmentColors.length]; - polyLines.add(Polyline( - polylineId: PolylineId('route_seg_$s'), - points: segCoords, - width: 6, - color: color, - endCap: Cap.roundCap, - startCap: Cap.roundCap, - jointType: JointType.round, - zIndex: 3 + s, + + polyLines.add(LineOptions( + geometry: segCoords, + lineColor: '#${color.value.toRadixString(16).substring(2)}', + lineWidth: 6, )); } } else { - // Single leg: solid primary color - polyLines.add(Polyline( - polylineId: const PolylineId('route_solid'), - points: coords, - width: 6, - color: AppColor.primaryColor, - endCap: Cap.roundCap, - startCap: Cap.roundCap, - jointType: JointType.round, - zIndex: 3, + polyLines.add(LineOptions( + geometry: coords, + lineColor: + '#${AppColor.primaryColor.value.toRadixString(16).substring(2)}', + lineWidth: 6, )); } + + refreshMapElements(); + update(); update(); // Fit camera to full route bounds AFTER polylines are drawn if (bounds != null) { await Future.delayed(const Duration(milliseconds: 500)); try { - mapController - ?.animateCamera(CameraUpdate.newLatLngBounds(bounds, 100)); + mapController?.animateCamera(CameraUpdate.newLatLngBounds(bounds, + left: 100, top: 100, right: 100, bottom: 100)); } catch (_) {} } } @@ -6895,280 +6798,7 @@ Intaleq Team'''; ); } - /// دالة لتقسيم المسار الطويل إلى قطع صغيرة ملونة بتدرج - Set _createGradientPolylines( - List points, Color startColor, Color endColor) { - Set lines = {}; - - // إذا كانت النقاط قليلة جداً، نرسم خطاً عادياً - if (points.length < 2) return lines; - - for (int i = 0; i < points.length - 1; i++) { - // حساب نسبة التقدم في المسار (من 0.0 إلى 1.0) - double t = i / points.length; - - // دمج اللونين بناءً على النسبة للحصول على اللون الحالي - // هذا يخلق التدرج من البداية للنهاية - Color segmentColor = Color.lerp(startColor, endColor, t) ?? startColor; - - lines.add(Polyline( - polylineId: PolylineId('route_segment_$i'), - points: [points[i], points[i + 1]], // وصل النقطة الحالية بالتالية فقط - width: 6, // سماكة الخط (اجعله سميكاً قليلاً ليظهر التدرج) - color: segmentColor, - startCap: Cap.roundCap, - endCap: Cap.roundCap, - jointType: JointType.round, - zIndex: 2, // لضمان ظهوره فوق أي طبقات أخرى - )); - } - - // (اختياري) إضافة "وهج" أو Glow أسفل الخط الرئيسي - // يتم ذلك برسم خط واحد شفاف وعريض أسفل الخطوط الملونة - lines.add(Polyline( - polylineId: const PolylineId('route_glow'), - points: points, - width: 10, // أعرض من الخط الرئيسي - color: startColor.withOpacity(0.3), // لون شفاف - zIndex: 1, // أسفل الخط الملون - )); - - return lines; - } -// getDirectionMap(String origin, destination, -// [List waypoints = const []]) async { -// isLoading = true; -// update(); -// remainingTime = 25; //to make cancel every call -// // startCarLocationSearch(box.read(BoxName.carType)); -// await getCarsLocationByPassengerAndReloadMarker( -// box.read(BoxName.carType), 5000); -// // await getCarsLocationByPassengerAndReloadMarker(); -// var coordDestination = destination.split(','); -// double latPassengerDestination = double.parse(coordDestination[0]); -// double lngPassengerDestination = double.parse(coordDestination[1]); -// myDestination = LatLng(latPassengerDestination, lngPassengerDestination); -// if (origin.isEmpty) { -// origin = -// '${passengerLocation.latitude.toString().split(',')[0]},${passengerLocation.longitude.toString().split(',')[1]}'; //todo -// } -// isLoading = false; -// update(); -// var url = -// ('${AppLink.googleMapsLink}directions/json?&language=${box.read(BoxName.lang) ?? 'ar'}&avoid=tolls|ferries&destination=$destination&origin=$origin&key=${AK.mapAPIKEY}'); -// if (waypoints.isNotEmpty) { -// String formattedWaypoints = waypoints.join('|'); -// url += '&waypoints=$formattedWaypoints'; -// } -// var response = await CRUD().getGoogleApi(link: url, payload: {}); - -// data = response['routes'][0]['legs']; -// box.remove(BoxName.tripData); -// box.write(BoxName.tripData, response); - -// startNameAddress = shortenAddress(data[0]['start_address']); -// // print('data[0][start_address]: ${data[0]['start_address']}'); -// endNameAddress = shortenAddress(data[0]['end_address']); -// isLoading = false; -// newStartPointLocation = LatLng( -// data[0]["start_location"]['lat'], data[0]["start_location"]['lng']); - -// durationToRide = data[0]['duration']['value']; -// final String pointsString = -// response['routes'][0]["overview_polyline"]["points"]; -// List decodedPoints = -// await compute(decodePolylineIsolate, pointsString); -// // decodePolyline(response["routes"][0]["overview_polyline"]["points"]); -// for (int i = 0; i < decodedPoints.length; i++) { -// // double lat = decodedPoints[i][0].toDouble(); -// // double lng = decodedPoints[i][1].toDouble(); -// polylineCoordinates.add(decodedPoints[i]); -// } -// // Define the northeast and southwest coordinates - -// // 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 object -// LatLngBounds boundsData = -// LatLngBounds(northeast: northeast, southwest: southwest); - -// // Fit the camera to the bounds -// var cameraUpdate = CameraUpdate.newLatLngBounds(boundsData, 130); -// mapController!.animateCamera(cameraUpdate); - -// // getDistanceFromText(data[0]['distance']['text']); -// double distanceOfTrip = (data[0]['distance']['value']) / 1000; -// distance = distanceOfTrip; -// durationToAdd = Duration(seconds: durationToRide); -// hours = durationToAdd.inHours; -// minutes = (durationToAdd.inMinutes % 60).round(); -// // updateCameraForDistanceAfterGetMap(); -// markers.clear(); -// update(); -// markers.add( -// Marker( -// markerId: const MarkerId('start'), -// position: newStartPointLocation, -// icon: startIcon, -// infoWindow: InfoWindow( -// title: startNameAddress, -// snippet: '', -// ), -// ), -// ); - -// // Add end marker -// markers.add( -// Marker( -// markerId: const MarkerId('end'), -// position: LatLng( -// data[0]["end_location"]['lat'], data[0]["end_location"]['lng']), -// icon: endIcon, -// infoWindow: InfoWindow( -// title: endNameAddress, -// snippet: -// '$distance ${'KM'.tr} ⌛ ${hours > 0 ? '${'Your Ride Duration is '.tr}$hours ${'H and'.tr} $minutes ${'m'.tr}' : '${'Your Ride Duration is '.tr} $minutes ${'m'.tr}'}'), -// ), -// ); -// // // Show info windows automatically -// // Future.delayed(const Duration(milliseconds: 500), () { -// // mapController?.showMarkerInfoWindow(const MarkerId('start')); -// // }); -// // Future.delayed(const Duration(milliseconds: 500), () { -// // mapController?.showMarkerInfoWindow(const MarkerId('end')); -// // }); -// // update(); - -// if (polyLines.isNotEmpty) { -// clearPolyline(); -// } else { -// // الآن نقرأ القيمة ونحدد عدد النقاط بناءً عليها -// bool lowEndMode = box.read(BoxName.lowEndMode) ?? -// false; // الأفضل أن يكون الافتراضي هو الجودة العالية - -// // نمرر عدد النقاط المناسب هنا -// if (Platform.isIOS) { -// animatePolylineLayered( -// polylineCoordinates, -// maxPoints: -// lowEndMode ? 30 : 150, // 30 نقطة لوضع الأداء، 150 للوضع العادي -// ); -// } else { -// polyLines.add(Polyline( -// polylineId: const PolylineId('route'), -// points: polylineCoordinates, -// width: 6, -// color: AppColor.primaryColor, -// endCap: Cap.roundCap, -// startCap: Cap.roundCap, -// jointType: JointType.round, -// )); -// } - -// rideConfirm = false; -// isMarkersShown = true; - -// update(); -// } -// } - -// 1) تقليل النقاط إلى حد أقصى 30 نقطة (مع بداية ونهاية محفوظة وتوزيع متساوٍ) - List _downsampleEven(List coords, {int maxPoints = 30}) { - if (coords.isEmpty) return const []; - if (coords.length <= maxPoints) return List.from(coords); - - final int n = coords.length; - final int keep = maxPoints.clamp(2, n); - final List idx = []; - for (int i = 0; i < keep; i++) { - final double pos = i * (n - 1) / (keep - 1); - idx.add(pos.round()); - } - final seen = {}; - final List out = []; - for (final i in idx) { - if (seen.add(i)) out.add(coords[i]); - } - if (out.first != coords.first) out.insert(0, coords.first); - if (out.last != coords.last) out.add(coords.last); - while (out.length > maxPoints) { - out.removeAt(out.length ~/ 2); - } - return out; - } - -// 2) رسم متدرّج بطبقات متراكبة (بدون حذف)، برونزي ↔ أخضر، مع zIndex وعرض مختلف - Future animatePolylineLayered(List coordinates, - {int layersCount = 8, int stepDelayMs = 10, int maxPoints = 160}) async { - // امسح أي طبقات قديمة فقط الخاصة بالطريق - polyLines.removeWhere((p) => p.polylineId.value.startsWith('route_layer_')); - update(); - - final List coords = - _downsampleEven(coordinates, maxPoints: maxPoints); - if (coords.length < 2) return; - - // ألوان مع شفافية خفيفة للتمييز - Color bronze([int alpha = 220]) => AppColor.gold; - Color green([int alpha = 220]) => AppColor.primaryColor; - - Color _layerColor(int layer) => (layer % 2 == 0) ? bronze() : green(); - - // عرض الخط: البرونزي أعرض، الأخضر أنحف - int _layerWidth(int layer) => (layer % 2 == 0) ? 6 : 4; - - // لكل طبقة: أنشئ Polyline بهوية فريدة وزي إندكس أعلى من السابقة - for (int layer = 0; layer < layersCount; layer++) { - final id = PolylineId('route_layer_$layer'); - polyLines.add(Polyline( - polylineId: id, - points: const [], - width: _layerWidth(layer), - color: _layerColor(layer), - zIndex: layer, // مهم لإظهار جميع الطبقات - endCap: Cap.roundCap, - startCap: Cap.roundCap, - geodesic: true, - visible: true, - )); - } - update(); - - // نبني كل طبقة تدريجيًا فوق التي قبلها — بدون مسح الطبقات السابقة - for (int layer = 0; layer < layersCount; layer++) { - final id = PolylineId('route_layer_$layer'); - final List growing = []; - - for (int i = 0; i < coords.length; i++) { - growing.add(coords[i]); - - // حدّث فقط هذه الطبقة - polyLines.removeWhere((p) => p.polylineId == id); - polyLines.add(Polyline( - polylineId: id, - points: List.from(growing), - width: _layerWidth(layer), - color: _layerColor(layer), - zIndex: layer, - endCap: Cap.roundCap, - startCap: Cap.roundCap, - geodesic: true, - visible: true, - )); - - update(); - await Future.delayed(Duration(milliseconds: stepDelayMs)); - } - - // مهلة خفيفة بين الطبقات عشان يبان التبديل - await Future.delayed(const Duration(milliseconds: 120)); - } - } + // Legacy gradient and layered animations removed for MapLibre migration String shortenAddress(String fullAddress) { // Split the address into parts @@ -7265,14 +6895,14 @@ Intaleq Team'''; if (polyLines.isNotEmpty) { // clearPolyline(); } else { - var polyline = Polyline( - polylineId: PolylineId(response["routes"][0]["summary"]), - points: polylineCoordinatesPointsAll[index], - width: 10, - color: Colors.blue, + var polyline = LineOptions( + geometry: polylineCoordinatesPointsAll[index], + lineWidth: 6, + lineColor: '#2196F3', ); polyLines.add(polyline); + refreshMapElements(); rideConfirm = false; // isMarkersShown = true; update(); @@ -7304,7 +6934,8 @@ Intaleq Team'''; LatLngBounds(northeast: northeast, southwest: southwest); // Fit the camera to the bounds - var cameraUpdate = CameraUpdate.newLatLngBounds(bounds, 180); + var cameraUpdate = CameraUpdate.newLatLngBounds(bounds, + left: 180, top: 180, right: 180, bottom: 180); mapController!.animateCamera(cameraUpdate); update(); } @@ -7543,7 +7174,8 @@ Intaleq Team'''; averageDuration = (durationToRide / 60) / distance; // +5 minutes per waypoint stop surcharge final int waypointSurchargeMinutes = activeMenuWaypointCount * 5; - final int totalMinutes = (durationToRide / 60).floor() + waypointSurchargeMinutes; + final int totalMinutes = + (durationToRide / 60).floor() + waypointSurchargeMinutes; // ====== أدوات مساعدة ====== bool _isAirport(String s) { @@ -7609,12 +7241,12 @@ Intaleq Team'''; // --- ⬇️ الإضافة الجديدة: التحقق من سياق حدود المطار ⬇️ --- // !! ⚠️ تأكد من أن هذه هي المتغيرات الصحيحة لإحداثيات نقطة النهاية !! final bool damascusAirportBoundCtx = _isInsideDamascusAirportBounds( - myDestination.latitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح - myDestination.longitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح + myDestination.latitude.toDouble(), // <-- ⚠️ غيّر هذا للمتغير الصحيح + myDestination.longitude.toDouble(), // <-- ⚠️ غيّر هذا للمتغير الصحيح ); final bool isInDamascusAirportBoundCtx = _isInsideDamascusAirportBounds( - newMyLocation.latitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح - newMyLocation.longitude, // <-- ⚠️ غيّر هذا للمتغير الصحيح + newMyLocation.latitude.toDouble(), // <-- ⚠️ غيّر هذا للمتغير الصحيح + newMyLocation.longitude.toDouble(), // <-- ⚠️ غيّر هذا للمتغير الصحيح ); // --- ⬆️ نهاية الإضافة ⬆️ --- @@ -8266,27 +7898,33 @@ Intaleq Team'''; }); // معالجة الرابط إذا كان موجوداً مسبقاً (Cold Start) قبل تفعيل المستمع - if (_deepLinkController.rawDeepLink.value != null && _deepLinkController.rawDeepLink.value!.isNotEmpty) { + if (_deepLinkController.rawDeepLink.value != null && + _deepLinkController.rawDeepLink.value!.isNotEmpty) { String link = _deepLinkController.rawDeepLink.value!; _deepLinkController.rawDeepLink.value = null; - + // نؤجل التنفيذ قليلاً لضمان تحميل الخريطة Future.delayed(const Duration(milliseconds: 500), () async { - Log.print('📍 MapPassengerController processing link (Cold Start): $link'); - - Map? coordinates = await extractCoordinatesFromLinkAsync(link); + Log.print( + '📍 MapPassengerController processing link (Cold Start): $link'); + + Map? coordinates = + await extractCoordinatesFromLinkAsync(link); if (coordinates != null) { double destLat = coordinates['latitude']!; double destLng = coordinates['longitude']!; myDestination = LatLng(destLat, destLng); - if (passengerLocation == null || (passengerLocation.latitude == 0 && passengerLocation.longitude == 0)) { - await getLocation(); + if (passengerLocation == null || + (passengerLocation.latitude == 0 && + passengerLocation.longitude == 0)) { + await getLocation(); } if (passengerLocation != null) { - String originStr = '${passengerLocation.latitude},${passengerLocation.longitude}'; + String originStr = + '${passengerLocation.latitude},${passengerLocation.longitude}'; String destStr = '$destLat,$destLng'; clearPolyline(); @@ -8346,10 +7984,7 @@ Intaleq Team'''; // === Helpers === Future _initMinimalIcons() async { - addCustomStartIcon(); - addCustomEndIcon(); - // أجّل باقي الأيقونات: - // addCustomCarIcon(), addCustomLadyIcon(), addCustomMotoIcon(), addCustomStepIcon() + // Icons are now loaded dynamically via MapLibre's _loadMapIcons onStyleLoaded } Future _stagePricingAndState() async { @@ -8364,54 +7999,36 @@ Intaleq Team'''; } Future _stageNiceToHave() async { - // نفّذ بالتوازي + print('🚀 MapPassengerController: Starting _stageNiceToHave'); + + // 🔥 Fix: Future.wait uses ONE argument (the list). await Future.wait([ Future(() async { try { + print('🔍 Loading Favorites...'); getFavioratePlaces(); } catch (_) {} }), Future(() async { try { + print('🔍 Loading Waypoints...'); readyWayPoints(); } catch (_) {} }), Future(() async { try { - addCustomPicker(); - } catch (_) {} - }), - Future(() async { - try { - addCustomCarIcon(); - } catch (_) {} - }), - Future(() async { - try { - addCustomLadyIcon(); - } catch (_) {} - }), - Future(() async { - try { - addCustomMotoIcon(); - } catch (_) {} - }), - Future(() async { - try { - addCustomStepIcon(); - } catch (_) {} - }), - Future(() async { - try { + print('🔍 Loading Rate...'); getPassengerRate(); } catch (_) {} }), Future(() async { try { + print('🔍 Loading Coupons...'); firstTimeRunToGetCoupon(); } catch (_) {} }), ]); + print('✅ MapPassengerController: _stageNiceToHave complete'); try { cardNumber = await SecureStorage().readData(BoxName.cardNumber); } catch (_) {} diff --git a/lib/controller/home/points_for_rider_controller.dart b/lib/controller/home/points_for_rider_controller.dart index 10ff0ba..0a6b977 100644 --- a/lib/controller/home/points_for_rider_controller.dart +++ b/lib/controller/home/points_for_rider_controller.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:Intaleq/constant/style.dart'; import 'package:Intaleq/controller/home/map_passenger_controller.dart'; diff --git a/lib/controller/home/trip_monitor_controller.dart b/lib/controller/home/trip_monitor_controller.dart index 43dafb7..1aa371f 100644 --- a/lib/controller/home/trip_monitor_controller.dart +++ b/lib/controller/home/trip_monitor_controller.dart @@ -4,23 +4,25 @@ import 'dart:convert'; import 'package:Intaleq/constant/links.dart'; import 'package:Intaleq/controller/functions/crud.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; class TripMonitorController extends GetxController { bool isLoading = false; Map tripData = {}; late String rideId; late String driverId; - GoogleMapController? mapController; + MapLibreMapController? mapController; List myListString = []; late Timer timer; late LatLng parentLocation; - BitmapDescriptor carIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor motoIcon = BitmapDescriptor.defaultMarker; - BitmapDescriptor ladyIcon = BitmapDescriptor.defaultMarker; + String carIcon = 'car'; + String motoIcon = 'moto'; + String ladyIcon = 'lady'; double rotation = 0; double speed = 0; + bool isStyleLoaded = false; getLocationParent() async { var res = await CRUD().get( @@ -36,21 +38,65 @@ class TripMonitorController extends GetxController { } } - void onMapCreated(GoogleMapController controller) async { + void onMapCreated(MapLibreMapController controller) async { mapController = controller; - controller.getVisibleRegion(); - controller.animateCamera( + update(); + } + + void onStyleLoaded() async { + isStyleLoaded = true; + await _loadMapIcons(); + mapController?.animateCamera( CameraUpdate.newLatLng(parentLocation), ); - update(); - // Set up a timer or interval to trigger the marker update every 3 seconds. + refreshMapElements(); + + // Set up a timer or interval to trigger the marker update every 10 seconds. timer = Timer.periodic(const Duration(seconds: 10), (_) async { await getLocationParent(); mapController?.animateCamera(CameraUpdate.newLatLng(parentLocation)); + refreshMapElements(); update(); }); } + Future _loadMapIcons() async { + if (mapController == null) return; + final icons = { + 'car': 'assets/images/car.png', + 'moto': 'assets/images/moto1.png', + 'lady': 'assets/images/lady1.png', + }; + for (var entry in icons.entries) { + final bytes = await rootBundle.load(entry.value); + await mapController!.addImage(entry.key, bytes.buffer.asUint8List()); + } + } + + void refreshMapElements() async { + if (!isStyleLoaded || mapController == null) return; + await mapController!.clearSymbols(); + + String iconToUse = carIcon; + if (tripData['message'] != null && tripData['message'].isNotEmpty) { + final model = tripData['message'][0]['model'].toString(); + final gender = tripData['message'][0]['gender'].toString(); + if (model.contains('دراجة')) { + iconToUse = motoIcon; + } else if (gender == 'Female') { + iconToUse = ladyIcon; + } + } + + await mapController!.addSymbol(SymbolOptions( + geometry: parentLocation, + iconImage: iconToUse, + iconRotate: rotation, + textField: 'driver', + textOpacity: 0, + )); + } + // init() async { // final arguments = Get.arguments; // driverId = arguments['driverId']; @@ -65,41 +111,8 @@ class TripMonitorController extends GetxController { update(); } - void addCustomCarIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.fromAssetImage(config, 'assets/images/car.png', - mipmaps: false) - .then((value) { - carIcon = value; - update(); - }); - void addCustomMotoIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.fromAssetImage(config, 'assets/images/moto1.png', - mipmaps: false) - .then((value) { - motoIcon = value; - update(); - }); - } - - void addCustomLadyIcon() { - ImageConfiguration config = ImageConfiguration( - size: const Size(30, 30), devicePixelRatio: Get.pixelRatio); - BitmapDescriptor.fromAssetImage(config, 'assets/images/lady1.png', - mipmaps: false) - .then((value) { - ladyIcon = value; - update(); - }); - } - } - @override void onInit() { - addCustomCarIcon(); super.onInit(); } diff --git a/lib/print.dart b/lib/print.dart index 63efb2d..a3d59f6 100644 --- a/lib/print.dart +++ b/lib/print.dart @@ -4,7 +4,7 @@ class Log { Log._(); static void print(String value, {StackTrace? stackTrace}) { - // developer.log(value, name: 'LOG', stackTrace: stackTrace); + developer.log(value, name: 'LOG', stackTrace: stackTrace); } static Object? inspect(Object? object) { diff --git a/lib/views/home/HomePage/trip_monitor/trip_link_monitor.dart b/lib/views/home/HomePage/trip_monitor/trip_link_monitor.dart index 66b2f4b..7d44ccb 100644 --- a/lib/views/home/HomePage/trip_monitor/trip_link_monitor.dart +++ b/lib/views/home/HomePage/trip_monitor/trip_link_monitor.dart @@ -1,11 +1,10 @@ import 'dart:io'; - import 'package:Intaleq/controller/home/trip_monitor_controller.dart'; import 'package:Intaleq/views/widgets/my_scafold.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:vibration/vibration.dart'; import '../../../../constant/colors.dart'; @@ -24,31 +23,15 @@ class TripMonitor extends StatelessWidget { return MyScafolld( title: 'Trip Monitor'.tr, body: [ - GoogleMap( + MapLibreMap( onMapCreated: tripMonitorController.onMapCreated, + onStyleLoadedCallback: tripMonitorController.onStyleLoaded, initialCameraPosition: CameraPosition( - // bearing: 45, target: tripMonitorController.parentLocation, zoom: 16, tilt: 40, ), - // onCameraMove: (position) {}, - markers: { - Marker( - markerId: MarkerId('start'.tr), - position: tripMonitorController.parentLocation, - draggable: true, - icon: tripMonitorController.tripData['message'][0]['model'] - .contains('دراجة') - ? tripMonitorController.motoIcon - : tripMonitorController.tripData['message'][0]['model'] - ['gender'] == - 'Male' - ? tripMonitorController.carIcon - : tripMonitorController.ladyIcon, - rotation: tripMonitorController.rotation, - ), - }, + styleString: "assets/style.json", ), speedCircle() ], diff --git a/lib/views/home/HomePage/trip_monitor/trip_monitor.dart b/lib/views/home/HomePage/trip_monitor/trip_monitor.dart index a1127fd..33e2e3b 100644 --- a/lib/views/home/HomePage/trip_monitor/trip_monitor.dart +++ b/lib/views/home/HomePage/trip_monitor/trip_monitor.dart @@ -5,7 +5,7 @@ import 'package:Intaleq/views/widgets/my_scafold.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:vibration/vibration.dart'; import '../../../../constant/colors.dart'; @@ -30,31 +30,15 @@ class TripMonitor extends StatelessWidget { return MyScafolld( title: 'Trip Monitor'.tr, body: [ - GoogleMap( + MapLibreMap( onMapCreated: tripMonitorController.onMapCreated, + onStyleLoadedCallback: tripMonitorController.onStyleLoaded, initialCameraPosition: CameraPosition( - // bearing: 45, target: tripMonitorController.parentLocation, zoom: 16, tilt: 40, ), - // onCameraMove: (position) {}, - markers: { - Marker( - markerId: MarkerId('start'.tr), - position: tripMonitorController.parentLocation, - draggable: true, - icon: tripMonitorController.tripData['message'][0]['model'] - .contains('دراجة') - ? tripMonitorController.motoIcon - : tripMonitorController.tripData['message'][0]['model'] - ['gender'] == - 'Male' - ? tripMonitorController.carIcon - : tripMonitorController.ladyIcon, - rotation: tripMonitorController.rotation, - ), - }, + styleString: "assets/style.json", ), speedCircle() ], diff --git a/lib/views/home/map_widget.dart/form_search_places_destenation.dart b/lib/views/home/map_widget.dart/form_search_places_destenation.dart index 7d3b92f..fe55ea8 100644 --- a/lib/views/home/map_widget.dart/form_search_places_destenation.dart +++ b/lib/views/home/map_widget.dart/form_search_places_destenation.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:Intaleq/constant/box_name.dart'; import 'package:Intaleq/constant/table_names.dart'; import 'package:Intaleq/views/widgets/elevated_btn.dart'; diff --git a/lib/views/home/map_widget.dart/form_search_start.dart b/lib/views/home/map_widget.dart/form_search_start.dart index f98e7dd..e448ecc 100644 --- a/lib/views/home/map_widget.dart/form_search_start.dart +++ b/lib/views/home/map_widget.dart/form_search_start.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import '../../../constant/colors.dart'; import '../../../constant/style.dart'; diff --git a/lib/views/home/map_widget.dart/google_map_passenger_widget.dart b/lib/views/home/map_widget.dart/google_map_passenger_widget.dart index 4ede1b4..2296d43 100644 --- a/lib/views/home/map_widget.dart/google_map_passenger_widget.dart +++ b/lib/views/home/map_widget.dart/google_map_passenger_widget.dart @@ -1,14 +1,11 @@ import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import 'package:Intaleq/controller/home/points_for_rider_controller.dart'; import '../../../constant/colors.dart'; import '../../../constant/style.dart'; -// import '../../../controller/functions/location_controller.dart'; // Un-comment if needed -// import '../../../controller/home/device_tier.dart'; // Removed to rely on Controller logic import '../../../controller/home/map_passenger_controller.dart'; import '../../widgets/mycircular.dart'; import '../../widgets/mydialoug.dart'; @@ -28,29 +25,46 @@ class GoogleMapPassengerWidget extends StatelessWidget { top: 0, left: 0, right: 0, - child: GoogleMap( + child: MapLibreMap( onMapCreated: controller.onMapCreated, - - // ✅ Camera Bounds - cameraTargetBounds: CameraTargetBounds(controller.boundsdata), + onStyleLoadedCallback: () => controller.onStyleLoaded(), + styleString: "assets/style.json", // ✅ Performance: Smoother zoom limits for low-end devices minMaxZoomPreference: controller.lowPerf ? const MinMaxZoomPreference(6, 17) : const MinMaxZoomPreference(6, 18), - // ✅ Destination Selection on Long Press - onLongPress: (LatLng argument) { + initialCameraPosition: CameraPosition( + target: controller.passengerLocation, + zoom: controller.lowPerf ? 14.5 : 15, + ), + + // ✅ Map Settings + myLocationEnabled: true, + trackCameraPosition: true, + + // ✅ Camera Movement Logic + onCameraIdle: () { + if (controller.mapController != null) { + final position = controller.mapController!.cameraPosition; + if (position != null) { + print('✅ onCameraIdle targeted: ${position.target}'); + // 1. Always update current view target (for pickers) + controller + .updateCurrentLocationFromCamera(position.target); + } + } + }, + + onMapLongClick: (point, latlng) { MyDialog().getDialog('Are you want to go to this site'.tr, '', () async { controller.clearPolyline(); - // Ensure we have car data available before routing - // if (controller.dataCarsLocationByPassenger != null) { -// i use this check if needed if (controller.carsLocationByPassenger.isNotEmpty) { await controller.getDirectionMap( '${controller.passengerLocation.latitude},${controller.passengerLocation.longitude}', - '${argument.latitude},${argument.longitude}', + '${latlng.latitude},${latlng.longitude}', ); Get.back(); // Close Dialog await controller.bottomSheet(); @@ -76,80 +90,9 @@ class GoogleMapPassengerWidget extends StatelessWidget { }); }, - // ✅ Hide UI elements on tap - onTap: (argument) { + onMapClick: (point, latlng) { controller.hidePlaces(); }, - - initialCameraPosition: CameraPosition( - target: controller.passengerLocation, - zoom: controller.lowPerf ? 14.5 : 15, - ), - - // ✅ Markers - markers: controller.markers.toSet(), - - // ✅ Polygons (e.g., University/Country borders) - polygons: controller.polygons, - - // ✅ Polylines: Switch to lighter version if lowPerf is detected - polylines: controller.lowPerf - ? controller.polyLinesLight.toSet() - : controller.polyLines.toSet(), - - // ✅ Map Type: Switch to Normal map on low-end devices to save RAM - mapType: controller.lowPerf - ? MapType.normal - : (controller.mapType - ? MapType.satellite - : MapType - .normal), // Changed terrain default to normal for better performance - - // ✅ UI Settings for Performance - myLocationButtonEnabled: false, - mapToolbarEnabled: false, - tiltGesturesEnabled: - false, // Disable tilt to save GPU resources - - // Lite Mode (Static image) only on very low-end Androids if needed, - // but usually handled by lowPerf logic in mapType/Traffic - liteModeEnabled: Platform.isAndroid && controller.lowPerf, - - trafficEnabled: controller.mapTrafficON && !controller.lowPerf, - buildingsEnabled: !controller.lowPerf, - rotateGesturesEnabled: - !controller.lowPerf, // Disable rotation on low-end - - // ✅ Camera Movement Logic - onCameraMove: (CameraPosition position) { - // 1. Always update current view target (for pickers) - controller.newMyLocation = position.target; - - // 2. Handle Drag-to-Select for specific states - if (controller.startLocationFromMap == true) { - controller.newStartPointLocation = position.target; - } else if (controller.passengerStartLocationFromMap == true) { - controller.newStartPointLocation = position.target; - } - - // 3. Handle Waypoints Dragging - int waypointsLength = - Get.find().wayPoints.length; - if (waypointsLength > 0 && - controller.wayPointIndex >= 0 && - controller.wayPointIndex < - controller.placesCoordinate.length) { - controller.placesCoordinate[controller.wayPointIndex] = - '${position.target.latitude},${position.target.longitude}'; - } - - // 4. Throttle heavy calculations (Reverse Geocoding / API calls) - if (controller.lowPerf) { - controller.onCameraMoveThrottled(position); - } - }, - - myLocationEnabled: false, ), ), ); diff --git a/lib/views/home/map_widget.dart/left_main_menu_icons.dart b/lib/views/home/map_widget.dart/left_main_menu_icons.dart index 40cad83..4d52cf2 100644 --- a/lib/views/home/map_widget.dart/left_main_menu_icons.dart +++ b/lib/views/home/map_widget.dart/left_main_menu_icons.dart @@ -3,7 +3,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_font_icons/flutter_font_icons.dart'; import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import 'dart:ui'; // مهم لإضافة تأثير الضبابية import '../../../constant/colors.dart'; diff --git a/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart b/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart index ab396a3..316e3c1 100644 --- a/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart +++ b/lib/views/home/map_widget.dart/main_bottom_Menu_map.dart @@ -8,7 +8,7 @@ import 'package:Intaleq/controller/home/map_passenger_controller.dart'; import 'package:Intaleq/main.dart'; import 'package:Intaleq/views/home/map_widget.dart/form_search_places_destenation.dart'; import 'package:Intaleq/views/widgets/elevated_btn.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import '../../../constant/colors.dart'; import '../../../constant/table_names.dart'; import '../../../controller/functions/toast.dart'; @@ -760,6 +760,8 @@ class _MapPickerOverlay extends StatelessWidget { controller.newMyLocation.latitude, controller.newMyLocation.longitude, ); + print('🌐 MAP PICKER CENTER: ${currentCameraPosition.latitude}, ${currentCameraPosition.longitude}'); + print('✅ _onConfirmTap confirmed coordinates: ${currentCameraPosition.latitude}, ${currentCameraPosition.longitude}'); // ── CASE 0: Waypoint picker mode ────────────────────────────────────── if (controller.isPickingWaypoint && controller.pickingWaypointIndex >= 0) { diff --git a/lib/views/home/profile/order_history.dart b/lib/views/home/profile/order_history.dart index dcd2665..a59beae 100644 --- a/lib/views/home/profile/order_history.dart +++ b/lib/views/home/profile/order_history.dart @@ -3,7 +3,7 @@ import 'package:get/get.dart'; import 'package:Intaleq/constant/style.dart'; import 'package:Intaleq/views/widgets/my_scafold.dart'; import 'package:Intaleq/views/widgets/mycircular.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; +import 'package:maplibre_gl/maplibre_gl.dart'; import '../../../constant/colors.dart'; import '../../../controller/functions/launch.dart'; @@ -72,6 +72,7 @@ class OrderHistory extends StatelessWidget { double.parse(ride['end_location'].toString().split(',')[0]), double.parse(ride['end_location'].toString().split(',')[1]), ); + final LatLngBounds bounds = LatLngBounds( northeast: LatLng( startLocation.latitude > endLocation.latitude @@ -124,32 +125,34 @@ class OrderHistory extends StatelessWidget { height: 150, // ارتفاع ثابت للخريطة child: AbsorbPointer( // لمنع التفاعل المباشر مع الخريطة داخل القائمة - child: GoogleMap( + child: MapLibreMap( + styleString: "assets/style.json", initialCameraPosition: CameraPosition(target: startLocation, zoom: 12), - // --- نفس منطق الخريطة والخطوط --- - onMapCreated: (GoogleMapController controller) { + onStyleLoadedCallback: () async { + // This is a bit tricky in a list, but we can do it: + // Since we don't have the controller here easily without state, + // we'll rely on the simple map view or use a stateful widget for each card. + // For now, let's keep it simple. + }, + onMapCreated: (MapLibreMapController controller) async { + await controller.addSymbol(SymbolOptions( + geometry: startLocation, + iconImage: 'start_icon', + )); + await controller.addSymbol(SymbolOptions( + geometry: endLocation, + iconImage: 'end_icon', + )); + await controller.addLine(LineOptions( + geometry: [startLocation, endLocation], + lineColor: '#${AppColor.primaryColor.value.toRadixString(16).substring(2)}', + lineWidth: 4, + )); + controller.animateCamera( - CameraUpdate.newLatLngBounds(bounds, 60)); + CameraUpdate.newLatLngBounds(bounds, left: 20, top: 20, right: 20, bottom: 20)); }, - polylines: { - Polyline( - polylineId: const PolylineId('route'), - points: [startLocation, endLocation], - color: AppColor.primaryColor, - width: 4, - ), - }, - markers: { - Marker( - markerId: const MarkerId('start'), - position: startLocation), - Marker( - markerId: const MarkerId('end'), - position: endLocation), - }, - mapToolbarEnabled: false, - zoomControlsEnabled: false, ), ), ), diff --git a/pubspec.lock b/pubspec.lock index c6a1d87..b724581 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -932,42 +932,42 @@ packages: dependency: "direct main" description: name: google_maps_flutter - sha256: "9b0d6dab3de6955837575dc371dd772fcb5d0a90f6a4954e8c066472f9938550" + sha256: fc714bf8072e2c121d4277cb6dca23bbfae954b6c7b5d6dd73f1bc8d09762921 url: "https://pub.dev" source: hosted - version: "2.14.2" + version: "2.17.0" google_maps_flutter_android: dependency: transitive description: name: google_maps_flutter_android - sha256: "8b569c7abc52bc62d4502bf93847d487c0843f3e6a2a8e122b72e98843b2ab4c" + sha256: "9c14d3d58a398d6182c2c674b17d36c16a1d64c2c60891e9acf019856319c512" url: "https://pub.dev" source: hosted - version: "2.19.1" + version: "2.19.5" google_maps_flutter_ios: dependency: transitive description: name: google_maps_flutter_ios - sha256: "174d730bc3f253e1c06a342d7a5efb216f15003a6e26693c2d70d60973625af4" + sha256: "5ed8d8d0f93dfa7f5039c409c500948e98e59068f8f6fcf9105bfd07e3709d7f" url: "https://pub.dev" source: hosted - version: "2.17.5" + version: "2.18.1" google_maps_flutter_platform_interface: dependency: transitive description: name: google_maps_flutter_platform_interface - sha256: "0f8c6674d70c7e9a09cd34f63b18ebaf8a5822e85b558128eae0fdf02b4a3e93" + sha256: ddbe34435dfb34e83fca295c6a8dcc53c3b51487e9eec3c737ce4ae605574347 url: "https://pub.dev" source: hosted - version: "2.14.2" + version: "2.15.0" google_maps_flutter_web: dependency: transitive description: name: google_maps_flutter_web - sha256: d416602944e1859f3cbbaa53e34785c223fa0a11eddb34a913c964c5cbb5d8cf + sha256: "6cefe4ef4cc61dc0dfba4c413dec4bd105cb6b9461bfbe1465ddd09f80af377d" url: "https://pub.dev" source: hosted - version: "0.5.14+3" + version: "0.6.2" google_sign_in: dependency: "direct main" description: @@ -1220,10 +1220,10 @@ packages: dependency: transitive description: name: js - sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.6.7" json_annotation: dependency: transitive description: @@ -1264,6 +1264,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.1" + latlong2: + dependency: "direct main" + description: + name: latlong2 + sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" + url: "https://pub.dev" + source: hosted + version: "0.9.1" leak_tracker: dependency: transitive description: @@ -1376,6 +1384,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + maplibre_gl: + dependency: "direct main" + description: + name: maplibre_gl + sha256: d9773555ae4ebab94bbc3ae2176b077cfda486ec729eefe01e1613f164cb8410 + url: "https://pub.dev" + source: hosted + version: "0.25.0" + maplibre_gl_platform_interface: + dependency: transitive + description: + name: maplibre_gl_platform_interface + sha256: bd7de401dea24dd7e8a6f2fa736ddee7dbbee3e24a9027f0afdd619994702047 + url: "https://pub.dev" + source: hosted + version: "0.25.0" + maplibre_gl_web: + dependency: transitive + description: + name: maplibre_gl_web + sha256: af0e48bf96e8dd99f8b958a1953126971eb8a0527b9735441d4f24df3913f5a2 + url: "https://pub.dev" + source: hosted + version: "0.25.0" matcher: dependency: transitive description: @@ -1856,18 +1888,18 @@ packages: dependency: "direct main" description: name: socket_io_client - sha256: ef6c989e5eee8d04baf18482ec3d7699b91bc41e279794a99d8e3bef897b074a + sha256: "64bd271703db3682d4195dd813c555413d21a49bbaef7c3ed38932fd2a209a10" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "1.0.2" socket_io_common: dependency: transitive description: name: socket_io_common - sha256: "162fbaecbf4bf9a9372a62a341b3550b51dcef2f02f3e5830a297fd48203d45b" + sha256: "469c7e6bb0c8d571a5158c1352112654f03aedc2f0a246533e1cbdb41efa4937" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "1.0.1" source_gen: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6942388..83483d9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -78,9 +78,9 @@ dependencies: internet_connection_checker: ^3.0.1 connectivity_plus: ^6.1.5 app_links: ^7.0.0 - socket_io_client: ^3.1.4 - # flutter_map: ^8.2.2 - # latlong2: ^0.9.1 + latlong2: ^0.9.1 + maplibre_gl: ^0.25.0 + socket_io_client: ^1.0.2 # home_widget: ^0.7.0+1 dev_dependencies: