Logging data
Try-catch function
This commit is contained in:
anhtunz
2025-06-17 16:43:45 +07:00
parent 22fef0e0a8
commit 2d53f2cdd3
41 changed files with 1591 additions and 1299 deletions

View File

@@ -36,6 +36,7 @@
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:showWhenLocked="true" android:showWhenLocked="true"
android:turnScreenOn="true" android:turnScreenOn="true"
android:enableOnBackInvokedCallback="true"
android:exported="true"> android:exported="true">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user

3
devtools_options.yaml Normal file
View File

@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:

View File

@@ -4,7 +4,6 @@ import '../product/base/bloc/base_bloc.dart';
import '../feature/bell/bell_model.dart'; import '../feature/bell/bell_model.dart';
class BellBloc extends BlocBase { class BellBloc extends BlocBase {
final bellItems = StreamController<List<BellItems>>.broadcast(); final bellItems = StreamController<List<BellItems>>.broadcast();
StreamSink<List<BellItems>> get sinkBellItems => bellItems.sink; StreamSink<List<BellItems>> get sinkBellItems => bellItems.sink;
Stream<List<BellItems>> get streamBellItems => bellItems.stream; Stream<List<BellItems>> get streamBellItems => bellItems.stream;

View File

@@ -1,20 +1,17 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:sfm_app/product/services/api_services.dart';
import 'package:sfm_app/product/utils/device_utils.dart';
import '../product/shared/shared_snack_bar.dart'; import '../product/services/api_services.dart';
import '../product/utils/date_time_utils.dart'; import '../product/utils/date_time_utils.dart';
import '../feature/device_log/device_logs_model.dart'; import '../feature/device_log/device_logs_model.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/utils/device_utils.dart';
class DetailDeviceBloc extends BlocBase { class DetailDeviceBloc extends BlocBase {
APIServices apiServices = APIServices(); APIServices apiServices = APIServices();
@@ -43,7 +40,7 @@ class DetailDeviceBloc extends BlocBase {
String thingID, String thingID,
Completer<GoogleMapController> controller, Completer<GoogleMapController> controller,
) async { ) async {
try { await apiServices.execute(context, () async {
Device device = await apiServices.getDeviceInformation(thingID); Device device = await apiServices.getDeviceInformation(thingID);
sinkDeviceInfo.add(device); sinkDeviceInfo.add(device);
if (device.areaPath != null) { if (device.areaPath != null) {
@@ -73,10 +70,41 @@ class DetailDeviceBloc extends BlocBase {
mapController mapController
.animateCamera(CameraUpdate.newCameraPosition(cameraPosition)); .animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
} }
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom(context, e.toString()); // Device device = await apiServices.getDeviceInformation(thingID);
} // sinkDeviceInfo.add(device);
// if (device.areaPath != null) {
// String fullLocation = await DeviceUtils.instance
// .getFullDeviceLocation(context, device.areaPath!, "");
// log("Location: $fullLocation");
// sinkDeviceLocation.add(fullLocation);
// }
// Map<String, dynamic> sensorMap = {};
// if (device.status!.sensors != null) {
// sensorMap = DeviceUtils.instance
// .getDeviceSensors(context, device.status!.sensors!);
// } else {
// sensorMap = DeviceUtils.instance.getDeviceSensors(context, []);
// }
// sinkDeviceSensor.add(sensorMap);
// if (device.settings!.latitude! != "" &&
// device.settings!.longitude! != "") {
// final CameraPosition cameraPosition = CameraPosition(
// target: LatLng(
// double.parse(device.settings!.latitude!),
// double.parse(device.settings!.longitude!),
// ),
// zoom: 13,
// );
// final GoogleMapController mapController = await controller.future;
// mapController
// .animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
// }
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
void findLocation(BuildContext context, String areaPath) async { void findLocation(BuildContext context, String areaPath) async {
@@ -85,12 +113,13 @@ class DetailDeviceBloc extends BlocBase {
sinkDeviceLocation.add(fullLocation); sinkDeviceLocation.add(fullLocation);
} }
void getNearerSensorValue(BuildContext context,String thingID) async { void getNearerSensorValue(BuildContext context, String thingID) async {
try { apiServices.execute(context, () async {
List<SensorLogs> sensorTemps = []; List<SensorLogs> sensorTemps = [];
DateTime twoDaysAgo = DateTime.now().subtract(const Duration(days: 2)); DateTime twoDaysAgo = DateTime.now().subtract(const Duration(days: 2));
String from = DateTimeUtils.instance.formatDateTimeToString(twoDaysAgo); String from = DateTimeUtils.instance.formatDateTimeToString(twoDaysAgo);
String now = DateTimeUtils.instance.formatDateTimeToString(DateTime.now()); String now =
DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
Map<String, dynamic> params = { Map<String, dynamic> params = {
'thing_id': thingID, 'thing_id': thingID,
'from': from, 'from': from,
@@ -98,7 +127,8 @@ class DetailDeviceBloc extends BlocBase {
'limit': '100', 'limit': '100',
'n': '7', 'n': '7',
}; };
DeviceLog devicesListLog = await apiServices.getLogsOfDevice(thingID, params); DeviceLog devicesListLog =
await apiServices.getLogsOfDevice(thingID, params);
if (devicesListLog.sensors!.isNotEmpty) { if (devicesListLog.sensors!.isNotEmpty) {
for (var sensor in devicesListLog.sensors!) { for (var sensor in devicesListLog.sensors!) {
sensorTemps.add(sensor); sensorTemps.add(sensor);
@@ -108,11 +138,35 @@ class DetailDeviceBloc extends BlocBase {
} else { } else {
sinkSensorTemps.add([]); sinkSensorTemps.add([]);
} }
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // List<SensorLogs> sensorTemps = [];
context, e.toString()); // DateTime twoDaysAgo = DateTime.now().subtract(const Duration(days: 2));
sinkSensorTemps.add([]); // String from = DateTimeUtils.instance.formatDateTimeToString(twoDaysAgo);
} // String now =
// DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
// Map<String, dynamic> params = {
// 'thing_id': thingID,
// 'from': from,
// 'to': now,
// 'limit': '100',
// 'n': '7',
// };
// DeviceLog devicesListLog =
// await apiServices.getLogsOfDevice(thingID, params);
// if (devicesListLog.sensors!.isNotEmpty) {
// for (var sensor in devicesListLog.sensors!) {
// sensorTemps.add(sensor);
// }
// sensorTemps = sensorTemps.reversed.toList();
// sinkSensorTemps.add(sensorTemps);
// } else {
// sinkSensorTemps.add([]);
// }
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// sinkSensorTemps.add([]);
// }
} }
} }

View File

@@ -1,13 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/constant/app/app_constants.dart'; import '../product/constant/app/app_constants.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../product/shared/shared_snack_bar.dart';
import '../product/utils/date_time_utils.dart'; import '../product/utils/date_time_utils.dart';
import '../product/utils/device_utils.dart'; import '../product/utils/device_utils.dart';
@@ -39,15 +36,12 @@ class DeviceLogsBloc extends BlocBase {
void dispose() {} void dispose() {}
void getAllDevices(BuildContext context) async { void getAllDevices(BuildContext context) async {
try { await apiServices.execute(context, () async {
List<Device> originalDevices = await apiServices.getOwnerDevices(); List<Device> originalDevices = await apiServices.getOwnerDevices();
List<Device> devices = List<Device> devices =
DeviceUtils.instance.sortDeviceByState(originalDevices); DeviceUtils.instance.sortDeviceByState(originalDevices);
sinkAllDevices.add(devices); sinkAllDevices.add(devices);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(context, e.toString());
}
} }
void getDeviceLogByThingID( void getDeviceLogByThingID(
@@ -57,7 +51,7 @@ class DeviceLogsBloc extends BlocBase {
DateTime fromDate, DateTime fromDate,
List<SensorLogs> sensors, List<SensorLogs> sensors,
) async { ) async {
try { await apiServices.execute(context, () async {
sinkmessage.add(ApplicationConstants.LOADING); sinkmessage.add(ApplicationConstants.LOADING);
String fromDateString = String fromDateString =
DateTimeUtils.instance.formatDateTimeToString(fromDate); DateTimeUtils.instance.formatDateTimeToString(fromDate);
@@ -85,9 +79,38 @@ class DeviceLogsBloc extends BlocBase {
sinkmessage.add(ApplicationConstants.NO_DATA); sinkmessage.add(ApplicationConstants.NO_DATA);
} }
sinkSensors.add(sensors); sinkSensors.add(sensors);
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom(context, e.toString()); // sinkmessage.add(ApplicationConstants.LOADING);
} // String fromDateString =
// DateTimeUtils.instance.formatDateTimeToString(fromDate);
// String now =
// DateTimeUtils.instance.formatDateTimeToString(DateTime.now());
// Map<String, dynamic> params = {
// 'thing_id': thingID,
// 'from': fromDateString,
// 'to': now,
// 'limit': '30',
// "offset": offset.toString(),
// "asc": "true"
// };
// DeviceLog devicesListLog =
// await apiServices.getLogsOfDevice(thingID, params);
// if (devicesListLog.sensors!.isEmpty) {
// bool hasMore = false;
// sinkHasMore.add(hasMore);
// }
// if (devicesListLog.sensors!.isNotEmpty) {
// for (var sensor in devicesListLog.sensors!) {
// sensors.add(sensor);
// }
// } else {
// sinkmessage.add(ApplicationConstants.NO_DATA);
// }
// sinkSensors.add(sensors);
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
} }

View File

@@ -36,7 +36,6 @@ class DeviceNotificationSettingsBloc extends BlocBase {
StreamSink<String> get sinkMessageChange => messageChange.sink; StreamSink<String> get sinkMessageChange => messageChange.sink;
Stream<String> get streaMmessageChange => messageChange.stream; Stream<String> get streaMmessageChange => messageChange.stream;
@override @override
void dispose() {} void dispose() {}
} }

View File

@@ -1,17 +1,17 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../product/services/language_services.dart'; import '../product/services/language_services.dart';
import '../product/shared/model/ward_model.dart'; import '../product/shared/model/ward_model.dart';
import '../product/shared/shared_snack_bar.dart'; import '../product/shared/shared_snack_bar.dart';
import '../product/utils/response_status_utils.dart'; import '../product/utils/response_status_utils.dart';
import '../product/shared/model/district_model.dart'; import '../product/shared/model/district_model.dart';
import '../product/shared/model/province_model.dart'; import '../product/shared/model/province_model.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
@@ -80,56 +80,42 @@ class DeviceUpdateBloc extends BlocBase {
List<DropdownMenuItem<Province>> provincesData = []; List<DropdownMenuItem<Province>> provincesData = [];
provincesData.clear(); provincesData.clear();
sinkListProvinces.add(provincesData); sinkListProvinces.add(provincesData);
try { await apiServices.execute(context, () async {
List<Province> provinces = await apiServices.getAllProvinces(); List<Province> provinces = await apiServices.getAllProvinces();
for (var province in provinces) { for (var province in provinces) {
provincesData.add( provincesData.add(
DropdownMenuItem(value: province, child: Text(province.fullName!))); DropdownMenuItem(value: province, child: Text(province.fullName!)));
} }
sinkListProvinces.add(provincesData); sinkListProvinces.add(provincesData);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
Future<void> getAllDistricts(BuildContext context, String provinceID) async { Future<void> getAllDistricts(BuildContext context, String provinceID) async {
List<DropdownMenuItem<District>> districtsData = []; List<DropdownMenuItem<District>> districtsData = [];
districtsData.clear(); districtsData.clear();
sinkListDistricts.add(districtsData); sinkListDistricts.add(districtsData);
try { await apiServices.execute(context, () async {
final districts = await apiServices.getAllDistricts(provinceID); final districts = await apiServices.getAllDistricts(provinceID);
for (var district in districts) { for (var district in districts) {
districtsData.add( districtsData.add(
DropdownMenuItem(value: district, child: Text(district.fullName!))); DropdownMenuItem(value: district, child: Text(district.fullName!)));
} }
sinkListDistricts.add(districtsData); sinkListDistricts.add(districtsData);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
Future<void> getAllWards(BuildContext context, String districtID) async { Future<void> getAllWards(BuildContext context, String districtID) async {
List<DropdownMenuItem<Ward>> wardsData = []; List<DropdownMenuItem<Ward>> wardsData = [];
wardsData.clear(); wardsData.clear();
sinkListWards.add(wardsData); sinkListWards.add(wardsData);
try { await apiServices.execute(context, () async {
final wards = await apiServices.getAllWards(districtID); final wards = await apiServices.getAllWards(districtID);
for (var ward in wards) { for (var ward in wards) {
wardsData.add(DropdownMenuItem(value: ward, child: Text(ward.fullName!))); wardsData
.add(DropdownMenuItem(value: ward, child: Text(ward.fullName!)));
} }
sinkListWards.add(wardsData); sinkListWards.add(wardsData);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
Future<void> getDeviceInformation( Future<void> getDeviceInformation(
@@ -138,7 +124,7 @@ class DeviceUpdateBloc extends BlocBase {
TextEditingController deviceNameController, TextEditingController deviceNameController,
TextEditingController latitudeController, TextEditingController latitudeController,
TextEditingController longitudeController) async { TextEditingController longitudeController) async {
try { await apiServices.execute(context, () async {
Device device = await apiServices.getDeviceInformation(thingID); Device device = await apiServices.getDeviceInformation(thingID);
sinkDeviceInfo.add(device); sinkDeviceInfo.add(device);
deviceNameController.text = device.name ?? ""; deviceNameController.text = device.name ?? "";
@@ -155,23 +141,24 @@ class DeviceUpdateBloc extends BlocBase {
String wardCode = areaPath[2]; String wardCode = areaPath[2];
// Kiểm tra các mã có hợp lệ không (không rỗng) // Kiểm tra các mã có hợp lệ không (không rỗng)
if (provinceCode.isNotEmpty && districtCode.isNotEmpty && wardCode.isNotEmpty) { if (provinceCode.isNotEmpty &&
districtCode.isNotEmpty &&
wardCode.isNotEmpty) {
try { try {
// Lấy danh sách districts và wards // Lấy danh sách districts và wards
await getAllDistricts(context,provinceCode); await getAllDistricts(context, provinceCode);
await getAllWards(context,districtCode); await getAllWards(context, districtCode);
// Xử lý Province // Xử lý Province
try { try {
Province province = await apiServices.getProvinceByID(provinceCode); Province province =
await apiServices.getProvinceByID(provinceCode);
Map<String, String> provinceData = { Map<String, String> provinceData = {
"name": province.fullName ?? "Unknown Province", "name": province.fullName ?? "Unknown Province",
"code": province.code ?? provinceCode "code": province.code ?? provinceCode
}; };
sinkProvinceData.add(provinceData); sinkProvinceData.add(provinceData);
} catch (e) { } catch (e) {
// Thêm dữ liệu mặc định khi lỗi // Thêm dữ liệu mặc định khi lỗi
Map<String, String> provinceData = { Map<String, String> provinceData = {
"name": "Error Loading Province", "name": "Error Loading Province",
@@ -179,20 +166,20 @@ class DeviceUpdateBloc extends BlocBase {
}; };
sinkProvinceData.add(provinceData); sinkProvinceData.add(provinceData);
if (!context.mounted) return; if (!context.mounted) return;
showErrorTopSnackBarCustom( showErrorTopSnackBarCustom(context, e.toString());
context, e.toString());
} }
// Xử lý District // Xử lý District
try { try {
District district = await apiServices.getDistrictByID(districtCode); District district =
await apiServices.getDistrictByID(districtCode);
Map<String, String> districData = { Map<String, String> districData = {
"name": district.fullName ?? "Unknown District", "name": district.fullName ?? "Unknown District",
"code": district.code ?? districtCode, "code": district.code ?? districtCode,
}; };
sinkDistrictData.add(districData); sinkDistrictData.add(districData);
} catch (e) { } catch (e) {
print("Lỗi khi lấy thông tin district ($districtCode): $e"); log("Lỗi khi lấy thông tin district ($districtCode): $e");
Map<String, String> districData = { Map<String, String> districData = {
"name": "Error Loading District", "name": "Error Loading District",
"code": districtCode, "code": districtCode,
@@ -209,77 +196,161 @@ class DeviceUpdateBloc extends BlocBase {
}; };
sinkWardData.add(wardMap); sinkWardData.add(wardMap);
} catch (e) { } catch (e) {
print("Lỗi khi lấy thông tin ward ($wardCode): $e"); log("Lỗi khi lấy thông tin ward ($wardCode): $e");
Map<String, String> wardMap = { Map<String, String> wardMap = {
"name": "Error Loading Ward", "name": "Error Loading Ward",
"code": wardCode, "code": wardCode,
}; };
sinkWardData.add(wardMap); sinkWardData.add(wardMap);
} }
} catch (e) { } catch (e) {
print("Lỗi khi gọi getAllDistricts hoặc getAllWards: $e"); log("Lỗi khi gọi getAllDistricts hoặc getAllWards: $e");
} }
} else { } else {
await getAllProvinces(context); await getAllProvinces(context);
print("Một hoặc nhiều mã địa phương trống: Province: $provinceCode, District: $districtCode, Ward: $wardCode"); log("Một hoặc nhiều mã địa phương trống: Province: $provinceCode, District: $districtCode, Ward: $wardCode");
} }
} else { } else {
showNoIconTopSnackBar(context,"AreaPath không đủ thông tin: ${device.areaPath}",Colors.orangeAccent, Colors.white); 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); // 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 { Future<Province> getProvinceByName(BuildContext context, String name) async {
try { return await apiServices.execute(context, () async {
List<Province> provinces = await apiServices.getProvincesByName(name); List<Province> provinces = await apiServices.getProvincesByName(name);
if (provinces.isNotEmpty) { if (provinces.isNotEmpty) {
return provinces[0]; return provinces[0];
} else { } else {
return Province(name: "null"); return Province(name: "null");
} }
} catch (e) { });
if (context.mounted) {
showErrorTopSnackBarCustom(context, e.toString());
} }
return Province(name: "null");
}
}
Future<District> getDistrictByName( Future<District> getDistrictByName(
BuildContext context, String name, String provinceCode) async { BuildContext context, String name, String provinceCode) async {
try { return apiServices.execute(context, () async {
final districts = await apiServices.getDistrictsByName(name); final districts = await apiServices.getDistrictsByName(name);
return districts.firstWhere( return districts.firstWhere(
(district) => district.provinceCode == provinceCode, (district) => district.provinceCode == provinceCode,
orElse: () => District(name: "null"), orElse: () => District(name: "null"),
); );
} catch (e) { });
if (context.mounted) {
showErrorTopSnackBarCustom(context, e.toString());
}
return District(name: "null");
}
} }
Future<Ward> getWardByName( Future<Ward> getWardByName(
BuildContext context, String name, String districtCode) async { BuildContext context, String name, String districtCode) async {
try { return apiServices.execute(context, () async {
final wards = await apiServices.getWardsByName(name); final wards = await apiServices.getWardsByName(name);
return wards.firstWhere( return wards.firstWhere(
(ward) => ward.districtCode == districtCode, (ward) => ward.districtCode == districtCode,
orElse: () => Ward(name: "null"), orElse: () => Ward(name: "null"),
); );
} catch (e) { });
if (context.mounted) {
showErrorTopSnackBarCustom(context, e.toString());
}
return Ward(name: "null");
}
} }
Future<void> updateDevice( Future<void> updateDevice(
@@ -292,7 +363,7 @@ class DeviceUpdateBloc extends BlocBase {
String districtCode, String districtCode,
String wardCode, String wardCode,
) async { ) async {
try { await apiServices.execute(context, () async {
DateTime dateTime = DateTime.now(); DateTime dateTime = DateTime.now();
String formattedDateTime = String formattedDateTime =
DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime); DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
@@ -312,11 +383,30 @@ class DeviceUpdateBloc extends BlocBase {
appLocalization(context).notification_update_device_success, appLocalization(context).notification_update_device_success,
appLocalization(context).notification_update_device_failed, appLocalization(context).notification_update_device_failed,
); );
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // DateTime dateTime = DateTime.now();
context, e.toString()); // 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());
// }
} }
} }

View File

@@ -1,13 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/constant/app/app_constants.dart'; import '../product/constant/app/app_constants.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../product/shared/shared_snack_bar.dart'; import '../product/shared/shared_snack_bar.dart';
import '../product/utils/device_utils.dart'; import '../product/utils/device_utils.dart';
@@ -76,7 +73,7 @@ class DevicesManagerBloc extends BlocBase {
// } // }
// } // }
void getDeviceByState(BuildContext context,int state) async { void getDeviceByState(BuildContext context, int state) async {
try { try {
sinkTagStates.add([state]); sinkTagStates.add([state]);
@@ -91,16 +88,16 @@ class DevicesManagerBloc extends BlocBase {
List<Device> devices = []; List<Device> devices = [];
List<Device> originalDevices = []; List<Device> originalDevices = [];
if (state != -2) { if (state != -2) {
originalDevices = originalDevices = await apiServices
await apiServices.getOwnerDeviceByState({"state": state.toString()}); .getOwnerDeviceByState({"state": state.toString()});
} else { } else {
originalDevices = await apiServices.getOwnerDevices(); originalDevices = await apiServices.getOwnerDevices();
} }
List<Device> publicDevices = []; List<Device> publicDevices = [];
for(var device in originalDevices){ for (var device in originalDevices) {
if(device.visibility == "PUBLIC"){ if (device.visibility == "PUBLIC") {
publicDevices.add(device); publicDevices.add(device);
} }
} }
@@ -119,10 +116,8 @@ class DevicesManagerBloc extends BlocBase {
sinkAllDevices.add(devices); sinkAllDevices.add(devices);
} catch (e) { } catch (e) {
if (!context.mounted) return; if (!context.mounted) return;
showErrorTopSnackBarCustom( showErrorTopSnackBarCustom(context, e.toString());
context, e.toString());
} }
} }
String _getStateKey(int state) { String _getStateKey(int state) {

View File

@@ -1,16 +1,13 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../product/services/language_services.dart'; import '../product/services/language_services.dart';
import '../product/shared/shared_snack_bar.dart';
import '../product/utils/response_status_utils.dart'; import '../product/utils/response_status_utils.dart';
import '../feature/inter_family/group_detail/group_detail_model.dart'; import '../feature/inter_family/group_detail/group_detail_model.dart';
class DetailGroupBloc extends BlocBase { class DetailGroupBloc extends BlocBase {
@@ -30,8 +27,8 @@ class DetailGroupBloc extends BlocBase {
@override @override
void dispose() {} void dispose() {}
Future<void> getGroupDetail(BuildContext context,String groupID) async { Future<void> getGroupDetail(BuildContext context, String groupID) async {
try { await apiServices.execute(context, () async {
List<DeviceOfGroup> warningDevices = []; List<DeviceOfGroup> warningDevices = [];
GroupDetail group = await apiServices.getGroupDetail(groupID); GroupDetail group = await apiServices.getGroupDetail(groupID);
sinkDetailGroup.add(group); sinkDetailGroup.add(group);
@@ -43,73 +40,104 @@ class DetailGroupBloc extends BlocBase {
} }
sinkWarningDevice.add(warningDevices); sinkWarningDevice.add(warningDevices);
} }
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // List<DeviceOfGroup> warningDevices = [];
context, e.toString()); // GroupDetail group = await apiServices.getGroupDetail(groupID);
} // sinkDetailGroup.add(group);
// if (group.devices != null) {
// for (var device in group.devices!) {
// if (device.state == 1) {
// warningDevices.add(device);
// }
// }
// sinkWarningDevice.add(warningDevices);
// }
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
Future<void> approveUserToGroup(BuildContext context, String groupID, Future<void> approveUserToGroup(BuildContext context, String groupID,
String userID, String userName) async { String userID, String userName) async {
try { await apiServices.execute(context, () async {
Map<String, dynamic> body = {"group_id": groupID, "user_id": userID}; Map<String, dynamic> body = {"group_id": groupID, "user_id": userID};
int statusCode = await apiServices.approveGroup(body); int statusCode = await apiServices.approveGroup(body);
showSnackBarResponseByStatusCode(context, statusCode, showSnackBarResponseByStatusCode(context, statusCode,
"Đã duyệt $userName vào nhóm!", "Duyệt $userName thất bại!"); "Đã duyệt $userName vào nhóm!", "Duyệt $userName thất bại!");
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // Map<String, dynamic> body = {"group_id": groupID, "user_id": userID};
context, e.toString()); // int statusCode = await apiServices.approveGroup(body);
} // showSnackBarResponseByStatusCode(context, statusCode,
// "Đã duyệt $userName vào nhóm!", "Duyệt $userName thất bại!");
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
Future<void> deleteOrUnapproveUser(BuildContext context, String groupID, Future<void> deleteOrUnapproveUser(BuildContext context, String groupID,
String userID, String userName) async { String userID, String userName) async {
try { await apiServices.execute(context, () async {
int statusCode = await apiServices.deleteUserInGroup(groupID, userID); int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
showSnackBarResponseByStatusCode(context, statusCode, showSnackBarResponseByStatusCode(context, statusCode,
"Đã xóa người dùng $userName", "Xóa người dùng $userName thất bại"); "Đã xóa người dùng $userName", "Xóa người dùng $userName thất bại");
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
context, e.toString()); // showSnackBarResponseByStatusCode(context, statusCode,
} // "Đã xóa người dùng $userName", "Xóa người dùng $userName thất bại");
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
Future<void> deleteDevice(BuildContext context, String groupID, Future<void> deleteDevice(BuildContext context, String groupID,
String thingID, String deviceName) async { String thingID, String deviceName) async {
try { await apiServices.execute(context, () async {
int statusCode = await apiServices.deleteDeviceInGroup(groupID, thingID); int statusCode = await apiServices.deleteDeviceInGroup(groupID, thingID);
showSnackBarResponseByStatusCode(context, statusCode, showSnackBarResponseByStatusCode(context, statusCode,
"Đã xóa thiết bị $deviceName", "Xóa thiết bị $deviceName thất bại"); "Đã xóa thiết bị $deviceName", "Xóa thiết bị $deviceName thất bại");
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // int statusCode = await apiServices.deleteDeviceInGroup(groupID, thingID);
context, e.toString()); // showSnackBarResponseByStatusCode(context, statusCode,
} // "Đã xóa thiết bị $deviceName", "Xóa thiết bị $deviceName thất bại");
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
Future<void> leaveGroup( Future<void> leaveGroup(
BuildContext context, String groupID, String userID) async { BuildContext context, String groupID, String userID) async {
try { await apiServices.execute(context, () async {
int statusCode = await apiServices.deleteUserInGroup(groupID, userID); int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
context, context,
statusCode, statusCode,
appLocalization(context).notification_leave_group_success, appLocalization(context).notification_leave_group_success,
appLocalization(context).notification_leave_group_failed); appLocalization(context).notification_leave_group_failed);
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // int statusCode = await apiServices.deleteUserInGroup(groupID, userID);
context, e.toString()); // showSnackBarResponseByStatusCode(
} // context,
// statusCode,
// appLocalization(context).notification_leave_group_success,
// appLocalization(context).notification_leave_group_failed);
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
Future<void> updateDeviceNameInGroup( Future<void> updateDeviceNameInGroup(
BuildContext context, String thingID, String newAlias) async { BuildContext context, String thingID, String newAlias) async {
try { await apiServices.execute(context, () async {
Map<String, dynamic> body = {"thing_id": thingID, "alias": newAlias}; Map<String, dynamic> body = {"thing_id": thingID, "alias": newAlias};
int statusCode = await apiServices.updateDeviceAlias(body); int statusCode = await apiServices.updateDeviceAlias(body);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
@@ -118,26 +146,29 @@ class DetailGroupBloc extends BlocBase {
appLocalization(context).notification_update_device_success, appLocalization(context).notification_update_device_success,
appLocalization(context).notification_update_device_failed, appLocalization(context).notification_update_device_failed,
); );
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // Map<String, dynamic> body = {"thing_id": thingID, "alias": newAlias};
context, e.toString()); // int statusCode = await apiServices.updateDeviceAlias(body);
} // showSnackBarResponseByStatusCode(
// context,
// statusCode,
// appLocalization(context).notification_update_device_success,
// appLocalization(context).notification_update_device_failed,
// );
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
Future<List<Device>> getOwnerDevices(BuildContext context) async { Future<List<Device>> getOwnerDevices(BuildContext context) {
List<Device> allDevices = []; return apiServices.execute(context, () async {
try {
final originalDevices = await apiServices.getOwnerDevices(); final originalDevices = await apiServices.getOwnerDevices();
allDevices = originalDevices.where((device) => device.visibility == "PUBLIC").toList(); return originalDevices
.where((device) => device.visibility == "PUBLIC")
return allDevices; .toList();
} catch (e) { });
if (context.mounted) {
showErrorTopSnackBarCustom(context, e.toString());
}
return allDevices;
}
} }
Future<void> addDeviceToGroup( Future<void> addDeviceToGroup(
@@ -145,7 +176,7 @@ class DetailGroupBloc extends BlocBase {
Map<String, dynamic> body = { Map<String, dynamic> body = {
"thing_id": thingID, "thing_id": thingID,
}; };
try { await apiServices.execute(context, () async {
int statusCode = await apiServices.addDeviceToGroup(groupID, body); int statusCode = await apiServices.addDeviceToGroup(groupID, body);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
context, context,
@@ -153,10 +184,18 @@ class DetailGroupBloc extends BlocBase {
appLocalization(context).notification_add_device_success, appLocalization(context).notification_add_device_success,
appLocalization(context).notification_add_device_failed, appLocalization(context).notification_add_device_failed,
); );
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // int statusCode = await apiServices.addDeviceToGroup(groupID, body);
context, e.toString()); // showSnackBarResponseByStatusCode(
} // context,
// statusCode,
// appLocalization(context).notification_add_device_success,
// appLocalization(context).notification_add_device_failed,
// );
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
} }

View File

@@ -5,18 +5,19 @@ import '../feature/home/device_alias_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
class HomeBloc extends BlocBase { class HomeBloc extends BlocBase {
final allDevicesAliasMap =
final allDevicesAliasMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast(); StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasMap => StreamSink<Map<String, List<DeviceWithAlias>>> get sinkAllDevicesAliasMap =>
allDevicesAliasMap.sink; allDevicesAliasMap.sink;
Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasMap => Stream<Map<String, List<DeviceWithAlias>>> get streamAllDevicesAliasMap =>
allDevicesAliasMap.stream; allDevicesAliasMap.stream;
final allDevicesAliasJoinedMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast(); final allDevicesAliasJoinedMap =
StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasJoinedMap => StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
allDevicesAliasJoinedMap.sink; StreamSink<Map<String, List<DeviceWithAlias>>>
Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasJoinedMap => get sinkAllDevicesAliasJoinedMap => allDevicesAliasJoinedMap.sink;
allDevicesAliasJoinedMap.stream; Stream<Map<String, List<DeviceWithAlias>>>
get streamAllDevicesAliasJoinedMap => allDevicesAliasJoinedMap.stream;
final countNotification = StreamController<int>.broadcast(); final countNotification = StreamController<int>.broadcast();
StreamSink<int> get sinkCountNotification => countNotification.sink; StreamSink<int> get sinkCountNotification => countNotification.sink;
@@ -28,11 +29,17 @@ class HomeBloc extends BlocBase {
final ownerDevicesStatus = final ownerDevicesStatus =
StreamController<Map<String, List<DeviceWithAlias>>>.broadcast(); StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
StreamSink<Map<String, List<DeviceWithAlias>>> StreamSink<Map<String, List<DeviceWithAlias>>> get sinkOwnerDevicesStatus =>
get sinkOwnerDevicesStatus => ownerDevicesStatus.sink; ownerDevicesStatus.sink;
Stream<Map<String, List<DeviceWithAlias>>> get streamOwnerDevicesStatus => Stream<Map<String, List<DeviceWithAlias>>> get streamOwnerDevicesStatus =>
ownerDevicesStatus.stream; ownerDevicesStatus.stream;
@override @override
void dispose() {} void dispose() {
allDevicesAliasMap.close();
allDevicesAliasJoinedMap.close();
countNotification.close();
hasJoinedDevice.close();
ownerDevicesStatus.close();
}
} }

View File

@@ -1,16 +1,13 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../product/constant/app/app_constants.dart';
import '../product/constant/app/app_constants.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/services/language_services.dart'; import '../product/services/language_services.dart';
import '../product/shared/shared_snack_bar.dart';
import '../product/utils/response_status_utils.dart'; import '../product/utils/response_status_utils.dart';
import '../feature/inter_family/groups/groups_model.dart'; import '../feature/inter_family/groups/groups_model.dart';
@@ -36,10 +33,10 @@ class InterFamilyBloc extends BlocBase {
@override @override
void dispose() {} void dispose() {}
void getAllGroup(String role) async { void getAllGroup(BuildContext context, String role) async {
List<Group> groups = []; List<Group> groups = [];
sinkCurrentGroups.add(groups); sinkCurrentGroups.add(groups);
try { await apiServices.execute(context, () async {
groups = await apiServices.getAllGroups(); groups = await apiServices.getAllGroups();
groups = sortGroupByName(groups); groups = sortGroupByName(groups);
@@ -55,19 +52,13 @@ class InterFamilyBloc extends BlocBase {
return false; return false;
}, },
).toList(); ).toList();
sinkCurrentGroups.add(currentGroups); sinkCurrentGroups.add(currentGroups);
} catch (e) { });
// Xử lý lỗi khi jsonDecode thất bại
log("Error decoding JSON: $e");
sinkCurrentGroups.add([]);
}
log("Inter Family Role: $role");
} }
Future<void> createGroup( Future<void> createGroup(
BuildContext context, String name, String description) async { BuildContext context, String name, String description) async {
try { await apiServices.execute(context, () async {
Map<String, dynamic> body = {"name": name, "description": description}; Map<String, dynamic> body = {"name": name, "description": description};
int? statusCode = await apiServices.createGroup(body); int? statusCode = await apiServices.createGroup(body);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
@@ -75,17 +66,12 @@ class InterFamilyBloc extends BlocBase {
statusCode, statusCode,
appLocalization(context).notification_add_group_success, appLocalization(context).notification_add_group_success,
appLocalization(context).notification_add_group_failed); appLocalization(context).notification_add_group_failed);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
Future<void> changeGroupInformation(BuildContext context, String groupID, Future<void> changeGroupInformation(BuildContext context, String groupID,
String name, String description) async { String name, String description) async {
try { await apiServices.execute(context, () async {
Map<String, dynamic> body = {"name": name, "description": description}; Map<String, dynamic> body = {"name": name, "description": description};
int statusCode = await apiServices.updateGroup(body, groupID); int statusCode = await apiServices.updateGroup(body, groupID);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
@@ -93,44 +79,32 @@ class InterFamilyBloc extends BlocBase {
statusCode, statusCode,
appLocalization(context).notification_update_group_success, appLocalization(context).notification_update_group_success,
appLocalization(context).notification_update_group_failed); appLocalization(context).notification_update_group_failed);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
Future<void> joinGroup(BuildContext context, String groupID) async { Future<void> joinGroup(BuildContext context, String groupID) async {
try {
Map<String, dynamic> body = { Map<String, dynamic> body = {
"group_id": groupID, "group_id": groupID,
}; };
await apiServices.execute(context, () async {
int statusCode = await apiServices.joinGroup(groupID, body); int statusCode = await apiServices.joinGroup(groupID, body);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
context, context,
statusCode, statusCode,
appLocalization(context).notification_join_request_group_success, appLocalization(context).notification_join_request_group_success,
appLocalization(context).notification_join_request_group_failed); appLocalization(context).notification_join_request_group_failed);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
Future<void> deleteGroup(BuildContext context, String groupID) async { Future<void> deleteGroup(BuildContext context, String groupID) async {
try { await apiServices.execute(context, () async {
int statusCode = await apiServices.deleteGroup(groupID); int statusCode = await apiServices.deleteGroup(groupID);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
context, context,
statusCode, statusCode,
appLocalization(context).notification_delete_group_success, appLocalization(context).notification_delete_group_success,
appLocalization(context).notification_delete_group_failed); appLocalization(context).notification_delete_group_failed);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
List<Group> sortGroupByName(List<Group> groups) { List<Group> sortGroupByName(List<Group> groups) {

View File

@@ -1,18 +1,15 @@
import 'dart:async'; import 'dart:async';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
class LoginBloc extends BlocBase{ class LoginBloc extends BlocBase {
final loginRequest = StreamController<Map<String, dynamic>>.broadcast();
final loginRequest = StreamController<Map<String,dynamic>>.broadcast(); StreamSink<Map<String, dynamic>> get sinkLoginRequest => loginRequest.sink;
StreamSink<Map<String,dynamic>> get sinkLoginRequest => loginRequest.sink; Stream<Map<String, dynamic>> get streamLoginRequest => loginRequest.stream;
Stream<Map<String,dynamic>> get streamLoginRequest => loginRequest.stream;
final isShowPassword = StreamController<bool>.broadcast(); final isShowPassword = StreamController<bool>.broadcast();
StreamSink<bool> get sinkIsShowPassword => isShowPassword.sink; StreamSink<bool> get sinkIsShowPassword => isShowPassword.sink;
Stream<bool> get streamIsShowPassword => isShowPassword.stream; Stream<bool> get streamIsShowPassword => isShowPassword.stream;
@override @override
void dispose() { void dispose() {}
}
} }

View File

@@ -1,18 +1,16 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/cache/local_manager.dart';
import 'package:sfm_app/product/constant/app/api_path_constant.dart'; import '../product/cache/local_manager.dart';
import 'package:sfm_app/product/constant/enums/local_keys_enums.dart'; import '../product/constant/app/api_path_constant.dart';
import 'package:sfm_app/product/network/network_manager.dart'; import '../product/constant/enums/local_keys_enums.dart';
import '../product/network/network_manager.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/services/api_services.dart'; import '../product/services/api_services.dart';
import '../feature/bell/bell_model.dart'; import '../feature/bell/bell_model.dart';
import '../feature/settings/profile/profile_model.dart'; import '../feature/settings/profile/profile_model.dart';
import '../product/shared/shared_snack_bar.dart';
class MainBloc extends BlocBase { class MainBloc extends BlocBase {
APIServices apiServices = APIServices(); APIServices apiServices = APIServices();
@@ -44,19 +42,13 @@ class MainBloc extends BlocBase {
void dispose() {} void dispose() {}
void getUserProfile(BuildContext context) async { void getUserProfile(BuildContext context) async {
try { await apiServices.execute(context, () async {
User user = await apiServices.getUserDetail(); User user = await apiServices.getUserDetail();
sinkUserProfile.add(user); sinkUserProfile.add(user);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
getFCMTokenAndPresentations() async { getFCMTokenAndPresentations() async {
String? firebaseAppToken = await FirebaseMessaging.instance.getToken(); String? firebaseAppToken = await FirebaseMessaging.instance.getToken();
if (firebaseAppToken != null) { if (firebaseAppToken != null) {
@@ -67,14 +59,11 @@ class MainBloc extends BlocBase {
} }
} }
Future<int> sendNotificationToken(String token) async{ Future<int> sendNotificationToken(String token) async {
String uid = await getUID(); String uid = await getUID();
Map<String,dynamic> body = { Map<String, dynamic> body = {"user_id": uid, "app_token": token};
"user_id": uid, int statusCode = await NetworkManager.instance!
"app_token": token .updateDataInServer(APIPathConstants.NOTIFICATION_TOKEN_PATH, body);
};
int statusCode = await NetworkManager.instance!.updateDataInServer(
APIPathConstants.NOTIFICATION_TOKEN_PATH, body);
return statusCode; return statusCode;
} }

View File

@@ -1,9 +1,9 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../product/services/map_services.dart'; import '../product/services/map_services.dart';
import '../product/shared/shared_snack_bar.dart'; import '../product/shared/shared_snack_bar.dart';
import '../feature/devices/device_model.dart'; import '../feature/devices/device_model.dart';
@@ -75,6 +75,4 @@ class MapBloc extends BlocBase {
context, "Không tìm thấy đường", Colors.orange, Colors.white); context, "Không tìm thấy đường", Colors.orange, Colors.white);
} }
} }
} }

View File

@@ -1,11 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:sfm_app/product/services/api_services.dart';
import '../product/services/api_services.dart';
import '../feature/settings/profile/profile_model.dart'; import '../feature/settings/profile/profile_model.dart';
import '../product/base/bloc/base_bloc.dart'; import '../product/base/bloc/base_bloc.dart';
import '../product/shared/shared_snack_bar.dart';
class SettingsBloc extends BlocBase { class SettingsBloc extends BlocBase {
// Settings Screen // Settings Screen
@@ -14,7 +12,6 @@ class SettingsBloc extends BlocBase {
StreamSink<User> get sinkUserProfile => userProfile.sink; StreamSink<User> get sinkUserProfile => userProfile.sink;
Stream<User> get streamUserProfile => userProfile.stream; Stream<User> get streamUserProfile => userProfile.stream;
// Profile Screen // Profile Screen
final isChangeProfileInfomation = StreamController<bool>.broadcast(); final isChangeProfileInfomation = StreamController<bool>.broadcast();
StreamSink<bool> get sinkIsChangeProfileInfomation => StreamSink<bool> get sinkIsChangeProfileInfomation =>
@@ -22,20 +19,13 @@ class SettingsBloc extends BlocBase {
Stream<bool> get streamIsChangeProfileInfomation => Stream<bool> get streamIsChangeProfileInfomation =>
isChangeProfileInfomation.stream; isChangeProfileInfomation.stream;
void getUserProfile(BuildContext context) async { void getUserProfile(BuildContext context) async {
try { await apiServices.execute(context, () async {
User user = await apiServices.getUserDetail(); User user = await apiServices.getUserDetail();
sinkUserProfile.add(user); sinkUserProfile.add(user);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
} }
}
@override @override
void dispose() { void dispose() {}
}
} }

View File

@@ -1,8 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/shared/shared_snack_bar.dart';
import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';
import '../../bloc/bell_bloc.dart'; import '../../bloc/bell_bloc.dart';
import '../../product/base/bloc/base_bloc.dart'; import '../../product/base/bloc/base_bloc.dart';
@@ -77,7 +76,8 @@ class _BellScreenState extends State<BellScreen> {
if (index < bellSnapshot.data!.length) { if (index < bellSnapshot.data!.length) {
return GestureDetector( return GestureDetector(
onTap: () async { onTap: () async {
readNotification(bellSnapshot.data![index].id!); readNotification(
bellSnapshot.data![index].id!);
}, },
child: Column( child: Column(
children: [ children: [
@@ -163,24 +163,18 @@ class _BellScreenState extends State<BellScreen> {
getBellNotification(offset); getBellNotification(offset);
} }
void readNotification(String id) async{ void readNotification(String id) async {
try { await apiServices.execute(context, () async {
List<String> read = []; List<String> read = [];
read.add(id); read.add(id);
await apiServices await apiServices.updateStatusOfNotification(read);
.updateStatusOfNotification(read);
read.clear(); read.clear();
} catch (e) { });
if (mounted){
showErrorTopSnackBarCustom(
context, e.toString());
}
}
refresh(); refresh();
} }
Future<void> getBellNotification(int offset) async { Future<void> getBellNotification(int offset) async {
try { apiServices.execute(context, () async {
bell = await apiServices.getBellNotifications( bell = await apiServices.getBellNotifications(
offset.toString(), (offset + 20).toString()); offset.toString(), (offset + 20).toString());
if (bell.items!.isEmpty) { if (bell.items!.isEmpty) {
@@ -193,10 +187,7 @@ class _BellScreenState extends State<BellScreen> {
} }
bellBloc.bellItems.add(items); bellBloc.bellItems.add(items);
check = false; check = false;
} catch (e) { });
if (!mounted) return;
showErrorTopSnackBarCustom(context, e.toString());
}
} }
String timeAgo(BuildContext context, DateTime dateTime) { String timeAgo(BuildContext context, DateTime dateTime) {

View File

@@ -1,8 +1,9 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/bloc/devices_manager_bloc.dart';
import 'package:sfm_app/product/shared/shared_snack_bar.dart'; import '../../bloc/devices_manager_bloc.dart';
import '../../product/shared/shared_snack_bar.dart';
import '../../product/utils/response_status_utils.dart'; import '../../product/utils/response_status_utils.dart';
import '../../product/constant/enums/role_enums.dart'; import '../../product/constant/enums/role_enums.dart';
import '../../product/services/api_services.dart'; import '../../product/services/api_services.dart';
@@ -11,7 +12,8 @@ import '../../product/constant/icon/icon_constants.dart';
import '../../product/extension/context_extension.dart'; import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';
addNewDevice(BuildContext context, String role, DevicesManagerBloc deviceManagerBloc) async { addNewDevice(BuildContext context, String role,
DevicesManagerBloc deviceManagerBloc) async {
TextEditingController extIDController = TextEditingController(text: ""); TextEditingController extIDController = TextEditingController(text: "");
TextEditingController deviceNameController = TextEditingController(text: ""); TextEditingController deviceNameController = TextEditingController(text: "");
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@@ -77,7 +79,8 @@ addNewDevice(BuildContext context, String role, DevicesManagerBloc deviceManager
Colors.white); Colors.white);
ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).hideCurrentSnackBar();
} else { } else {
addDevices(context, role, extID, deviceName, deviceManagerBloc); addDevices(
context, role, extID, deviceName, deviceManagerBloc);
ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).hideCurrentSnackBar();
} }
}, },
@@ -90,12 +93,12 @@ addNewDevice(BuildContext context, String role, DevicesManagerBloc deviceManager
); );
} }
void addDevices( void addDevices(BuildContext context, String role, String extID,
BuildContext context, String role, String extID, String deviceName, DevicesManagerBloc deviceManagerBloc) async { String deviceName, DevicesManagerBloc deviceManagerBloc) async {
APIServices apiServices = APIServices(); APIServices apiServices = APIServices();
Map<String, dynamic> body = {}; Map<String, dynamic> body = {};
if (role == RoleEnums.ADMIN.name) { if (role == RoleEnums.ADMIN.name) {
try { await apiServices.execute(context,() async {
body = {"ext_id": extID, "name": deviceName}; body = {"ext_id": extID, "name": deviceName};
int statusCode = await apiServices.createDeviceByAdmin(body); int statusCode = await apiServices.createDeviceByAdmin(body);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
@@ -103,15 +106,10 @@ void addDevices(
statusCode, statusCode,
appLocalization(context).notification_create_device_success, appLocalization(context).notification_create_device_success,
appLocalization(context).notification_create_device_failed); appLocalization(context).notification_create_device_failed);
deviceManagerBloc.getDeviceByState(context,-2); deviceManagerBloc.getDeviceByState(context, -2);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} else { } else {
try { await apiServices.execute(context,() async {
body = {"ext_id": extID}; body = {"ext_id": extID};
int statusCode = await apiServices.registerDevice(body); int statusCode = await apiServices.registerDevice(body);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
@@ -119,12 +117,7 @@ void addDevices(
statusCode, statusCode,
appLocalization(context).notification_add_device_success, appLocalization(context).notification_add_device_success,
appLocalization(context).notification_device_not_exist); appLocalization(context).notification_device_not_exist);
deviceManagerBloc.getDeviceByState(context,-2); deviceManagerBloc.getDeviceByState(context, -2);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
} }
}
} }

View File

@@ -5,7 +5,6 @@ import '../../bloc/devices_manager_bloc.dart';
import '../../product/constant/enums/role_enums.dart'; import '../../product/constant/enums/role_enums.dart';
import '../../product/services/api_services.dart'; import '../../product/services/api_services.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';
import '../../product/shared/shared_snack_bar.dart';
import '../../product/utils/response_status_utils.dart'; import '../../product/utils/response_status_utils.dart';
handleDeleteDevice(BuildContext context, DevicesManagerBloc devicesManagerBloc, handleDeleteDevice(BuildContext context, DevicesManagerBloc devicesManagerBloc,
@@ -48,27 +47,24 @@ deleteOrUnregisterDevice(BuildContext context, DevicesManagerBloc devicesBloc,
Map<String, dynamic> body = { Map<String, dynamic> body = {
"ext_id": extID, "ext_id": extID,
}; };
await apiServices.execute(context, () async {
int statusCode = await apiServices.unregisterDevice(body); int statusCode = await apiServices.unregisterDevice(body);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
context, context,
statusCode, statusCode,
appLocalization(context).notification_delete_device_success, appLocalization(context).notification_delete_device_success,
appLocalization(context).notification_delete_device_failed); appLocalization(context).notification_delete_device_failed);
devicesBloc.getDeviceByState(context,-2); devicesBloc.getDeviceByState(context, -2);
});
} else { } else {
try { await apiServices.execute(context, () async {
int statusCode = await apiServices.deleteDeviceByAdmin(extID); int statusCode = await apiServices.deleteDeviceByAdmin(extID);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
context, context,
statusCode, statusCode,
appLocalization(context).notification_delete_device_success, appLocalization(context).notification_delete_device_success,
appLocalization(context).notification_delete_device_failed); appLocalization(context).notification_delete_device_failed);
devicesBloc.getDeviceByState(context,-2); devicesBloc.getDeviceByState(context, -2);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
} }

View File

@@ -88,23 +88,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
return StreamBuilder<Device>( return StreamBuilder<Device>(
stream: detailDeviceBloc.streamDeviceInfo, stream: detailDeviceBloc.streamDeviceInfo,
builder: (context, deviceSnapshot) { builder: (context, deviceSnapshot) {
if (deviceSnapshot.data?.extId == null) {
detailDeviceBloc.getDeviceDetail(
context,
widget.thingID,
controller,
);
return Scaffold(
appBar: AppBar(),
body: Center(
child: Text(appLocalization(context).no_data_message),
),
);
} else {
return StreamBuilder<Map<String, dynamic>>( return StreamBuilder<Map<String, dynamic>>(
stream: detailDeviceBloc.streamDeviceSensor, stream: detailDeviceBloc.streamDeviceSensor,
builder: (context, sensorSnapshot) { builder: (context, sensorSnapshot) {
if (sensorSnapshot.data != null) { if (sensorSnapshot.data != null ) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(deviceSnapshot.data?.name ?? ""), title: Text(deviceSnapshot.data?.name ?? ""),
@@ -637,13 +624,26 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
), ),
), ),
); );
} else {
return const SharedLoadingAnimation();
} }
}, else {
detailDeviceBloc.getDeviceDetail(
context,
widget.thingID,
controller,
);
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: AppBar(),
body: const Center(
child: SharedLoadingAnimation(),
),
); );
} }
}, },
); );
}
);
} }
} }

View File

@@ -1,11 +1,10 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart';
import '../../product/shared/shared_component_loading_animation.dart'; import '../../product/shared/shared_component_loading_animation.dart';
import '../../product/shared/shared_loading_animation.dart'; import '../../product/utils/app_logger_utils.dart';
import '../../product/shared/shared_snack_bar.dart';
import 'shared/alert_card.dart'; import 'shared/alert_card.dart';
import 'shared/warning_card.dart'; import 'shared/warning_card.dart';
import '../../product/utils/device_utils.dart'; import '../../product/utils/device_utils.dart';
@@ -19,8 +18,8 @@ import '../../bloc/home_bloc.dart';
import '../../product/base/bloc/base_bloc.dart'; import '../../product/base/bloc/base_bloc.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
const HomeScreen({super.key}); const HomeScreen({super.key, required this.persistentTabController});
final PersistentTabController persistentTabController;
@override @override
State<HomeScreen> createState() => _HomeScreenState(); State<HomeScreen> createState() => _HomeScreenState();
} }
@@ -29,7 +28,6 @@ class _HomeScreenState extends State<HomeScreen> {
late HomeBloc homeBloc; late HomeBloc homeBloc;
APIServices apiServices = APIServices(); APIServices apiServices = APIServices();
Map<String, List<DeviceWithAlias>> allDevicesAliasMap = {}; Map<String, List<DeviceWithAlias>> allDevicesAliasMap = {};
Map<String, List<DeviceWithAlias>> allDevicesAliasJoinedMap = {};
List<DeviceWithAlias> devices = []; List<DeviceWithAlias> devices = [];
bool isFunctionCall = false; bool isFunctionCall = false;
Timer? getAllDevicesTimer; Timer? getAllDevicesTimer;
@@ -41,6 +39,8 @@ class _HomeScreenState extends State<HomeScreen> {
void initState() { void initState() {
super.initState(); super.initState();
homeBloc = BlocProvider.of(context); homeBloc = BlocProvider.of(context);
getAllDevicesTimer?.cancel();
AppLoggerUtils.debug("Init State HomeScreen");
getOwnerAndJoinedDevices(); getOwnerAndJoinedDevices();
const duration = Duration(seconds: 10); const duration = Duration(seconds: 10);
getAllDevicesTimer = getAllDevicesTimer =
@@ -50,6 +50,7 @@ class _HomeScreenState extends State<HomeScreen> {
@override @override
void dispose() { void dispose() {
getAllDevicesTimer?.cancel(); getAllDevicesTimer?.cancel();
homeBloc.dispose();
super.dispose(); super.dispose();
} }
@@ -198,29 +199,13 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
), ),
), ),
StreamBuilder<bool?>( StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamHasJoinedDevice,
initialData: null,
builder: (context, hasJoinedDeviceSnapshot) {
return StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamAllDevicesAliasMap, stream: homeBloc.streamAllDevicesAliasMap,
builder: (context, allDevicesAliasMapSnapshot) { builder: (context, allDevicesAliasMapSnapshot) {
return StreamBuilder<Map<String, List<DeviceWithAlias>>>( if(allDevicesAliasMapSnapshot.data == null){
stream: homeBloc.streamAllDevicesAliasJoinedMap,
builder: (context, allDevicesAliasJoinedMapSnapshot) {
if (hasJoinedDeviceSnapshot.data == null) {
return const SharedComponentLoadingAnimation(); return const SharedComponentLoadingAnimation();
} else { }else{
final data = allDevicesAliasMapSnapshot.data!; final data = allDevicesAliasMapSnapshot.data!;
final dataJoined =
allDevicesAliasJoinedMapSnapshot.data!;
if (hasJoinedDeviceSnapshot.data == false) {
if (!allDevicesAliasMapSnapshot.hasData ||
allDevicesAliasMapSnapshot.data == null) {
return const Center(
child: CircularProgressIndicator());
}
return OverviewCard( return OverviewCard(
isOwner: true, isOwner: true,
total: data['all']?.length ?? 0, total: data['all']?.length ?? 0,
@@ -230,75 +215,7 @@ class _HomeScreenState extends State<HomeScreen> {
unused: data['not-use']?.length ?? 0, unused: data['not-use']?.length ?? 0,
showUnused: false, showUnused: false,
); );
} else {
return DefaultTabController(
length: 2,
child: Column(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.start,
children: [
TabBar(
tabs: [
Tab(
text: appLocalization(context)
.over_view_owner_devices),
Tab(
text: appLocalization(context)
.over_view_joined_devices),
],
labelColor: Colors.blue,
unselectedLabelColor: Colors.grey,
indicatorColor: Colors.blue,
),
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: context.dynamicHeight(0.5),
minHeight: context.dynamicHeight(0.3),
),
child: TabBarView(
children: [
OverviewCard(
isOwner: true,
total: data['all']?.length ?? 0,
active: data['online']?.length ?? 0,
inactive:
data['offline']?.length ?? 0,
warning: data['warn']?.length ?? 0,
unused:
data['not-use']?.length ?? 0,
showUnused: false,
),
OverviewCard(
isOwner: false,
total:
dataJoined['all']?.length ?? 0,
active:
dataJoined['online']?.length ??
0,
inactive:
dataJoined['offline']?.length ??
0,
warning:
dataJoined['warn']?.length ?? 0,
unused:
dataJoined['not-use']?.length ??
0,
showUnused: false,
showActive: false,
showInactive: false,
),
],
),
),
],
),
);
} }
}
},
);
},
);
}, },
), ),
], ],
@@ -309,8 +226,8 @@ class _HomeScreenState extends State<HomeScreen> {
} }
void getOwnerAndJoinedDevices() async { void getOwnerAndJoinedDevices() async {
try { await apiServices.execute(context, () async {
devices = await apiServices.getDashBoardDevices(); devices = await apiServices.getDashBoardDevices().handleApiError();
List<DeviceWithAlias> publicDevices = []; List<DeviceWithAlias> publicDevices = [];
for (var device in devices) { for (var device in devices) {
if (device.visibility == "PUBLIC") { if (device.visibility == "PUBLIC") {
@@ -320,10 +237,7 @@ class _HomeScreenState extends State<HomeScreen> {
getOwnerDeviceState(publicDevices); getOwnerDeviceState(publicDevices);
checkSettingDevice(publicDevices); checkSettingDevice(publicDevices);
getDeviceStatusAliasMap(publicDevices); getDeviceStatusAliasMap(publicDevices);
} catch (e) { });
if (!mounted) return;
showErrorTopSnackBarCustom(context, e.toString());
}
} }
void getOwnerDeviceState(List<DeviceWithAlias> allDevices) async { void getOwnerDeviceState(List<DeviceWithAlias> allDevices) async {
@@ -335,7 +249,7 @@ class _HomeScreenState extends State<HomeScreen> {
int count = 0; int count = 0;
for (var device in allDevices) { for (var device in allDevices) {
if (device.isOwner != true) continue; // if (device.isOwner != true) continue;
if (!mounted) return; if (!mounted) return;
Map<String, dynamic> sensorMap = DeviceUtils.instance Map<String, dynamic> sensorMap = DeviceUtils.instance
@@ -368,15 +282,11 @@ class _HomeScreenState extends State<HomeScreen> {
void getDeviceStatusAliasMap(List<DeviceWithAlias> devices) { void getDeviceStatusAliasMap(List<DeviceWithAlias> devices) {
allDevicesAliasMap.clear(); allDevicesAliasMap.clear();
allDevicesAliasJoinedMap.clear();
bool check = false;
for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) { for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) {
allDevicesAliasMap[key] = []; allDevicesAliasMap[key] = [];
allDevicesAliasJoinedMap[key] = [];
} }
for (DeviceWithAlias device in devices) { for (DeviceWithAlias device in devices) {
if (device.isOwner == true) {
allDevicesAliasMap['all']!.add(device); allDevicesAliasMap['all']!.add(device);
if (device.state == 0 || device.state == 1) { if (device.state == 0 || device.state == 1) {
allDevicesAliasMap['online']!.add(device); allDevicesAliasMap['online']!.add(device);
@@ -390,33 +300,16 @@ class _HomeScreenState extends State<HomeScreen> {
if (device.state == -2) { if (device.state == -2) {
allDevicesAliasMap['not-use']!.add(device); allDevicesAliasMap['not-use']!.add(device);
} }
} else {
check = true;
allDevicesAliasJoinedMap['all']!.add(device);
if (device.state == 0 || device.state == 1) {
allDevicesAliasJoinedMap['online']!.add(device);
} }
if (device.state == -1) {
allDevicesAliasJoinedMap['offline']!.add(device);
}
if (device.state == 1) {
allDevicesAliasJoinedMap['warning']!.add(device);
}
if (device.state == -2) {
allDevicesAliasJoinedMap['not-use']!.add(device);
}
}
}
homeBloc.sinkHasJoinedDevice.add(check);
homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap); homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap);
homeBloc.sinkAllDevicesAliasJoinedMap.add(allDevicesAliasJoinedMap);
} }
void checkSettingDevice(List<DeviceWithAlias> devices) async { void checkSettingDevice(List<DeviceWithAlias> devices) async {
try {
if (isFunctionCall) { if (isFunctionCall) {
log("Ham check setting da duoc goi"); log("Ham check setting da duoc goi");
} else { } else {
await apiServices.execute(context, () async {
List<DeviceNotificationSettings> list = List<DeviceNotificationSettings> list =
await apiServices.getAllSettingsNotificationOfDevices(); await apiServices.getAllSettingsNotificationOfDevices();
// log("List: $list"); // log("List: $list");
@@ -425,24 +318,16 @@ class _HomeScreenState extends State<HomeScreen> {
for (var device in devices) { for (var device in devices) {
if (!thingIdsInList.contains(device.thingId)) { if (!thingIdsInList.contains(device.thingId)) {
log("Device with Thing ID ${device.thingId} is not in the notification settings list."); log("Device with Thing ID ${device.thingId} is not in the notification settings list.");
try { await apiServices.execute(context, () async {
await apiServices.setupDeviceNotification( await apiServices.setupDeviceNotification(
device.thingId!, device.name!); device.thingId!, device.name!);
} catch (e) { });
if (!mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} else { } else {
log("All devices are in the notification settings list."); log("All devices are in the notification settings list.");
} }
} }
});
} }
isFunctionCall = true; isFunctionCall = true;
} catch (e) {
if (!mounted) return;
showErrorTopSnackBarCustom(context, e.toString());
}
} }
} }

View File

@@ -3,7 +3,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:sfm_app/feature/home/device_alias_model.dart'; import '../../../product/shared/shared_rocket_container.dart';
import '../../../product/constant/enums/app_route_enums.dart'; import '../../../product/constant/enums/app_route_enums.dart';
import '../../../product/constant/image/image_constants.dart'; import '../../../product/constant/image/image_constants.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
@@ -11,16 +11,16 @@ import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../device_alias_model.dart';
Future<Widget> notificationCard(BuildContext context, String notiticationType, Future<Widget> notificationCard(BuildContext context, String notificationType,
String notificationTitle, DeviceWithAlias device) async { String notificationTitle, DeviceWithAlias device) async {
String location = ""; String location = "";
if (device.areaPath != "") { if (device.areaPath != "") {
location = await DeviceUtils.instance location = await DeviceUtils.instance
.getFullDeviceLocation(context, device.areaPath!,""); .getFullDeviceLocation(context, device.areaPath!, "");
} }
String path = ""; String path = "";
// DateTime time = DateTime.now();
String time = ""; String time = "";
for (var sensor in device.status!.sensors!) { for (var sensor in device.status!.sensors!) {
if (sensor.name! == "7") { if (sensor.name! == "7") {
@@ -29,7 +29,7 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
time = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime); time = DateFormat('yyyy-MM-dd HH:mm:ss').format(dateTime);
} }
} }
if (notiticationType == "lowBattery") { if (notificationType == "lowBattery") {
path = ImageConstants.instance.getImage("low_battery"); path = ImageConstants.instance.getImage("low_battery");
} }
return Card( return Card(
@@ -117,11 +117,13 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
), ),
], ],
), ),
Align( device.isOwner!
? Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: OutlinedButton( child: OutlinedButton(
style: const ButtonStyle( style: const ButtonStyle(
backgroundColor: WidgetStatePropertyAll(Colors.blueAccent), backgroundColor:
WidgetStatePropertyAll(Colors.blueAccent),
), ),
onPressed: () { onPressed: () {
context.pushNamed(AppRoutes.DEVICE_DETAIL.name, context.pushNamed(AppRoutes.DEVICE_DETAIL.name,
@@ -129,11 +131,42 @@ Future<Widget> notificationCard(BuildContext context, String notiticationType,
}, },
child: Text( child: Text(
appLocalization(context).detail_message, appLocalization(context).detail_message,
style: const TextStyle( style: const TextStyle(color: Colors.white),
color: Colors.white, ),
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClipPath(
clipper: SharedRocketContainer(),
child: Container(
padding: EdgeInsets.all(context.lowValue),
height: context.mediumValue,
width: context.dynamicWidth(0.22),
decoration: BoxDecoration(
color: Colors.green[300],
),
child: Text(
appLocalization(context).interfamily_page_name,
), ),
), ),
), ),
OutlinedButton(
style: const ButtonStyle(
backgroundColor:
WidgetStatePropertyAll(Colors.blueAccent),
),
onPressed: () {
context.pushNamed(AppRoutes.DEVICE_DETAIL.name,
pathParameters: {'thingID': device.thingId!});
},
child: Text(
appLocalization(context).detail_message,
style: const TextStyle(color: Colors.white),
),
),
],
), ),
], ],
), ),

View File

@@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:maps_launcher/maps_launcher.dart'; import 'package:maps_launcher/maps_launcher.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
import '../../../product/shared/shared_rocket_container.dart';
import '../device_alias_model.dart'; import '../device_alias_model.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/constant/image/image_constants.dart'; import '../../../product/constant/image/image_constants.dart';
@@ -21,7 +23,7 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
String fullLocation = ""; String fullLocation = "";
if (device.areaPath != "") { if (device.areaPath != "") {
fullLocation = await DeviceUtils.instance fullLocation = await DeviceUtils.instance
.getFullDeviceLocation(context, device.areaPath!,""); .getFullDeviceLocation(context, device.areaPath!, "");
} }
String time = ""; String time = "";
for (var sensor in device.status!.sensors!) { for (var sensor in device.status!.sensors!) {
@@ -187,7 +189,8 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
), ),
), ),
SizedBox(width: context.mediumValue), SizedBox(width: context.mediumValue),
Expanded( device.isOwner!
? Expanded(
child: Align( child: Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: OutlinedButton( child: OutlinedButton(
@@ -196,7 +199,8 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
WidgetStatePropertyAll(backgroundColor)), WidgetStatePropertyAll(backgroundColor)),
onPressed: () async { onPressed: () async {
if (message == if (message ==
appLocalization(context).button_fake_fire_message) { appLocalization(context)
.button_fake_fire_message) {
await showDialog( await showDialog(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
@@ -209,9 +213,11 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
actions: [ actions: [
TextButton( TextButton(
onPressed: () async { onPressed: () async {
try { await apiServices.execute(context,
() async {
int statusCode = await apiServices int statusCode = await apiServices
.confirmFakeFireByUser(device.thingId!); .confirmFakeFireByUser(
device.thingId!);
if (statusCode == 200) { if (statusCode == 200) {
showNoIconTopSnackBar( showNoIconTopSnackBar(
context, context,
@@ -227,18 +233,15 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
Colors.red, Colors.red,
Colors.red); Colors.red);
} }
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
child: Text( child: Text(
appLocalization(context) appLocalization(context)
.confirm_fake_fire_sure_message, .confirm_fake_fire_sure_message,
style: style: const TextStyle(
const TextStyle(color: Colors.red)), color: Colors.red)),
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
@@ -253,7 +256,105 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
} else { } else {
showNoIconTopSnackBar( showNoIconTopSnackBar(
context, context,
appLocalization(context).let_PCCC_handle_message, appLocalization(context)
.let_PCCC_handle_message,
Colors.orange,
Colors.white);
}
},
child: Text(
message,
style: TextStyle(color: textColor),
),
),
),
)
: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
ClipPath(
clipper: SharedRocketContainer(),
child: Container(
padding: EdgeInsets.all(context.lowValue),
height: context.mediumValue,
width: context.dynamicWidth(0.22),
decoration: BoxDecoration(
color: Colors.green[300],
),
child: Text(
appLocalization(context).interfamily_page_name,
),
),
),
Expanded(
child: Align(
alignment: Alignment.centerRight,
child: OutlinedButton(
style: ButtonStyle(
backgroundColor: WidgetStatePropertyAll(
backgroundColor)),
onPressed: () async {
if (message ==
appLocalization(context)
.button_fake_fire_message) {
await showDialog(
context: context,
builder: (context) => AlertDialog(
icon: const Icon(Icons.warning),
iconColor: Colors.red,
title: Text(appLocalization(context)
.confirm_fake_fire_message),
content: Text(appLocalization(context)
.confirm_fake_fire_body),
actions: [
TextButton(
onPressed: () async {
await apiServices.execute(context,
() async {
int statusCode =
await apiServices
.confirmFakeFireByUser(
device.thingId!);
if (statusCode == 200) {
showNoIconTopSnackBar(
context,
appLocalization(context)
.notification_confirm_fake_fire_success,
Colors.green,
Colors.white);
} else {
showNoIconTopSnackBar(
context,
appLocalization(context)
.notification_confirm_fake_fire_failed,
Colors.red,
Colors.red);
}
});
Navigator.of(context).pop();
},
child: Text(
appLocalization(context)
.confirm_fake_fire_sure_message,
style: const TextStyle(
color: Colors.red)),
),
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text(appLocalization(context)
.cancel_button_content),
),
],
),
);
} else {
showNoIconTopSnackBar(
context,
appLocalization(context)
.let_PCCC_handle_message,
Colors.orange, Colors.orange,
Colors.white); Colors.white);
} }
@@ -269,6 +370,8 @@ Future<Widget> warningCard(BuildContext context, APIServices apiServices,
), ),
], ],
), ),
],
),
), ),
), ),
); );

View File

@@ -5,7 +5,6 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../bloc/group_detail_bloc.dart'; import '../../../bloc/group_detail_bloc.dart';
import '../../../product/shared/shared_loading_animation.dart'; import '../../../product/shared/shared_loading_animation.dart';
import '../../../product/shared/shared_snack_bar.dart';
import 'group_detail_model.dart'; import 'group_detail_model.dart';
import '../../../product/base/bloc/base_bloc.dart'; import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/constant/app/app_constants.dart'; import '../../../product/constant/app/app_constants.dart';
@@ -325,7 +324,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
Future.delayed(context.lowDuration).then( Future.delayed(context.lowDuration).then(
(value) => Navigator.pop(context), (value) => Navigator.pop(context),
); );
try { await apiServices.execute(context, () async {
int statusCode = await apiServices int statusCode = await apiServices
.deleteGroup(widget.group); .deleteGroup(widget.group);
showSnackBarResponseByStatusCode( showSnackBarResponseByStatusCode(
@@ -335,11 +334,7 @@ class _DetailGroupScreenState extends State<DetailGroupScreen> {
.notification_delete_group_success, .notification_delete_group_success,
appLocalization(context) appLocalization(context)
.notification_delete_group_failed); .notification_delete_group_failed);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
}, },
child: Text( child: Text(
appLocalization(context) appLocalization(context)

View File

@@ -39,7 +39,7 @@ class _GroupsScreenState extends State<GroupsScreen> {
const duration = Duration(seconds: 5); const duration = Duration(seconds: 5);
getAllGroupsTimer = Timer.periodic( getAllGroupsTimer = Timer.periodic(
duration, duration,
(Timer t) => interFamilyBloc.getAllGroup(widget.role), (Timer t) => interFamilyBloc.getAllGroup(context, widget.role),
); );
} }
@@ -57,7 +57,7 @@ class _GroupsScreenState extends State<GroupsScreen> {
stream: interFamilyBloc.streamCurrentGroups, stream: interFamilyBloc.streamCurrentGroups,
builder: (context, groupsSnapshot) { builder: (context, groupsSnapshot) {
if (groupsSnapshot.data == null) { if (groupsSnapshot.data == null) {
interFamilyBloc.getAllGroup(widget.role); interFamilyBloc.getAllGroup(context,widget.role);
return const SharedLoadingAnimation(); return const SharedLoadingAnimation();
} else if (groupsSnapshot.data!.isEmpty) { } else if (groupsSnapshot.data!.isEmpty) {
return Center( return Center(

View File

@@ -1,10 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:qr_flutter/qr_flutter.dart'; import 'package:qr_flutter/qr_flutter.dart';
import '../../../bloc/inter_family_bloc.dart'; import '../../../bloc/inter_family_bloc.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import 'groups_model.dart'; import 'groups_model.dart';
shareGroup(BuildContext context, Group group) { shareGroup(BuildContext context, Group group) {
@@ -80,7 +80,8 @@ showActionDialog(
if (dialogTitle == appLocalization(context).delete_group_title) { if (dialogTitle == appLocalization(context).delete_group_title) {
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
await interFamilyBloc.deleteGroup(context, group.id!); await interFamilyBloc.deleteGroup(context, group.id!);
interFamilyBloc.getAllGroup(role); // ignore: use_build_context_synchronously
interFamilyBloc.getAllGroup(context,role);
} else {} } else {}
}, },
child: Text( child: Text(

View File

@@ -122,7 +122,7 @@ createOrJoinGroupDialog(
try { try {
await interFamilyBloc.createGroup( await interFamilyBloc.createGroup(
context, groupName, description); context, groupName, description);
interFamilyBloc.getAllGroup(role); interFamilyBloc.getAllGroup(context, role);
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
} catch (e) { } catch (e) {
// log("Lỗi khi tạo nhóm: $e"); // log("Lỗi khi tạo nhóm: $e");
@@ -133,7 +133,7 @@ createOrJoinGroupDialog(
try { try {
await interFamilyBloc.changeGroupInformation( await interFamilyBloc.changeGroupInformation(
context, groupID, groupName, description); context, groupID, groupName, description);
interFamilyBloc.getAllGroup(role); interFamilyBloc.getAllGroup(context, role);
Navigator.of(dialogContext).pop(); Navigator.of(dialogContext).pop();
} catch (e) { } catch (e) {
// log("Lỗi khi sửa nhóm: $e"); // log("Lỗi khi sửa nhóm: $e");

View File

@@ -1,8 +1,6 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:developer'; import 'dart:developer';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart'; import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -10,16 +8,14 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:badges/badges.dart' as badges; import 'package:badges/badges.dart' as badges;
import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart'; import 'package:persistent_bottom_nav_bar/persistent_bottom_nav_bar.dart';
import 'package:sfm_app/product/shared/shared_snack_bar.dart';
import 'package:sfm_app/product/utils/permission_handler.dart'; import '../../product/utils/permission_handler.dart';
import '../../product/permission/notification_permission.dart'; import '../../product/permission/notification_permission.dart';
import '../../product/services/notification_services.dart';
import '../settings/profile/profile_model.dart'; import '../settings/profile/profile_model.dart';
import '../../product/extension/context_extension.dart'; import '../../product/extension/context_extension.dart';
import '../../bloc/home_bloc.dart'; import '../../bloc/home_bloc.dart';
import '../../product/constant/app/app_constants.dart'; import '../../product/constant/app/app_constants.dart';
import '../../product/constant/enums/app_route_enums.dart'; import '../../product/constant/enums/app_route_enums.dart';
import '../../product/permission/location_permission.dart';
import '../../product/services/theme_services.dart'; import '../../product/services/theme_services.dart';
import '../../bloc/devices_manager_bloc.dart'; import '../../bloc/devices_manager_bloc.dart';
import '../devices/devices_manager_screen.dart'; import '../devices/devices_manager_screen.dart';
@@ -47,8 +43,6 @@ class MainScreen extends StatefulWidget {
State<MainScreen> createState() => _MainScreenState(); State<MainScreen> createState() => _MainScreenState();
} }
PersistentTabController controller = PersistentTabController(initialIndex: 0);
// @pragma('vm:entry-point') // @pragma('vm:entry-point')
// Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async { // Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// log("Full background message payload: ${message.toMap()}"); // log("Full background message payload: ${message.toMap()}");
@@ -59,8 +53,8 @@ PersistentTabController controller = PersistentTabController(initialIndex: 0);
// log("Background message handled: ${message.data['title']}"); // log("Background message handled: ${message.data['title']}");
// } // }
class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver { class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
PersistentTabController controller = PersistentTabController(initialIndex: 0);
APIServices apiServices = APIServices(); APIServices apiServices = APIServices();
// final NotificationServices notificationServices = NotificationServices(); // final NotificationServices notificationServices = NotificationServices();
late MainBloc mainBloc; late MainBloc mainBloc;
@@ -112,17 +106,19 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
FirebaseMessaging.onMessage.listen((RemoteMessage message) { FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification; RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android; AndroidNotification? android = message.notification?.android;
if (notification != null && android != null ) { if (notification != null && android != null) {
const AndroidNotificationDetails androidPlatformChannelSpecifics = const AndroidNotificationDetails androidPlatformChannelSpecifics =
AndroidNotificationDetails( AndroidNotificationDetails('your channel id', 'your channel name',
'your channel id', 'your channel name',
importance: Importance.max, importance: Importance.max,
priority: Priority.high, priority: Priority.high,
ticker: 'ticker'); ticker: 'ticker');
const NotificationDetails platformChannelSpecifics = const NotificationDetails platformChannelSpecifics =
NotificationDetails(android: androidPlatformChannelSpecifics); NotificationDetails(android: androidPlatformChannelSpecifics);
flutterLocalNotificationsPlugin.show( flutterLocalNotificationsPlugin.show(
notification.hashCode, notification.title, notification.body, platformChannelSpecifics, notification.hashCode,
notification.title,
notification.body,
platformChannelSpecifics,
); );
} }
}); });
@@ -151,7 +147,6 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
} }
List<PersistentBottomNavBarItem> _navBarsItems() { List<PersistentBottomNavBarItem> _navBarsItems() {
return [ return [
PersistentBottomNavBarItem( PersistentBottomNavBarItem(
@@ -200,7 +195,9 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
List<Widget> _buildScreens() { List<Widget> _buildScreens() {
return [ return [
BlocProvider( BlocProvider(
child: const HomeScreen(), child: HomeScreen(
persistentTabController: controller,
),
blocBuilder: () => HomeBloc(), blocBuilder: () => HomeBloc(),
), ),
BlocProvider( BlocProvider(
@@ -238,7 +235,7 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
SizedBox( SizedBox(
width: context.lowValue, width: context.lowValue,
), ),
Flexible( child: Text(userSnapshot.data?.name ?? "")) Flexible(child: Text(userSnapshot.data?.name ?? ""))
], ],
); );
}), }),
@@ -404,12 +401,10 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
} }
Future<void> getBellNotification() async { Future<void> getBellNotification() async {
try{ await apiServices.execute(context, () async {
bell = await apiServices.getBellNotifications("0", "20"); bell = await apiServices.getBellNotifications("0", "20");
mainBloc.bellBloc.add(bell); mainBloc.bellBloc.add(bell);
}catch(e){ });
showErrorTopSnackBarCustom(context, e.toString());
}
} }
bool checkStatus(List<BellItems> bells) { bool checkStatus(List<BellItems> bells) {

View File

@@ -1,23 +1,20 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
import 'package:google_maps_cluster_manager_2/google_maps_cluster_manager_2.dart'; import 'package:google_maps_cluster_manager_2/google_maps_cluster_manager_2.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' import 'package:google_maps_flutter/google_maps_flutter.dart'
hide ClusterManager, Cluster; hide ClusterManager, Cluster;
import 'package:sfm_app/feature/devices/device_model.dart';
import 'package:sfm_app/bloc/map_bloc.dart'; import '../../bloc/map_bloc.dart';
import 'package:sfm_app/feature/map/widget/on_tap_marker_widget.dart'; import '../../product/base/bloc/base_bloc.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 'package:sfm_app/product/utils/permission_handler.dart';
import '../../product/constant/enums/app_theme_enums.dart'; import '../../product/constant/enums/app_theme_enums.dart';
import '../../product/shared/shared_snack_bar.dart'; import '../../product/constant/icon/icon_constants.dart';
import '../../product/services/api_services.dart';
import '../../product/utils/permission_handler.dart';
import '../devices/device_model.dart';
import 'widget/on_tap_marker_widget.dart';
class MapScreen extends StatefulWidget { class MapScreen extends StatefulWidget {
const MapScreen({super.key}); const MapScreen({super.key});
@@ -39,7 +36,7 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
APIServices apiServices = APIServices(); APIServices apiServices = APIServices();
final streamController = StreamController<GoogleMapController>.broadcast(); final streamController = StreamController<GoogleMapController>.broadcast();
List<Device> devices = []; List<Device> devices = [];
Completer<GoogleMapController> _controller = Completer(); final Completer<GoogleMapController> _controller = Completer();
List<String> imageAssets = [ List<String> imageAssets = [
IconConstants.instance.getIcon("normal_icon"), IconConstants.instance.getIcon("normal_icon"),
IconConstants.instance.getIcon("offline_icon"), IconConstants.instance.getIcon("offline_icon"),
@@ -121,7 +118,8 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
clusterManager.updateMap(); clusterManager.updateMap();
}, },
polylines: { polylines: {
if (polylinesSnapshot.data != null && polylinesSnapshot.data!.isNotEmpty) ... [ if (polylinesSnapshot.data != null &&
polylinesSnapshot.data!.isNotEmpty) ...[
Polyline( Polyline(
polylineId: const PolylineId('router'), polylineId: const PolylineId('router'),
points: polylinesSnapshot.data!, points: polylinesSnapshot.data!,
@@ -189,7 +187,8 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
position: cluster.location, position: cluster.location,
onTap: () async { onTap: () async {
LocationPermission permission = await checkAndRequestPermission(); LocationPermission permission = await checkAndRequestPermission();
if (permission == LocationPermission.whileInUse || permission == LocationPermission.always) { if (permission == LocationPermission.whileInUse ||
permission == LocationPermission.always) {
Position position = await Geolocator.getCurrentPosition(); Position position = await Geolocator.getCurrentPosition();
onTapMarker( onTapMarker(
// ignore: use_build_context_synchronously // ignore: use_build_context_synchronously
@@ -277,23 +276,12 @@ class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
} }
void getAllMarkers() async { void getAllMarkers() async {
try { await apiServices.execute(context, () async {
devices.clear(); devices.clear();
final devicesList = await apiServices.getOwnerDevices(); final devicesList = await apiServices.getOwnerDevices();
for (var device in devicesList) { for (var device in devicesList) {
devices.add(device); devices.add(device);
} }
} catch (e) { });
if (!mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
} }
}
// Future<bool> checkLocationPermission(context) async {
// bool check = await LocationPermissionRequest.instance
// .checkLocationPermission(context);
// return check;
// }
} }

View File

@@ -1,8 +1,8 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:convert';
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../product/shared/shared_snack_bar.dart'; import '../../../product/shared/shared_snack_bar.dart';
import '../../../bloc/device_notification_settings_bloc.dart'; import '../../../bloc/device_notification_settings_bloc.dart';
import 'device_notification_settings_model.dart'; import 'device_notification_settings_model.dart';
@@ -111,15 +111,12 @@ class _DeviceNotificationSettingsScreenState
} }
void getNotificationSetting() async { void getNotificationSetting() async {
try { await apiServices.execute(context, () async {
deviceNotifications = deviceNotifications =
await apiServices.getAllSettingsNotificationOfDevices(); await apiServices.getAllSettingsNotificationOfDevices();
deviceNotificationSettingsBloc.sinkListNotifications deviceNotificationSettingsBloc.sinkListNotifications
.add(deviceNotifications); .add(deviceNotifications);
} catch (e) { });
if (!mounted) return;
showErrorTopSnackBarCustom(context, e.toString());
}
} }
Widget listNotificationSetting( Widget listNotificationSetting(
@@ -293,13 +290,14 @@ class _DeviceNotificationSettingsScreenState
void updateDeviceNotification(String thingID, Map<String, int> notifiSettings, void updateDeviceNotification(String thingID, Map<String, int> notifiSettings,
bool isDataChange) async { bool isDataChange) async {
try { await apiServices.execute(context, () async {
int statusCode = await apiServices.updateDeviceNotificationSettings( int statusCode = await apiServices.updateDeviceNotificationSettings(
thingID, notifiSettings); thingID, notifiSettings);
if (statusCode == 200) { if (statusCode == 200) {
showNoIconTopSnackBar( showNoIconTopSnackBar(
context, context,
appLocalization(context).notification_update_device_settings_success, appLocalization(context)
.notification_update_device_settings_success,
Colors.green, Colors.green,
Colors.white); Colors.white);
} else { } else {
@@ -311,11 +309,6 @@ class _DeviceNotificationSettingsScreenState
} }
isDataChange = false; isDataChange = false;
deviceNotificationSettingsBloc.sinkIsDataChange.add(isDataChange); deviceNotificationSettingsBloc.sinkIsDataChange.add(isDataChange);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
} }

View File

@@ -1,6 +1,7 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../product/shared/shared_snack_bar.dart'; import '../../../product/shared/shared_snack_bar.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/services/api_services.dart'; import '../../../product/services/api_services.dart';
@@ -8,7 +9,6 @@ import '../../../bloc/settings_bloc.dart';
import '../../../product/shared/shared_input_decoration.dart'; import '../../../product/shared/shared_input_decoration.dart';
import '../../../product/extension/context_extension.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import 'profile_model.dart'; import 'profile_model.dart';
changeUserInfomation( changeUserInfomation(
@@ -38,7 +38,7 @@ changeUserInfomation(
? IconButton( ? IconButton(
onPressed: () async { onPressed: () async {
if (formKey.currentState!.validate()) { if (formKey.currentState!.validate()) {
try { await apiServices.execute(context,() async {
formKey.currentState!.save(); formKey.currentState!.save();
String latitude = user.latitude ?? ""; String latitude = user.latitude ?? "";
String longitude = user.longitude ?? ""; String longitude = user.longitude ?? "";
@@ -69,11 +69,42 @@ changeUserInfomation(
} }
settingsBloc.getUserProfile(context); settingsBloc.getUserProfile(context);
Navigator.pop(modalBottomSheetContext); Navigator.pop(modalBottomSheetContext);
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // formKey.currentState!.save();
context, e.toString()); // String latitude = user.latitude ?? "";
} // String longitude = user.longitude ?? "";
// Map<String, dynamic> body = {
// "name": username,
// "email": email,
// "phone": tel,
// "address": address,
// "latitude": latitude,
// "longitude": longitude
// };
// int statusCode =
// await apiServices.updateUserProfile(body);
// if (statusCode == 200) {
// showNoIconTopSnackBar(
// modalBottomSheetContext,
// appLocalization(context)
// .notification_update_profile_success,
// Colors.green,
// Colors.white);
// } else {
// showNoIconTopSnackBar(
// modalBottomSheetContext,
// appLocalization(context)
// .notification_update_profile_failed,
// Colors.redAccent,
// Colors.white);
// }
// settingsBloc.getUserProfile(context);
// Navigator.pop(modalBottomSheetContext);
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(context, e.toString());
// }
} }
}, },
icon: icon:
@@ -212,7 +243,7 @@ changeUserInfomation(
child: TextButton( child: TextButton(
onPressed: () async { onPressed: () async {
if (formKey.currentState!.validate()) { if (formKey.currentState!.validate()) {
try { await apiServices.execute(context,() async {
formKey.currentState!.save(); formKey.currentState!.save();
String latitude = user.latitude ?? ""; String latitude = user.latitude ?? "";
String longitude = user.longitude ?? ""; String longitude = user.longitude ?? "";
@@ -224,8 +255,8 @@ changeUserInfomation(
"latitude": latitude, "latitude": latitude,
"longitude": longitude "longitude": longitude
}; };
int statusCode = int statusCode = await apiServices
await apiServices.updateUserProfile(body); .updateUserProfile(body);
if (statusCode == 200) { if (statusCode == 200) {
showNoIconTopSnackBar( showNoIconTopSnackBar(
modalBottomSheetContext, modalBottomSheetContext,
@@ -243,11 +274,7 @@ changeUserInfomation(
} }
settingsBloc.getUserProfile(context); settingsBloc.getUserProfile(context);
Navigator.pop(modalBottomSheetContext); Navigator.pop(modalBottomSheetContext);
} catch (e) { });
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
}
} }
}, },
style: const ButtonStyle( style: const ButtonStyle(
@@ -296,8 +323,8 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
isChangeSnapshot.data ?? isChange isChangeSnapshot.data ?? isChange
? IconButton( ? IconButton(
onPressed: () async { onPressed: () async {
try {
if (formKey.currentState!.validate()) { if (formKey.currentState!.validate()) {
await apiServices.execute(context,() async {
formKey.currentState!.save(); formKey.currentState!.save();
Map<String, dynamic> body = { Map<String, dynamic> body = {
"password_old": oldPass, "password_old": oldPass,
@@ -321,11 +348,7 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
Colors.white); Colors.white);
} }
Navigator.pop(modalBottomSheetContext); Navigator.pop(modalBottomSheetContext);
} });
} catch (e) {
if (!context.mounted) return;
showErrorTopSnackBarCustom(
context, e.toString());
} }
}, },
icon: icon:
@@ -410,15 +433,15 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
? Center( ? Center(
child: TextButton( child: TextButton(
onPressed: () async { onPressed: () async {
try { await apiServices.execute(context,() async {
if (formKey.currentState!.validate()) { if (formKey.currentState!.validate()) {
formKey.currentState!.save(); formKey.currentState!.save();
Map<String, dynamic> body = { Map<String, dynamic> body = {
"password_old": oldPass, "password_old": oldPass,
"password_new": newPass, "password_new": newPass,
}; };
int statusCode = int statusCode = await apiServices
await apiServices.updateUserPassword(body); .updateUserPassword(body);
if (statusCode == 200) { if (statusCode == 200) {
showNoIconTopSnackBar( showNoIconTopSnackBar(
modalBottomSheetContext, modalBottomSheetContext,
@@ -436,11 +459,38 @@ changeUserPassword(BuildContext context, SettingsBloc settingsBloc) {
} }
Navigator.pop(modalBottomSheetContext); Navigator.pop(modalBottomSheetContext);
} }
} catch (e) { });
if (!context.mounted) return; // try {
showErrorTopSnackBarCustom( // if (formKey.currentState!.validate()) {
context, e.toString()); // formKey.currentState!.save();
} // Map<String, dynamic> body = {
// "password_old": oldPass,
// "password_new": newPass,
// };
// int statusCode = await apiServices
// .updateUserPassword(body);
// if (statusCode == 200) {
// showNoIconTopSnackBar(
// modalBottomSheetContext,
// appLocalization(context)
// .notification_update_password_success,
// Colors.green,
// Colors.white);
// } else {
// showNoIconTopSnackBar(
// modalBottomSheetContext,
// appLocalization(context)
// .notification_update_password_failed,
// Colors.redAccent,
// Colors.white);
// }
// Navigator.pop(modalBottomSheetContext);
// }
// } catch (e) {
// if (!context.mounted) return;
// showErrorTopSnackBarCustom(
// context, e.toString());
// }
}, },
style: const ButtonStyle( style: const ButtonStyle(
backgroundColor: backgroundColor:

View File

@@ -1,10 +1,8 @@
import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../product/constant/app/app_constants.dart'; import '../../product/constant/app/app_constants.dart';
import '../../product/shared/shared_loading_animation.dart'; import '../../product/shared/shared_loading_animation.dart';
import '../../product/shared/shared_snack_bar.dart';
import 'profile/profile_screen.dart'; import 'profile/profile_screen.dart';
import '../../product/constant/icon/icon_constants.dart'; import '../../product/constant/icon/icon_constants.dart';
import '../../product/extension/context_extension.dart'; import '../../product/extension/context_extension.dart';
@@ -29,7 +27,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
void initState() { void initState() {
super.initState(); super.initState();
settingsBloc = BlocProvider.of(context); settingsBloc = BlocProvider.of(context);
// getUserProfile();
} }
@override @override
@@ -41,7 +38,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
), ),
body: StreamBuilder<User>( body: StreamBuilder<User>(
stream: settingsBloc.streamUserProfile, stream: settingsBloc.streamUserProfile,
// initialData: user,
builder: (context, userSnapshot) { builder: (context, userSnapshot) {
if (userSnapshot.data == null) { if (userSnapshot.data == null) {
settingsBloc.getUserProfile(context); settingsBloc.getUserProfile(context);
@@ -139,17 +135,6 @@ class _SettingsScreenState extends State<SettingsScreen> {
); );
} }
// void getUserProfile() async {
// try {
// user = await apiServices.getUserDetail();
// settingsBloc.sinkUserProfile.add(user);
// } catch (e) {
// if (!mounted) return;
// showErrorTopSnackBarCustom(
// context, e.toString());
// }
// }
String getAvatarContent(String username) { String getAvatarContent(String username) {
String name = ""; String name = "";
if (username.isNotEmpty) { if (username.isNotEmpty) {

View File

@@ -1,6 +1,7 @@
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/utils/app_logger_utils.dart';
import 'package:sfm_app/product/utils/responsive_text_utils.dart'; import 'package:sfm_app/product/utils/responsive_text_utils.dart';
import '../theme/app_theme_light.dart'; import '../theme/app_theme_light.dart';
@@ -169,3 +170,15 @@ extension TextStyleExtention on BuildContext {
TextStyle get headlineLargeTextStyle => TextStyle get headlineLargeTextStyle =>
Theme.of(this).textTheme.headlineLarge!; Theme.of(this).textTheme.headlineLarge!;
} }
extension FutureExtension<T> on Future<T> {
Future<T> handleApiError() async {
try {
return await this;
} catch (e) {
AppLoggerUtils.error(e.toString());
return Future.error(e);
}
}
}

View File

@@ -2,6 +2,8 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import '../utils/app_logger_utils.dart';
import '../constant/status_code/status_code_constants.dart'; import '../constant/status_code/status_code_constants.dart';
import '../cache/local_manager.dart'; import '../cache/local_manager.dart';
@@ -39,7 +41,8 @@ class NetworkManager {
Future<String> getDataFromServer(String path) async { Future<String> getDataFromServer(String path) async {
try { try {
final url = Uri.https(ApplicationConstants.DOMAIN, path); final url = Uri.https(ApplicationConstants.DOMAIN, path);
log("[${DateTime.now().toLocal().toString().split(' ')[1]}] GET url: $url"); AppLoggerUtils.info("GET url: $url");
// log("[${DateTime.now().toLocal().toString().split(' ')[1]}] GET url: $url");
final headers = await getHeaders(); final headers = await getHeaders();
final response = await http.get(url, headers: headers).timeout( final response = await http.get(url, headers: headers).timeout(
Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT), Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT),
@@ -53,7 +56,8 @@ class NetworkManager {
throw Exception('Lỗi server: ${response.statusCode}'); throw Exception('Lỗi server: ${response.statusCode}');
} }
} catch (e, stackTrace) { } catch (e, stackTrace) {
log('Lỗi khi lấy dữ liệu: $e, StackTrace: $stackTrace'); // AppLoggerUtils.error(message)
// log('Lỗi khi lấy dữ liệu: $e, StackTrace: $stackTrace');
throw Exception('Lỗi khi lấy dữ liệu: $e'); throw Exception('Lỗi khi lấy dữ liệu: $e');
} }
} }
@@ -73,7 +77,8 @@ class NetworkManager {
String path, Map<String, dynamic> params) async { String path, Map<String, dynamic> params) async {
try { try {
final url = Uri.https(ApplicationConstants.DOMAIN, path, params); final url = Uri.https(ApplicationConstants.DOMAIN, path, params);
log("[${DateTime.now().toLocal().toString().split(' ')[1]}] GET Params url: $url"); AppLoggerUtils.info("GET Params url: $url");
// log("[${DateTime.now().toLocal().toString().split(' ')[1]}] GET Params url: $url");
final headers = await getHeaders(); final headers = await getHeaders();
final response = await http.get(url, headers: headers).timeout( final response = await http.get(url, headers: headers).timeout(
Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT), Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT),
@@ -90,16 +95,16 @@ class NetworkManager {
log('Lỗi khi lấy dữ liệu: $e, StackTrace: $stackTrace'); log('Lỗi khi lấy dữ liệu: $e, StackTrace: $stackTrace');
throw Exception('Lỗi khi lấy dữ liệu: $e'); throw Exception('Lỗi khi lấy dữ liệu: $e');
} }
final url = Uri.https(ApplicationConstants.DOMAIN, path, params); // final url = Uri.https(ApplicationConstants.DOMAIN, path, params);
log("[${DateTime.now().toLocal().toString().split(' ')[1]}] GET Params url: $url"); // log("[${DateTime.now().toLocal().toString().split(' ')[1]}] GET Params url: $url");
final headers = await getHeaders(); // final headers = await getHeaders();
final response = await http.get(url, headers: headers); // final response = await http.get(url, headers: headers);
if (response.statusCode == StatusCodeConstants.CREATED || // if (response.statusCode == StatusCodeConstants.CREATED ||
response.statusCode == StatusCodeConstants.OK) { // response.statusCode == StatusCodeConstants.OK) {
return response.body; // return response.body;
} else { // } else {
return ""; // return "";
} // }
} }
/// Creates new data on the server using a POST request. /// Creates new data on the server using a POST request.
@@ -109,7 +114,8 @@ class NetworkManager {
Future<int> createDataInServer(String path, Map<String, dynamic> body) async { Future<int> createDataInServer(String path, Map<String, dynamic> body) async {
try { try {
final url = Uri.https(ApplicationConstants.DOMAIN, path); final url = Uri.https(ApplicationConstants.DOMAIN, path);
log("[${DateTime.now().toLocal().toString().split(' ')[1]}] POST url: $url"); AppLoggerUtils.info("POST url: $url");
// log("[${DateTime.now().toLocal().toString().split(' ')[1]}] POST url: $url");
final headers = await getHeaders(); final headers = await getHeaders();
final response = await http final response = await http
.post(url, headers: headers, body: jsonEncode(body)) .post(url, headers: headers, body: jsonEncode(body))
@@ -137,7 +143,8 @@ class NetworkManager {
Future<int> updateDataInServer(String path, Map<String, dynamic> body) async { Future<int> updateDataInServer(String path, Map<String, dynamic> body) async {
try { try {
final url = Uri.https(ApplicationConstants.DOMAIN, path); final url = Uri.https(ApplicationConstants.DOMAIN, path);
log("[${DateTime.now().toLocal().toString().split(' ')[1]}] PUT url: $url"); AppLoggerUtils.info("PUT url: $url");
// log("[${DateTime.now().toLocal().toString().split(' ')[1]}] PUT url: $url");
final headers = await getHeaders(); final headers = await getHeaders();
final response = final response =
await http.put(url, headers: headers, body: jsonEncode(body)).timeout( await http.put(url, headers: headers, body: jsonEncode(body)).timeout(
@@ -166,7 +173,8 @@ class NetworkManager {
Future<int> deleteDataInServer(String path) async { Future<int> deleteDataInServer(String path) async {
try { try {
final url = Uri.https(ApplicationConstants.DOMAIN, path); final url = Uri.https(ApplicationConstants.DOMAIN, path);
log("[${DateTime.now().toLocal().toString().split(' ')[1]}] DELETE url: $url"); // log("[${DateTime.now().toLocal().toString().split(' ')[1]}] DELETE url: $url");
AppLoggerUtils.info("DELETE url: $url");
final headers = await getHeaders(); final headers = await getHeaders();
final response = await http.delete(url, headers: headers).timeout( final response = await http.delete(url, headers: headers).timeout(
Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT), Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT),

View File

@@ -5,7 +5,8 @@ import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:sfm_app/product/shared/model/province_model.dart'; import '../shared/model/province_model.dart';
import '../utils/app_logger_utils.dart';
import '../../feature/device_log/device_logs_model.dart'; import '../../feature/device_log/device_logs_model.dart';
import '../../feature/devices/device_model.dart'; import '../../feature/devices/device_model.dart';
import '../../feature/home/device_alias_model.dart'; import '../../feature/home/device_alias_model.dart';
@@ -26,6 +27,8 @@ import '../constant/enums/local_keys_enums.dart';
import '../network/network_manager.dart'; import '../network/network_manager.dart';
class APIServices { class APIServices {
Map<String, String> headers = { Map<String, String> headers = {
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -52,12 +55,10 @@ class APIServices {
return headers; return headers;
} }
Future<T> executeApiCall<T>( Future<T> executeApiCall<T>(Future<dynamic> Function() apiCall,
Future<dynamic> Function() apiCall, { {T Function(dynamic)? parser,
T Function(dynamic)? parser,
String errorMessage = 'Lỗi khi gọi API', String errorMessage = 'Lỗi khi gọi API',
T Function(int)? statusCodeHandler, // Thêm handler cho statusCode T Function(int)? statusCodeHandler}) async {
}) async {
try { try {
final response = await apiCall().timeout( final response = await apiCall().timeout(
Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT), Duration(seconds: ApplicationConstants.CALL_API_TIMEOUT),
@@ -81,11 +82,38 @@ class APIServices {
throw Exception('Dữ liệu trả về rỗng'); throw Exception('Dữ liệu trả về rỗng');
} }
} catch (e, stackTrace) { } catch (e, stackTrace) {
// log('Lỗi API: $e, StackTrace: $stackTrace'); AppLoggerUtils.error("Lỗi gọi API", e, stackTrace);
throw Exception('$errorMessage: $e'); throw Exception('$errorMessage: $e');
} }
} }
/// Most Used Function
// Future<T> execute<T>(Future<T> Function() apiCall) async {
// try {
// return await apiCall();
// } catch (e) {
// AppLoggerUtils.error(e.toString());
// return Future.error(e);
// }
// }
Future<T> execute<T>(
BuildContext context,
Future<T> Function() apiCall, {
bool checkMounted = true,
}) async {
try {
return await apiCall();
} catch (e) {
if (checkMounted && !context.mounted) {
return Future.error('Widget not mounted');
}
showErrorTopSnackBarCustom(context, "Lỗi hệ thống");
return Future.error(e);
}
}
Future<String> login(String path, Map<String, dynamic> loginRequest) async { Future<String> login(String path, Map<String, dynamic> loginRequest) async {
final url = Uri.https(ApplicationConstants.DOMAIN, path); final url = Uri.https(ApplicationConstants.DOMAIN, path);
final headers = await getHeaders(); final headers = await getHeaders();
@@ -229,7 +257,8 @@ class APIServices {
); );
} }
Future<int> updateDeviceNotificationSettings(String thingID, Map<String, int> data) async { Future<int> updateDeviceNotificationSettings(
String thingID, Map<String, int> data) async {
Map<String, dynamic> body = {"thing_id": thingID, "notifi_settings": data}; Map<String, dynamic> body = {"thing_id": thingID, "notifi_settings": data};
return executeApiCall( return executeApiCall(
() => NetworkManager.instance!.updateDataInServer( () => NetworkManager.instance!.updateDataInServer(
@@ -279,7 +308,7 @@ class APIServices {
.getDataFromServer(APIPathConstants.PROVINCES_PATH), .getDataFromServer(APIPathConstants.PROVINCES_PATH),
parser: (json) => Province.fromJsonDynamicList(json['items']), parser: (json) => Province.fromJsonDynamicList(json['items']),
errorMessage: 'Lỗi khi GET /${APIPathConstants.PROVINCES_PATH}'); errorMessage: 'Lỗi khi GET /${APIPathConstants.PROVINCES_PATH}');
;
} }
Future<List<Province>> getProvincesByName(String name) async { Future<List<Province>> getProvincesByName(String name) async {
@@ -290,7 +319,7 @@ class APIServices {
parser: (json) => Province.fromJsonDynamicList(json['items']), parser: (json) => Province.fromJsonDynamicList(json['items']),
errorMessage: 'Lỗi khi GET /${APIPathConstants.PROVINCES_PATH}/$name', errorMessage: 'Lỗi khi GET /${APIPathConstants.PROVINCES_PATH}/$name',
); );
;
} }
Future<Province> getProvinceByID(String provinceID) async { Future<Province> getProvinceByID(String provinceID) async {

View File

@@ -0,0 +1,26 @@
import 'package:flutter/material.dart';
class SharedRocketContainer extends CustomClipper<Path> {
@override
Path getClip(Size size) {
final double width = size.width;
final double height = size.height;
const double pointyWidth = 20.0;
Path path = Path();
path.moveTo(0, 0);
path.lineTo(width - pointyWidth, 0);
path.lineTo(width, height / 2);
path.lineTo(width - pointyWidth, height);
path.lineTo(0, height);
path.close();
return path;
}
@override
bool shouldReclip(CustomClipper<Path> oldClipper) {
return false;
}
}

View File

@@ -13,6 +13,7 @@ class AppThemeDark extends AppTheme {
@override @override
ThemeData get theme => FlexThemeData.dark( ThemeData get theme => FlexThemeData.dark(
scaffoldBackground: Colors.black,
useMaterial3: true, useMaterial3: true,
scheme: FlexScheme.flutterDash, scheme: FlexScheme.flutterDash,
subThemesData: const FlexSubThemesData( subThemesData: const FlexSubThemesData(

View File

@@ -13,6 +13,7 @@ class AppThemeLight extends AppTheme {
@override @override
ThemeData get theme => FlexThemeData.light( ThemeData get theme => FlexThemeData.light(
scaffoldBackground: Colors.white,
useMaterial3: true, useMaterial3: true,
scheme: FlexScheme.flutterDash, scheme: FlexScheme.flutterDash,
bottomAppBarElevation: 20.0, bottomAppBarElevation: 20.0,

View File

@@ -0,0 +1,39 @@
import 'package:logger/logger.dart';
class AppLoggerUtils{
static final Logger _logger = Logger(
printer: PrettyPrinter(
methodCount: 2,
errorMethodCount: 8,
lineLength: 120,
colors: true,
printEmojis: true,
dateTimeFormat: (DateTime dateTime) {
// Tùy chỉnh định dạng thời gian
return '[${DateTime.now().toLocal().toString().split(' ')[1]}]';
},
// dateTimeFormat: DateTimeFormat.dateAndTime
),
level: Level.debug, // Cấp độ log tối thiểu (có thể thay đổi trong môi trường production)
);
static void debug(String message, [dynamic error, StackTrace? stackTrace]) {
_logger.d(message);
}
static void info(String message, [dynamic error, StackTrace? stackTrace]) {
_logger.i(message);
}
static void warning(String message, [dynamic error, StackTrace? stackTrace]) {
_logger.w(message, error: error, stackTrace: stackTrace);
}
static void error(String message, [dynamic error, StackTrace? stackTrace]) {
_logger.e(message, error: error, stackTrace: stackTrace);
}
static void trace(String message, [dynamic error, StackTrace? stackTrace]) {
_logger.t(message, error: error, stackTrace: stackTrace);
}
}

View File

@@ -557,6 +557,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.1"
logger:
dependency: "direct main"
description:
name: logger
sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1
url: "https://pub.dev"
source: hosted
version: "2.5.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:

View File

@@ -48,6 +48,7 @@ dependencies:
url_launcher: ^6.3.1 url_launcher: ^6.3.1
app_settings: ^5.1.1 app_settings: ^5.1.1
lottie: ^3.3.1 lottie: ^3.3.1
logger: ^2.5.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: