238 lines
6.9 KiB
Dart
238 lines
6.9 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:developer';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
|
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|
import 'package:sfm_app/feature/devices/device_model.dart';
|
|
import 'package:sfm_app/feature/map/map_bloc.dart';
|
|
import 'package:sfm_app/feature/map/widget/on_tap_marker_widget.dart';
|
|
import 'package:sfm_app/product/base/bloc/base_bloc.dart';
|
|
import 'package:sfm_app/product/constant/icon/icon_constants.dart';
|
|
import 'package:sfm_app/product/services/api_services.dart';
|
|
|
|
class MapScreen extends StatefulWidget {
|
|
const MapScreen({super.key});
|
|
|
|
@override
|
|
State<MapScreen> createState() => _MapScreenState();
|
|
}
|
|
|
|
class _MapScreenState extends State<MapScreen> {
|
|
late BitmapDescriptor normalIcon;
|
|
late BitmapDescriptor offlineIcon;
|
|
late BitmapDescriptor abnormalIcon;
|
|
late BitmapDescriptor flameIcon;
|
|
late BitmapDescriptor hospitalIcon;
|
|
late BitmapDescriptor fireStationIcon;
|
|
late MapBloc mapBloc;
|
|
late ClusterManager clusterManager;
|
|
MapType mapType = MapType.terrain;
|
|
APIServices apiServices = APIServices();
|
|
final streamController = StreamController<GoogleMapController>.broadcast();
|
|
List<Device> devices = [];
|
|
Completer<GoogleMapController> _controller = Completer();
|
|
List<String> imageAssets = [
|
|
IconConstants.instance.getIcon("normal_icon"),
|
|
IconConstants.instance.getIcon("offline_icon"),
|
|
IconConstants.instance.getIcon("flame_icon"),
|
|
IconConstants.instance.getIcon("hospital_marker"),
|
|
IconConstants.instance.getIcon("fire_station_marker"),
|
|
];
|
|
static const CameraPosition _myPosition = CameraPosition(
|
|
target: LatLng(20.976108, 105.791666),
|
|
zoom: 12,
|
|
);
|
|
Set<Marker> markersAll = {};
|
|
List<Marker> markers = [];
|
|
LatLng myLocation = const LatLng(213761, 123123);
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
mapBloc = BlocProvider.of(context);
|
|
_loadIcons();
|
|
getAllMarkers();
|
|
clusterManager = _initClusterManager();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
streamController.close();
|
|
_controller = Completer();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: Stack(
|
|
children: [
|
|
StreamBuilder<Set<Marker>>(
|
|
stream: mapBloc.streamAllMarker,
|
|
builder: (context, markerSnapshot) {
|
|
return StreamBuilder<List<LatLng>>(
|
|
stream: mapBloc.streamPolylines,
|
|
builder: (context, polylinesSnapshot) {
|
|
return GoogleMap(
|
|
initialCameraPosition: _myPosition,
|
|
mapType: mapType,
|
|
onMapCreated: (GoogleMapController controller) {
|
|
if (!_controller.isCompleted) {
|
|
_controller.complete(controller);
|
|
}
|
|
streamController.sink.add(controller);
|
|
clusterManager.setMapId(controller.mapId);
|
|
},
|
|
markers: markerSnapshot.data ?? markersAll
|
|
..addAll(markers),
|
|
zoomControlsEnabled: true,
|
|
myLocationEnabled: true,
|
|
mapToolbarEnabled: false,
|
|
onCameraMove: (position) {
|
|
clusterManager.onCameraMove(position);
|
|
},
|
|
onCameraIdle: () {
|
|
clusterManager.updateMap();
|
|
},
|
|
polylines: {
|
|
Polyline(
|
|
polylineId: const PolylineId('router'),
|
|
points: polylinesSnapshot.data ?? [],
|
|
color: Colors.deepPurpleAccent,
|
|
width: 8,
|
|
),
|
|
},
|
|
);
|
|
},
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _loadIcons() async {
|
|
List<Future<BitmapDescriptor>> iconFutures = imageAssets.map((asset) {
|
|
return BitmapDescriptor.fromAssetImage(const ImageConfiguration(), asset);
|
|
}).toList();
|
|
|
|
List<BitmapDescriptor> icons = await Future.wait(iconFutures);
|
|
|
|
normalIcon = icons[0];
|
|
offlineIcon = icons[1];
|
|
flameIcon = icons[2];
|
|
hospitalIcon = icons[3];
|
|
fireStationIcon = icons[4];
|
|
}
|
|
|
|
ClusterManager _initClusterManager() {
|
|
return ClusterManager<Device>(
|
|
devices,
|
|
_updateMarkers,
|
|
markerBuilder: _getmarkerBuilder(),
|
|
);
|
|
}
|
|
|
|
Future<Marker> Function(Cluster<Device>) _getmarkerBuilder() =>
|
|
(cluster) async {
|
|
return Marker(
|
|
markerId: MarkerId(
|
|
cluster.getId(),
|
|
),
|
|
position: cluster.location,
|
|
onTap: () {
|
|
onTapMarker(
|
|
context,
|
|
_controller,
|
|
mapBloc,
|
|
myLocation,
|
|
cluster.items,
|
|
imageAssets,
|
|
markers,
|
|
hospitalIcon,
|
|
fireStationIcon);
|
|
},
|
|
icon: getMarkerIcon(cluster),
|
|
);
|
|
};
|
|
|
|
BitmapDescriptor getMarkerIcon(Cluster<Device> cluster) {
|
|
if (cluster.items.length == 1) {
|
|
Device item = cluster.items.first;
|
|
if (item.state == 0) {
|
|
return normalIcon;
|
|
} else if (item.state == 1) {
|
|
return flameIcon;
|
|
} else {
|
|
return offlineIcon;
|
|
}
|
|
}
|
|
bool hasStateOne = false;
|
|
bool hasOtherState = false;
|
|
|
|
for (var item in cluster.items) {
|
|
if (item.state == 1) {
|
|
hasStateOne = true;
|
|
break;
|
|
} else if (item.state != 0) {
|
|
hasOtherState = true;
|
|
}
|
|
}
|
|
|
|
// log("Has state = 1: $hasStateOne, Has other state: $hasOtherState");
|
|
|
|
if (hasStateOne) {
|
|
return flameIcon; // flameIcon
|
|
} else if (hasOtherState) {
|
|
return normalIcon; // normalIcon
|
|
} else {
|
|
return offlineIcon; // offlineIcon
|
|
}
|
|
}
|
|
|
|
bool checkStateMarker(Cluster<Device> cluster) {
|
|
bool hasStateOne = false;
|
|
bool hasOtherState = false;
|
|
|
|
for (var item in cluster.items) {
|
|
if (item.state == 1) {
|
|
hasStateOne = true;
|
|
break;
|
|
} else if (item.state != 0) {
|
|
hasOtherState = true;
|
|
}
|
|
}
|
|
|
|
// log("Has state = 1: $hasStateOne, Has other state: $hasOtherState");
|
|
|
|
if (hasStateOne) {
|
|
return true; // flameIcon
|
|
} else if (hasOtherState) {
|
|
return false; // normalIcon
|
|
} else {
|
|
return true; // offlineIcon
|
|
}
|
|
}
|
|
|
|
void _updateMarkers(Set<Marker> marker) {
|
|
log("Update Marker");
|
|
markersAll = marker;
|
|
mapBloc.sinkAllMarker.add(marker);
|
|
}
|
|
|
|
void getAllMarkers() async {
|
|
String response = await apiServices.getOwnerDevices();
|
|
if (response != "") {
|
|
final data = jsonDecode(response);
|
|
List<dynamic> result = data['items'];
|
|
final devicesList = Device.fromJsonDynamicList(result);
|
|
for (var device in devicesList) {
|
|
devices.add(device);
|
|
}
|
|
}
|
|
}
|
|
}
|