Complete refactoring SFM App Source Code
This commit is contained in:
237
lib/feature/map/map_screen.dart
Normal file
237
lib/feature/map/map_screen.dart
Normal file
@@ -0,0 +1,237 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user