Files
sfm_app_final/lib/feature/map/map_screen.dart

283 lines
8.6 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:google_maps_cluster_manager_2/google_maps_cluster_manager_2.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'
hide ClusterManager, Cluster;
import 'package:sfm_app/feature/devices/device_model.dart';
import 'package:sfm_app/bloc/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/permission/location_permission.dart';
import 'package:sfm_app/product/services/api_services.dart';
import '../../product/constant/enums/app_theme_enums.dart';
class MapScreen extends StatefulWidget {
const MapScreen({super.key});
@override
State<MapScreen> createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
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);
// Position? position;
// bool isAllowLocationPermission = false;
String themeMode = '';
@override
void initState() {
super.initState();
mapBloc = BlocProvider.of(context);
_loadIcons();
getAllMarkers();
clusterManager = _initClusterManager();
}
@override
void dispose() {
super.dispose();
_controller = Completer();
streamController.close();
}
void onMapCreated(GoogleMapController controller) {
_controller.complete(controller);
streamController.add(controller);
clusterManager.setMapId(controller.mapId);
checkTheme();
}
@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 StreamBuilder<String>(
stream: mapBloc.streamMapTheme,
builder: (context, mapThemeSnapshot) {
return GoogleMap(
initialCameraPosition: _myPosition,
// mapType: mapType,
onMapCreated: onMapCreated,
markers: markerSnapshot.data ?? markersAll
..addAll(markers),
zoomControlsEnabled: false,
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,
),
},
style: mapThemeSnapshot.data,
);
},
);
},
);
},
),
],
),
);
}
void checkTheme() async {
String theme = await apiServices.checkTheme();
if (theme == AppThemes.LIGHT.name) {
themeMode = '';
} else {
themeMode = await _getFileData('assets/map_themes/maps_dark_theme.json');
}
mapBloc.sinkMapTheme.add(themeMode);
}
Future<String> _getFileData(String path) async {
return rootBundle.loadString(path);
}
Future<void> _loadIcons() async {
List<Future<BitmapDescriptor>> iconFutures = imageAssets.map((asset) {
return BitmapDescriptor.asset(
const ImageConfiguration(size: Size(50, 50)), 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: () async {
bool check = await checkLocationPermission(context);
if (check == true) {
Position position = await Geolocator.getCurrentPosition();
onTapMarker(
// ignore: use_build_context_synchronously
context,
_controller,
mapBloc,
LatLng(position.latitude, position.longitude),
cluster.items,
imageAssets,
markers,
hospitalIcon,
fireStationIcon,
);
} else {
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Cannot get your Location")));
}
},
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;
}
}
if (hasStateOne) {
return true; // flameIcon
} else if (hasOtherState) {
return false; // normalIcon
} else {
return true; // offlineIcon
}
}
void _updateMarkers(Set<Marker> marker) {
log("Update Marker");
checkTheme();
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);
}
}
}
Future<bool> checkLocationPermission(context) async {
bool check = await LocationPermissionRequest.instance
.checkLocationPermission(context);
return check;
}
}