413 lines
16 KiB
Dart
413 lines
16 KiB
Dart
// ignore_for_file: use_build_context_synchronously
|
|
|
|
import 'dart:async';
|
|
import 'dart:developer';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|
import 'package:intl/intl.dart';
|
|
|
|
import '../product/services/api_services.dart';
|
|
import '../product/services/language_services.dart';
|
|
import '../product/shared/model/ward_model.dart';
|
|
import '../product/shared/shared_snack_bar.dart';
|
|
import '../product/utils/response_status_utils.dart';
|
|
import '../product/shared/model/district_model.dart';
|
|
import '../product/shared/model/province_model.dart';
|
|
import '../feature/devices/device_model.dart';
|
|
import '../product/base/bloc/base_bloc.dart';
|
|
|
|
class DeviceUpdateBloc extends BlocBase {
|
|
APIServices apiServices = APIServices();
|
|
|
|
final deviceInfo = StreamController<Device>.broadcast();
|
|
StreamSink<Device> get sinkDeviceInfo => deviceInfo.sink;
|
|
Stream<Device> get streamDeviceInfo => deviceInfo.stream;
|
|
|
|
// DeviceUpdateScreen
|
|
final isChanged = StreamController<bool>.broadcast();
|
|
StreamSink<bool> get sinkIsChanged => isChanged.sink;
|
|
Stream<bool> get streamIsChanged => isChanged.stream;
|
|
|
|
final provinceData = StreamController<Map<String, String>>.broadcast();
|
|
StreamSink<Map<String, String>> get sinkProvinceData => provinceData.sink;
|
|
Stream<Map<String, String>> get streamProvinceData => provinceData.stream;
|
|
|
|
final listProvinces =
|
|
StreamController<List<DropdownMenuItem<Province>>>.broadcast();
|
|
StreamSink<List<DropdownMenuItem<Province>>> get sinkListProvinces =>
|
|
listProvinces.sink;
|
|
Stream<List<DropdownMenuItem<Province>>> get streamListProvinces =>
|
|
listProvinces.stream;
|
|
|
|
final districtData = StreamController<Map<String, String>>.broadcast();
|
|
StreamSink<Map<String, String>> get sinkDistrictData => districtData.sink;
|
|
Stream<Map<String, String>> get streamDistrictData => districtData.stream;
|
|
|
|
final listDistricts =
|
|
StreamController<List<DropdownMenuItem<District>>>.broadcast();
|
|
StreamSink<List<DropdownMenuItem<District>>> get sinkListDistricts =>
|
|
listDistricts.sink;
|
|
Stream<List<DropdownMenuItem<District>>> get streamListDistricts =>
|
|
listDistricts.stream;
|
|
|
|
final wardData = StreamController<Map<String, String>>.broadcast();
|
|
StreamSink<Map<String, String>> get sinkWardData => wardData.sink;
|
|
Stream<Map<String, String>> get streamWardData => wardData.stream;
|
|
|
|
final listWards = StreamController<List<DropdownMenuItem<Ward>>>.broadcast();
|
|
StreamSink<List<DropdownMenuItem<Ward>>> get sinkListWards => listWards.sink;
|
|
Stream<List<DropdownMenuItem<Ward>>> get streamListWards => listWards.stream;
|
|
|
|
// Show Maps in DeviceUpdateScreen
|
|
|
|
final markers = StreamController<Set<Marker>>.broadcast();
|
|
StreamSink<Set<Marker>> get sinkMarkers => markers.sink;
|
|
Stream<Set<Marker>> get streamMarkers => markers.stream;
|
|
|
|
final searchLocation = StreamController<TextEditingController>.broadcast();
|
|
StreamSink<TextEditingController> get sinkSearchLocation =>
|
|
searchLocation.sink;
|
|
Stream<TextEditingController> get streamSearchLocation =>
|
|
searchLocation.stream;
|
|
|
|
@override
|
|
void dispose() {
|
|
// deviceInfo.done;
|
|
}
|
|
|
|
Future<void> getAllProvinces(BuildContext context) async {
|
|
List<DropdownMenuItem<Province>> provincesData = [];
|
|
provincesData.clear();
|
|
sinkListProvinces.add(provincesData);
|
|
await apiServices.execute(context, () async {
|
|
List<Province> provinces = await apiServices.getAllProvinces();
|
|
for (var province in provinces) {
|
|
provincesData.add(
|
|
DropdownMenuItem(value: province, child: Text(province.fullName!)));
|
|
}
|
|
sinkListProvinces.add(provincesData);
|
|
});
|
|
}
|
|
|
|
Future<void> getAllDistricts(BuildContext context, String provinceID) async {
|
|
List<DropdownMenuItem<District>> districtsData = [];
|
|
districtsData.clear();
|
|
sinkListDistricts.add(districtsData);
|
|
await apiServices.execute(context, () async {
|
|
final districts = await apiServices.getAllDistricts(provinceID);
|
|
for (var district in districts) {
|
|
districtsData.add(
|
|
DropdownMenuItem(value: district, child: Text(district.fullName!)));
|
|
}
|
|
sinkListDistricts.add(districtsData);
|
|
});
|
|
}
|
|
|
|
Future<void> getAllWards(BuildContext context, String districtID) async {
|
|
List<DropdownMenuItem<Ward>> wardsData = [];
|
|
wardsData.clear();
|
|
sinkListWards.add(wardsData);
|
|
await apiServices.execute(context, () async {
|
|
final wards = await apiServices.getAllWards(districtID);
|
|
for (var ward in wards) {
|
|
wardsData
|
|
.add(DropdownMenuItem(value: ward, child: Text(ward.fullName!)));
|
|
}
|
|
sinkListWards.add(wardsData);
|
|
});
|
|
}
|
|
|
|
Future<void> getDeviceInformation(
|
|
BuildContext context,
|
|
String thingID,
|
|
TextEditingController deviceNameController,
|
|
TextEditingController latitudeController,
|
|
TextEditingController longitudeController) async {
|
|
await apiServices.execute(context, () async {
|
|
Device device = await apiServices.getDeviceInformation(thingID);
|
|
sinkDeviceInfo.add(device);
|
|
deviceNameController.text = device.name ?? "";
|
|
latitudeController.text = device.settings!.latitude ?? "";
|
|
longitudeController.text = device.settings!.longitude ?? "";
|
|
|
|
if (device.areaPath != null && device.areaPath!.isNotEmpty) {
|
|
List<String> areaPath = device.areaPath!.split('_');
|
|
|
|
// Kiểm tra độ dài của areaPath
|
|
if (areaPath.length >= 3) {
|
|
String provinceCode = areaPath[0];
|
|
String districtCode = areaPath[1];
|
|
String wardCode = areaPath[2];
|
|
|
|
// Kiểm tra các mã có hợp lệ không (không rỗng)
|
|
if (provinceCode.isNotEmpty &&
|
|
districtCode.isNotEmpty &&
|
|
wardCode.isNotEmpty) {
|
|
try {
|
|
// Lấy danh sách districts và wards
|
|
await getAllDistricts(context, provinceCode);
|
|
await getAllWards(context, districtCode);
|
|
|
|
// Xử lý Province
|
|
try {
|
|
Province province =
|
|
await apiServices.getProvinceByID(provinceCode);
|
|
Map<String, String> provinceData = {
|
|
"name": province.fullName ?? "Unknown Province",
|
|
"code": province.code ?? provinceCode
|
|
};
|
|
sinkProvinceData.add(provinceData);
|
|
} catch (e) {
|
|
// Thêm dữ liệu mặc định khi lỗi
|
|
Map<String, String> provinceData = {
|
|
"name": "Error Loading Province",
|
|
"code": provinceCode
|
|
};
|
|
sinkProvinceData.add(provinceData);
|
|
if (!context.mounted) return;
|
|
showErrorTopSnackBarCustom(context, e.toString());
|
|
}
|
|
|
|
// Xử lý District
|
|
try {
|
|
District district =
|
|
await apiServices.getDistrictByID(districtCode);
|
|
Map<String, String> districData = {
|
|
"name": district.fullName ?? "Unknown District",
|
|
"code": district.code ?? districtCode,
|
|
};
|
|
sinkDistrictData.add(districData);
|
|
} catch (e) {
|
|
log("Lỗi khi lấy thông tin district ($districtCode): $e");
|
|
Map<String, String> districData = {
|
|
"name": "Error Loading District",
|
|
"code": districtCode,
|
|
};
|
|
sinkDistrictData.add(districData);
|
|
}
|
|
|
|
// Xử lý Ward
|
|
try {
|
|
Ward ward = await apiServices.getWardByID(wardCode);
|
|
Map<String, String> wardMap = {
|
|
"name": ward.fullName ?? "Unknown Ward",
|
|
"code": ward.code ?? wardCode,
|
|
};
|
|
sinkWardData.add(wardMap);
|
|
} catch (e) {
|
|
log("Lỗi khi lấy thông tin ward ($wardCode): $e");
|
|
Map<String, String> wardMap = {
|
|
"name": "Error Loading Ward",
|
|
"code": wardCode,
|
|
};
|
|
sinkWardData.add(wardMap);
|
|
}
|
|
} catch (e) {
|
|
log("Lỗi khi gọi getAllDistricts hoặc getAllWards: $e");
|
|
}
|
|
} else {
|
|
await getAllProvinces(context);
|
|
log("Một hoặc nhiều mã địa phương trống: Province: $provinceCode, District: $districtCode, Ward: $wardCode");
|
|
}
|
|
} else {
|
|
showNoIconTopSnackBar(
|
|
context,
|
|
"AreaPath không đủ thông tin: ${device.areaPath}",
|
|
Colors.orangeAccent,
|
|
Colors.white);
|
|
}
|
|
}
|
|
});
|
|
// try {
|
|
// Device device = await apiServices.getDeviceInformation(thingID);
|
|
// sinkDeviceInfo.add(device);
|
|
// deviceNameController.text = device.name ?? "";
|
|
// latitudeController.text = device.settings!.latitude ?? "";
|
|
// longitudeController.text = device.settings!.longitude ?? "";
|
|
|
|
// if (device.areaPath != null && device.areaPath!.isNotEmpty) {
|
|
// List<String> areaPath = device.areaPath!.split('_');
|
|
|
|
// // Kiểm tra độ dài của areaPath
|
|
// if (areaPath.length >= 3) {
|
|
// String provinceCode = areaPath[0];
|
|
// String districtCode = areaPath[1];
|
|
// String wardCode = areaPath[2];
|
|
|
|
// // Kiểm tra các mã có hợp lệ không (không rỗng)
|
|
// if (provinceCode.isNotEmpty &&
|
|
// districtCode.isNotEmpty &&
|
|
// wardCode.isNotEmpty) {
|
|
// try {
|
|
// // Lấy danh sách districts và wards
|
|
// await getAllDistricts(context, provinceCode);
|
|
// await getAllWards(context, districtCode);
|
|
|
|
// // Xử lý Province
|
|
// try {
|
|
// Province province =
|
|
// await apiServices.getProvinceByID(provinceCode);
|
|
// Map<String, String> provinceData = {
|
|
// "name": province.fullName ?? "Unknown Province",
|
|
// "code": province.code ?? provinceCode
|
|
// };
|
|
// sinkProvinceData.add(provinceData);
|
|
// } catch (e) {
|
|
// // Thêm dữ liệu mặc định khi lỗi
|
|
// Map<String, String> provinceData = {
|
|
// "name": "Error Loading Province",
|
|
// "code": provinceCode
|
|
// };
|
|
// sinkProvinceData.add(provinceData);
|
|
// if (!context.mounted) return;
|
|
// showErrorTopSnackBarCustom(context, e.toString());
|
|
// }
|
|
|
|
// // Xử lý District
|
|
// try {
|
|
// District district =
|
|
// await apiServices.getDistrictByID(districtCode);
|
|
// Map<String, String> districData = {
|
|
// "name": district.fullName ?? "Unknown District",
|
|
// "code": district.code ?? districtCode,
|
|
// };
|
|
// sinkDistrictData.add(districData);
|
|
// } catch (e) {
|
|
// log("Lỗi khi lấy thông tin district ($districtCode): $e");
|
|
// Map<String, String> districData = {
|
|
// "name": "Error Loading District",
|
|
// "code": districtCode,
|
|
// };
|
|
// sinkDistrictData.add(districData);
|
|
// }
|
|
|
|
// // Xử lý Ward
|
|
// try {
|
|
// Ward ward = await apiServices.getWardByID(wardCode);
|
|
// Map<String, String> wardMap = {
|
|
// "name": ward.fullName ?? "Unknown Ward",
|
|
// "code": ward.code ?? wardCode,
|
|
// };
|
|
// sinkWardData.add(wardMap);
|
|
// } catch (e) {
|
|
// print("Lỗi khi lấy thông tin ward ($wardCode): $e");
|
|
// Map<String, String> wardMap = {
|
|
// "name": "Error Loading Ward",
|
|
// "code": wardCode,
|
|
// };
|
|
// sinkWardData.add(wardMap);
|
|
// }
|
|
// } catch (e) {
|
|
// print("Lỗi khi gọi getAllDistricts hoặc getAllWards: $e");
|
|
// }
|
|
// } else {
|
|
// await getAllProvinces(context);
|
|
// print(
|
|
// "Một hoặc nhiều mã địa phương trống: Province: $provinceCode, District: $districtCode, Ward: $wardCode");
|
|
// }
|
|
// } else {
|
|
// showNoIconTopSnackBar(
|
|
// context,
|
|
// "AreaPath không đủ thông tin: ${device.areaPath}",
|
|
// Colors.orangeAccent,
|
|
// Colors.white);
|
|
// }
|
|
// }
|
|
// } catch (e) {
|
|
// showNoIconTopSnackBar(context, "Lỗi trong getDeviceInfomation: $e",
|
|
// Colors.orangeAccent, Colors.white);
|
|
// }
|
|
}
|
|
|
|
Future<Province> getProvinceByName(BuildContext context, String name) async {
|
|
return await apiServices.execute(context, () async {
|
|
List<Province> provinces = await apiServices.getProvincesByName(name);
|
|
if (provinces.isNotEmpty) {
|
|
return provinces[0];
|
|
} else {
|
|
return Province(name: "null");
|
|
}
|
|
});
|
|
}
|
|
|
|
Future<District> getDistrictByName(
|
|
BuildContext context, String name, String provinceCode) async {
|
|
return apiServices.execute(context, () async {
|
|
final districts = await apiServices.getDistrictsByName(name);
|
|
return districts.firstWhere(
|
|
(district) => district.provinceCode == provinceCode,
|
|
orElse: () => District(name: "null"),
|
|
);
|
|
});
|
|
}
|
|
|
|
Future<Ward> getWardByName(
|
|
BuildContext context, String name, String districtCode) async {
|
|
return apiServices.execute(context, () async {
|
|
final wards = await apiServices.getWardsByName(name);
|
|
return wards.firstWhere(
|
|
(ward) => ward.districtCode == districtCode,
|
|
orElse: () => Ward(name: "null"),
|
|
);
|
|
});
|
|
}
|
|
|
|
Future<void> updateDevice(
|
|
BuildContext context,
|
|
String thingID,
|
|
String name,
|
|
String latitude,
|
|
String longitude,
|
|
String provinceCode,
|
|
String districtCode,
|
|
String wardCode,
|
|
) async {
|
|
await apiServices.execute(context, () async {
|
|
DateTime dateTime = DateTime.now();
|
|
String formattedDateTime =
|
|
DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
|
|
Map<String, dynamic> body = {
|
|
"name": name,
|
|
"area_province": provinceCode,
|
|
"area_district": districtCode,
|
|
"area_ward": wardCode,
|
|
"latitude": latitude,
|
|
"longitude": longitude,
|
|
"note": "User updated device infomation at $formattedDateTime",
|
|
};
|
|
int statusCode = await apiServices.updateOwnerDevice(thingID, body);
|
|
showSnackBarResponseByStatusCodeNoIcon(
|
|
context,
|
|
statusCode,
|
|
appLocalization(context).notification_update_device_success,
|
|
appLocalization(context).notification_update_device_failed,
|
|
);
|
|
});
|
|
// try {
|
|
// DateTime dateTime = DateTime.now();
|
|
// String formattedDateTime =
|
|
// DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
|
|
// Map<String, dynamic> body = {
|
|
// "name": name,
|
|
// "area_province": provinceCode,
|
|
// "area_district": districtCode,
|
|
// "area_ward": wardCode,
|
|
// "latitude": latitude,
|
|
// "longitude": longitude,
|
|
// "note": "User updated device infomation at $formattedDateTime",
|
|
// };
|
|
// int statusCode = await apiServices.updateOwnerDevice(thingID, body);
|
|
// showSnackBarResponseByStatusCodeNoIcon(
|
|
// context,
|
|
// statusCode,
|
|
// appLocalization(context).notification_update_device_success,
|
|
// appLocalization(context).notification_update_device_failed,
|
|
// );
|
|
// } catch (e) {
|
|
// if (!context.mounted) return;
|
|
// showErrorTopSnackBarCustom(context, e.toString());
|
|
// }
|
|
}
|
|
}
|