Update: 2026-07-12 05:40:28
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
// transit_live_map_page.dart — تتبع الباص الحي على الخريطة
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
import '../../constant/colors.dart';
|
||||
import '../../constant/style.dart';
|
||||
import '../../env/env.dart';
|
||||
import '../../controller/transit/transit_controller.dart';
|
||||
import '../widgets/my_scafold.dart';
|
||||
|
||||
class TransitLiveMapPage extends StatefulWidget {
|
||||
final int routeId;
|
||||
final String routeName;
|
||||
const TransitLiveMapPage({super.key, required this.routeId, required this.routeName});
|
||||
|
||||
@override
|
||||
State<TransitLiveMapPage> createState() => _TransitLiveMapPageState();
|
||||
}
|
||||
|
||||
class _TransitLiveMapPageState extends State<TransitLiveMapPage> {
|
||||
IntaleqMapController? _mapController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
Get.find<TransitController>().openLiveRoute(widget.routeId);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
Get.find<TransitController>().closeLiveRoute();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<TransitController>(
|
||||
builder: (c) {
|
||||
final stops = (c.liveTripData?['stops'] is List)
|
||||
? List<Map>.from(c.liveTripData!['stops'])
|
||||
: <Map>[];
|
||||
|
||||
final markers = <Marker>{};
|
||||
|
||||
for (final s in stops) {
|
||||
final lat = double.tryParse(s['latitude']?.toString() ?? '') ?? 0;
|
||||
final lng = double.tryParse(s['longitude']?.toString() ?? '') ?? 0;
|
||||
if (lat == 0 && lng == 0) continue;
|
||||
markers.add(Marker(
|
||||
markerId: MarkerId('stop_${s['id']}'),
|
||||
position: LatLng(lat, lng),
|
||||
infoWindow: InfoWindow(title: s['name_ar']?.toString() ?? ''),
|
||||
icon: InlqBitmap.defaultMarkerWithHue(
|
||||
(s['is_major']?.toString() ?? '0') == '1' ? 30 : 200),
|
||||
));
|
||||
}
|
||||
|
||||
LatLng? busLatLng;
|
||||
if (c.liveBusPosition != null) {
|
||||
busLatLng = LatLng(c.liveBusPosition!.lat, c.liveBusPosition!.lng);
|
||||
markers.add(Marker(
|
||||
markerId: const MarkerId('bus'),
|
||||
position: busLatLng,
|
||||
rotation: c.liveBusPosition!.heading,
|
||||
anchor: const Offset(0.5, 0.5),
|
||||
icon: InlqBitmap.defaultMarkerWithHue(120),
|
||||
));
|
||||
if (_mapController != null) {
|
||||
_mapController!.animateCamera(CameraUpdate.newLatLng(busLatLng));
|
||||
}
|
||||
}
|
||||
|
||||
final initialTarget = busLatLng ??
|
||||
(markers.isNotEmpty ? markers.first.position : const LatLng(31.95, 35.93));
|
||||
|
||||
return MyScafolld(
|
||||
title: widget.routeName,
|
||||
isleading: true,
|
||||
body: [
|
||||
Expanded(
|
||||
child: Stack(
|
||||
children: [
|
||||
IntaleqMap(
|
||||
apiKey: Env.mapSaasKey,
|
||||
initialCameraPosition: CameraPosition(target: initialTarget, zoom: 14),
|
||||
markers: markers,
|
||||
onMapCreated: (ctrl) => _mapController = ctrl,
|
||||
),
|
||||
if (c.isLoadingLiveTrip)
|
||||
const Positioned.fill(
|
||||
child: ColoredBox(
|
||||
color: Colors.black12,
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
),
|
||||
),
|
||||
if (!c.isLoadingLiveTrip && c.liveError.isNotEmpty)
|
||||
Positioned(
|
||||
top: 16,
|
||||
left: 16,
|
||||
right: 16,
|
||||
child: _statusBanner(c.liveError, AppColor.redColor),
|
||||
),
|
||||
if (!c.isLoadingLiveTrip &&
|
||||
c.liveError.isEmpty &&
|
||||
c.liveBusPosition == null)
|
||||
Positioned(
|
||||
top: 16,
|
||||
left: 16,
|
||||
right: 16,
|
||||
child: _statusBanner(
|
||||
'No bus running on this route right now'.tr, AppColor.yellowColor),
|
||||
),
|
||||
if (c.liveTripData?['trip']?['delay_minutes'] != null &&
|
||||
(int.tryParse(c.liveTripData!['trip']['delay_minutes'].toString()) ?? 0) > 0)
|
||||
Positioned(
|
||||
bottom: 24,
|
||||
left: 16,
|
||||
right: 16,
|
||||
child: _statusBanner(
|
||||
'${'Bus is delayed'.tr} ${c.liveTripData!['trip']['delay_minutes']} ${'min'.tr}',
|
||||
AppColor.yellowColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _statusBanner(String text, Color color) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColor.cardColor,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border(right: BorderSide(color: color, width: 4)),
|
||||
boxShadow: [BoxShadow(color: Colors.black12, blurRadius: 6)],
|
||||
),
|
||||
child: Text(text, style: AppStyle.title.copyWith(color: color, fontWeight: FontWeight.bold)),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user