Fix bugs in app

This commit is contained in:
anhtunz
2025-03-31 10:42:42 +07:00
parent ba9a3d95f6
commit b830d76d23
37 changed files with 299 additions and 572 deletions

View File

@@ -89,7 +89,7 @@ class DevicesManagerBloc extends BlocBase {
if (state != -2) { if (state != -2) {
body = body =
await apiServices.getOwnerDevieByState({"state": state.toString()}); await apiServices.getOwnerDeviceByState({"state": state.toString()});
} else { } else {
body = await apiServices.getOwnerDevices(); body = await apiServices.getOwnerDevices();
} }

View File

@@ -5,79 +5,22 @@ 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 allDevicesAlias = StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkAllDevicesAlias =>
allDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamAllDevicesAlias =>
allDevicesAlias.stream;
final onlineDevicesAlias = final allDevicesAliasMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast();
StreamController<List<DeviceWithAlias>>.broadcast(); StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasMap =>
StreamSink<List<DeviceWithAlias>> get sinkOnlineDevicesAlias => allDevicesAliasMap.sink;
onlineDevicesAlias.sink; Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasMap =>
Stream<List<DeviceWithAlias>> get streamOnlineDevicesAlias => allDevicesAliasMap.stream;
onlineDevicesAlias.stream;
final offlineDevicesAlias = final allDevicesAliasJoinedMap = StreamController<Map<String,List<DeviceWithAlias>>>.broadcast();
StreamController<List<DeviceWithAlias>>.broadcast(); StreamSink<Map<String,List<DeviceWithAlias>>> get sinkAllDevicesAliasJoinedMap =>
StreamSink<List<DeviceWithAlias>> get sinkOfflineDevicesAlias => allDevicesAliasJoinedMap.sink;
offlineDevicesAlias.sink; Stream<Map<String,List<DeviceWithAlias>>> get streamAllDevicesAliasJoinedMap =>
Stream<List<DeviceWithAlias>> get streamOfflineDevicesAlias => allDevicesAliasJoinedMap.stream;
offlineDevicesAlias.stream;
final warningDevicesAlias = final countNotification = StreamController<int>.broadcast();
StreamController<List<DeviceWithAlias>>.broadcast(); StreamSink<int> get sinkCountNotification => countNotification.sink;
StreamSink<List<DeviceWithAlias>> get sinkWarningDevicesAlias => Stream<int> get streamCountNotification => countNotification.stream;
warningDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamWarningDevicesAlias =>
warningDevicesAlias.stream;
final notUseDevicesAlias =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkNotUseDevicesAlias =>
notUseDevicesAlias.sink;
Stream<List<DeviceWithAlias>> get streamNotUseDevicesAlias =>
notUseDevicesAlias.stream;
final allDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkAllDevicesAliasJoined =>
allDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamAllDevicesAliasJoined =>
allDevicesAliasJoined.stream;
final onlineDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkOnlineDevicesAliasJoined =>
onlineDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamOnlineDevicesAliasJoined =>
onlineDevicesAliasJoined.stream;
final offlineDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkOfflineDevicesAliasJoined =>
offlineDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamOfflineDevicesAliasJoined =>
offlineDevicesAliasJoined.stream;
final warningDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkWarningDevicesAliasJoined =>
warningDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamWarningDevicesAliasJoined =>
warningDevicesAliasJoined.stream;
final notUseDevicesAliasJoined =
StreamController<List<DeviceWithAlias>>.broadcast();
StreamSink<List<DeviceWithAlias>> get sinkNotUseDevicesAliasJoined =>
notUseDevicesAliasJoined.sink;
Stream<List<DeviceWithAlias>> get streamNotUseDevicesAliasJoined =>
notUseDevicesAliasJoined.stream;
final countNotitication = StreamController<int>.broadcast();
StreamSink<int> get sinkCountNotitication => countNotitication.sink;
Stream<int> get streamCountNotitication => countNotitication.stream;
final ownerDevicesStatus = final ownerDevicesStatus =
StreamController<Map<String, List<DeviceWithAlias>>>.broadcast(); StreamController<Map<String, List<DeviceWithAlias>>>.broadcast();
@@ -86,7 +29,6 @@ class HomeBloc extends BlocBase {
Stream<Map<String, List<DeviceWithAlias>>> get streamOwnerDevicesStatus => Stream<Map<String, List<DeviceWithAlias>>> get streamOwnerDevicesStatus =>
ownerDevicesStatus.stream; ownerDevicesStatus.stream;
@override @override
void dispose() {} void dispose() {}
} }

View File

@@ -13,7 +13,7 @@ import '../../../../product/constant/enums/local_keys_enums.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/constant/icon/icon_constants.dart'; import '../../../../product/constant/icon/icon_constants.dart';
import '../../../../product/extention/context_extention.dart'; import '../../../../product/extension/context_extension.dart';
import '../../../../product/constant/image/image_constants.dart'; import '../../../../product/constant/image/image_constants.dart';
import '../../../../product/services/language_services.dart'; import '../../../../product/services/language_services.dart';
import '../../../../bloc/login_bloc.dart'; import '../../../../bloc/login_bloc.dart';

View File

@@ -1,7 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../product/extention/context_extention.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';

View File

@@ -7,7 +7,7 @@ import 'widgets/tag_widget.dart';
import '../devices/device_model.dart'; import '../devices/device_model.dart';
import '../../bloc/device_logs_bloc.dart'; import '../../bloc/device_logs_bloc.dart';
import '../../product/constant/icon/icon_constants.dart'; import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart'; import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';
import '../../product/shared/shared_snack_bar.dart'; import '../../product/shared/shared_snack_bar.dart';
import '../../product/utils/date_time_utils.dart'; import '../../product/utils/date_time_utils.dart';

View File

@@ -7,7 +7,7 @@ import '../../product/constant/enums/role_enums.dart';
import '../../product/services/api_services.dart'; import '../../product/services/api_services.dart';
import '../../product/utils/qr_utils.dart'; import '../../product/utils/qr_utils.dart';
import '../../product/constant/icon/icon_constants.dart'; import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart'; import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';
addNewDevice(BuildContext context, String role) async { addNewDevice(BuildContext context, String role) async {

View File

@@ -2,14 +2,14 @@ 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 'package:sfm_app/feature/device_log/device_logs_model.dart';
import 'package:sfm_app/product/constant/image/image_constants.dart';
import 'package:sfm_app/product/shared/shared_line_chart.dart';
import 'package:simple_ripple_animation/simple_ripple_animation.dart'; import 'package:simple_ripple_animation/simple_ripple_animation.dart';
import 'package:sfm_app/feature/device_log/device_logs_model.dart';
import '../../../product/constant/image/image_constants.dart';
import '../../../product/shared/shared_line_chart.dart';
import '../../../product/shared/shared_curve.dart'; import '../../../product/shared/shared_curve.dart';
import '../device_model.dart'; import '../device_model.dart';
import '../../../product/base/bloc/base_bloc.dart'; import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';
@@ -18,7 +18,9 @@ import '../../../bloc/device_detail_bloc.dart';
class DetailDeviceScreen extends StatefulWidget { class DetailDeviceScreen extends StatefulWidget {
const DetailDeviceScreen({super.key, required this.thingID}); const DetailDeviceScreen({super.key, required this.thingID});
final String thingID; final String thingID;
@override @override
State<DetailDeviceScreen> createState() => _DetailDeviceScreenState(); State<DetailDeviceScreen> createState() => _DetailDeviceScreenState();
} }
@@ -44,18 +46,29 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
late DetailDeviceBloc detailDeviceBloc; late DetailDeviceBloc detailDeviceBloc;
Completer<GoogleMapController> controller = Completer(); Completer<GoogleMapController> controller = Completer();
CameraPosition initialCamera = const CameraPosition( CameraPosition initialCamera =
target: LatLng(20.966048511844402, 105.74977710843086), zoom: 15); const CameraPosition(target: LatLng(20.966048511844402, 105.74977710843086), zoom: 15);
Timer? getDeviceDetailTimer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
detailDeviceBloc = BlocProvider.of(context); detailDeviceBloc = BlocProvider.of(context);
const duration = Duration(seconds: 10);
getDeviceDetailTimer = Timer.periodic(
duration,
(Timer t) => detailDeviceBloc.getDeviceDetail(
context,
widget.thingID,
controller,
),
);
} }
TextStyle textstyle = const TextStyle( @override
fontSize: 25, void dispose() {
fontWeight: FontWeight.w600, getDeviceDetailTimer?.cancel();
); }
BoxDecoration boxDecoration = BoxDecoration( BoxDecoration boxDecoration = BoxDecoration(
borderRadius: BorderRadius.circular(15), borderRadius: BorderRadius.circular(15),
@@ -105,8 +118,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
children: [ children: [
Positioned.fill( Positioned.fill(
child: Image.asset( child: Image.asset(
ImageConstants.instance ImageConstants.instance.getImage('smoke-detector'),
.getImage('smoke-detector'),
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
), ),
@@ -116,11 +128,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
width: 400, width: 400,
// color: Colors.blueAccent, // color: Colors.blueAccent,
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
margin: const EdgeInsets.fromLTRB( margin: const EdgeInsets.fromLTRB(0, 0, 0, 50),
0, 0, 0, 50),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
const SizedBox(), const SizedBox(),
Text( Text(
@@ -146,14 +156,13 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
height: context.dynamicHeight(0.08), height: context.dynamicHeight(0.08),
width: context.dynamicWidth(0.5), width: context.dynamicWidth(0.5),
decoration: BoxDecoration( decoration: BoxDecoration(
color: DeviceUtils.instance.getTableRowColor( color: DeviceUtils.instance
deviceSnapshot.data?.state ?? 3), .getTableRowColor(deviceSnapshot.data?.state ?? 3),
borderRadius: BorderRadius.circular(50), borderRadius: BorderRadius.circular(50),
), ),
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceAround,
MainAxisAlignment.spaceAround,
children: [ children: [
SizedBox( SizedBox(
height: context.mediumValue, height: context.mediumValue,
@@ -161,18 +170,17 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: deviceSnapshot.data?.state == 1 child: deviceSnapshot.data?.state == 1
? RippleAnimation( ? RippleAnimation(
color: Colors.red, color: Colors.red,
delay: context delay: context.dynamicMilliSecondDuration(
.dynamicMilliSecondDuration(
800, 800,
), ),
repeat: true, repeat: true,
minRadius: 10, minRadius: 10,
ripplesCount: 5, ripplesCount: 5,
duration: context duration: context.dynamicMilliSecondDuration(
.dynamicMilliSecondDuration(
1800, 1800,
), ),
child: CircleAvatar( child: CircleAvatar(
backgroundColor: Colors.transparent,
minRadius: context.mediumValue, minRadius: context.mediumValue,
maxRadius: context.mediumValue, maxRadius: context.mediumValue,
backgroundImage: AssetImage( backgroundImage: AssetImage(
@@ -183,9 +191,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
), ),
) )
: CircleAvatar( : CircleAvatar(
backgroundColor: DeviceUtils backgroundColor:
.instance DeviceUtils.instance.getTableRowColor(
.getTableRowColor(
deviceSnapshot.data?.state ?? 3, deviceSnapshot.data?.state ?? 3,
), ),
minRadius: context.mediumValue, minRadius: context.mediumValue,
@@ -230,12 +237,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Padding( child: Padding(
padding: context.paddingLow, padding: context.paddingLow,
child: Column( child: Column(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
appLocalization(context) appLocalization(context)
@@ -254,8 +259,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
sensorSnapshot.data!['sensorCsq'], sensorSnapshot.data!['sensorCsq'],
), ),
size: 30, size: 30,
color: DeviceUtils.instance color: DeviceUtils.instance.getSignalIconColor(
.getSignalIconColor(
context, context,
sensorSnapshot.data!['sensorCsq'], sensorSnapshot.data!['sensorCsq'],
), ),
@@ -264,10 +268,8 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
], ],
), ),
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.start,
MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Container( Container(
height: context.dynamicHeight(0.09), height: context.dynamicHeight(0.09),
@@ -275,11 +277,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Text( child: Text(
sensorSnapshot.data!['sensorCsq'], sensorSnapshot.data!['sensorCsq'],
style: TextStyle( style: TextStyle(
color: DeviceUtils.instance color: DeviceUtils.instance.getSignalIconColor(
.getSignalIconColor(
context, context,
sensorSnapshot sensorSnapshot.data!['sensorCsq'],
.data!['sensorCsq'],
), ),
fontSize: 40, fontSize: 40,
fontWeight: FontWeight.w900, fontWeight: FontWeight.w900,
@@ -299,12 +299,10 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Padding( child: Padding(
padding: context.paddingLow, padding: context.paddingLow,
child: Column( child: Column(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
appLocalization(context) appLocalization(context)
@@ -318,18 +316,14 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
height: context.dynamicWidth(0.12), height: context.dynamicWidth(0.12),
width: context.dynamicWidth(0.12), width: context.dynamicWidth(0.12),
child: Image.asset( child: Image.asset(
DeviceUtils.instance DeviceUtils.instance.getDeviceBatteryImg(
.getDeviceBatteryImg(
int.parse( int.parse(
sensorSnapshot sensorSnapshot.data!['sensorBattery'],
.data!['sensorBattery'],
), ),
), ),
color: DeviceUtils.instance color: DeviceUtils.instance.getDeviceBatteryColor(
.getDeviceBatteryColor(
int.parse( int.parse(
sensorSnapshot sensorSnapshot.data!['sensorBattery'],
.data!['sensorBattery'],
), ),
), ),
), ),
@@ -337,23 +331,18 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
], ],
), ),
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.start,
MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.center,
crossAxisAlignment:
CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
Container( Container(
height: context.dynamicHeight(0.09), height: context.dynamicHeight(0.09),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
sensorSnapshot sensorSnapshot.data!['sensorBattery'],
.data!['sensorBattery'],
style: TextStyle( style: TextStyle(
color: DeviceUtils.instance color: DeviceUtils.instance.getDeviceBatteryColor(
.getDeviceBatteryColor(
int.parse( int.parse(
sensorSnapshot sensorSnapshot.data!['sensorBattery'],
.data!['sensorBattery'],
), ),
), ),
fontSize: 50, fontSize: 50,
@@ -371,11 +360,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Text( child: Text(
'%', '%',
style: TextStyle( style: TextStyle(
color: DeviceUtils.instance color: DeviceUtils.instance.getDeviceBatteryColor(
.getDeviceBatteryColor(
int.parse( int.parse(
sensorSnapshot sensorSnapshot.data!['sensorBattery'],
.data!['sensorBattery'],
), ),
), ),
fontSize: 30, fontSize: 30,
@@ -403,8 +390,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Column( child: Column(
children: [ children: [
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
appLocalization(context) appLocalization(context)
@@ -419,11 +405,9 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
width: context.dynamicWidth(0.12), width: context.dynamicWidth(0.12),
child: Image.asset( child: Image.asset(
'assets/icons/temperature.png', 'assets/icons/temperature.png',
color: DeviceUtils.instance color: DeviceUtils.instance.getDeviceTempColor(
.getDeviceTempColor(
int.parse( int.parse(
sensorSnapshot sensorSnapshot.data!['sensorTemp'],
.data!['sensorTemp'],
), ),
), ),
), ),
@@ -439,28 +423,20 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
width: double.infinity, width: double.infinity,
height: 20, height: 20,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.grey color: Colors.grey.withValues(alpha: 0.3),
.withValues(alpha: 0.3), borderRadius: BorderRadius.circular(10),
borderRadius:
BorderRadius.circular(10),
), ),
), ),
LayoutBuilder( LayoutBuilder(
builder: (context, constraints) => builder: (context, constraints) => Container(
Container(
width: constraints.maxWidth * width: constraints.maxWidth *
(int.parse(sensorSnapshot (int.parse(sensorSnapshot.data!['sensorTemp']) / 75),
.data!['sensorTemp']) /
75),
height: 20, height: 20,
decoration: BoxDecoration( decoration: BoxDecoration(
color: DeviceUtils.instance color: DeviceUtils.instance.getDeviceTempColor(
.getDeviceTempColor( int.parse(sensorSnapshot.data!['sensorTemp']),
int.parse(sensorSnapshot
.data!['sensorTemp']),
), ),
borderRadius: borderRadius: BorderRadius.circular(10),
BorderRadius.circular(10),
), ),
), ),
) )
@@ -470,17 +446,14 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
height: 5, height: 5,
), ),
Row( Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
"${sensorSnapshot.data!['sensorTemp']} °C", "${sensorSnapshot.data!['sensorTemp']} °C",
style: TextStyle( style: TextStyle(
color: DeviceUtils.instance color: DeviceUtils.instance.getDeviceTempColor(
.getDeviceTempColor(
int.parse( int.parse(
sensorSnapshot sensorSnapshot.data!['sensorTemp'],
.data!['sensorTemp'],
), ),
), ),
fontSize: 30, fontSize: 30,
@@ -507,8 +480,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
appLocalization(context) appLocalization(context).paginated_data_table_column_devicePower,
.paginated_data_table_column_devicePower,
style: const TextStyle( style: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@@ -532,8 +504,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
stream: detailDeviceBloc.streamSensorTemps, stream: detailDeviceBloc.streamSensorTemps,
builder: (context, sensorTempsSnapshot) { builder: (context, sensorTempsSnapshot) {
if (sensorTempsSnapshot.data == null) { if (sensorTempsSnapshot.data == null) {
detailDeviceBloc detailDeviceBloc.getNearerSensorValue(widget.thingID);
.getNearerSensorValue(widget.thingID);
return const AspectRatio( return const AspectRatio(
aspectRatio: 3, aspectRatio: 3,
child: Center( child: Center(
@@ -552,8 +523,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
child: Container( child: Container(
margin: context.paddingLow, margin: context.paddingLow,
child: sharedLineChart( child: sharedLineChart(
appLocalization(context) appLocalization(context).detail_device_volt_message,
.detail_device_volt_message,
sensorTempsSnapshot.data ?? [], sensorTempsSnapshot.data ?? [],
), ),
), ),
@@ -580,48 +550,33 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
Radius.circular(15), Radius.circular(15),
), ),
), ),
child: deviceSnapshot child: deviceSnapshot.data!.settings!.latitude != ""
.data!.settings!.latitude !=
""
? StreamBuilder<String>( ? StreamBuilder<String>(
stream: detailDeviceBloc stream: detailDeviceBloc.streamDeviceLocation,
.streamDeviceLocation,
builder: (context, locationSnapshot) { builder: (context, locationSnapshot) {
if (locationSnapshot.data == null) { if (locationSnapshot.data == null) {
detailDeviceBloc.findLocation( detailDeviceBloc.findLocation(
context, context, deviceSnapshot.data!.areaPath!);
deviceSnapshot
.data!.areaPath!);
} }
return GoogleMap( return GoogleMap(
initialCameraPosition: initialCameraPosition: initialCamera,
initialCamera,
mapType: MapType.normal, mapType: MapType.normal,
markers: { markers: {
Marker( Marker(
infoWindow: InfoWindow( infoWindow: InfoWindow(
title: title: locationSnapshot.data ?? "",
locationSnapshot.data ??
"",
), ),
markerId: MarkerId( markerId: MarkerId(deviceSnapshot.data!.thingId!),
deviceSnapshot
.data!.thingId!),
position: LatLng( position: LatLng(
double.parse(deviceSnapshot double.parse(
.data! deviceSnapshot.data!.settings!.latitude!),
.settings! double.parse(
.latitude!), deviceSnapshot.data!.settings!.longitude!),
double.parse(deviceSnapshot
.data!
.settings!
.longitude!),
), ),
), ),
}, },
onMapCreated: (mapcontroller) { onMapCreated: (mapcontroller) {
controller controller.complete(mapcontroller);
.complete(mapcontroller);
}, },
mapToolbarEnabled: false, mapToolbarEnabled: false,
zoomControlsEnabled: false, zoomControlsEnabled: false,
@@ -636,8 +591,7 @@ class _DetailDeviceScreenState extends State<DetailDeviceScreen> {
), ),
), ),
Text( Text(
appLocalization(context) appLocalization(context).device_update_location,
.device_update_location,
style: const TextStyle( style: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

View File

@@ -5,7 +5,7 @@ import '../device_model.dart';
import '../../../bloc/device_update_bloc.dart'; import '../../../bloc/device_update_bloc.dart';
import 'map_dialog.dart'; import 'map_dialog.dart';
import '../../../product/base/bloc/base_bloc.dart'; import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.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';

View File

@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart' ; import 'package:google_maps_flutter/google_maps_flutter.dart' ;
import '../../../bloc/device_update_bloc.dart'; import '../../../bloc/device_update_bloc.dart';
import '../../../product/constant/app/app_constants.dart'; import '../../../product/constant/app/app_constants.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/shared/find_location_maps/shared_map_search_location.dart'; import '../../../product/shared/find_location_maps/shared_map_search_location.dart';

View File

@@ -13,7 +13,7 @@ import '../../product/base/bloc/base_bloc.dart';
import '../../product/constant/enums/app_route_enums.dart'; import '../../product/constant/enums/app_route_enums.dart';
import '../../product/constant/enums/role_enums.dart'; import '../../product/constant/enums/role_enums.dart';
import '../../product/constant/icon/icon_constants.dart'; import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart'; import '../../product/extension/context_extension.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/utils/device_utils.dart'; import '../../product/utils/device_utils.dart';

View File

@@ -9,7 +9,7 @@ import '../../product/utils/device_utils.dart';
import 'device_alias_model.dart'; import 'device_alias_model.dart';
import 'shared/overview_card.dart'; import 'shared/overview_card.dart';
import '../settings/device_notification_settings/device_notification_settings_model.dart'; import '../settings/device_notification_settings/device_notification_settings_model.dart';
import '../../product/extention/context_extention.dart'; import '../../product/extension/context_extension.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 '../../bloc/home_bloc.dart'; import '../../bloc/home_bloc.dart';
@@ -25,18 +25,9 @@ class HomeScreen extends StatefulWidget {
class _HomeScreenState extends State<HomeScreen> { 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>> allDevicesAliasJoinedMap = {};
List<DeviceWithAlias> devices = []; List<DeviceWithAlias> devices = [];
List<DeviceWithAlias> allDevicesAlias = [];
List<DeviceWithAlias> onlineDevicesAlias = [];
List<DeviceWithAlias> offlineDevicesAlias = [];
List<DeviceWithAlias> warningDevicesAlias = [];
List<DeviceWithAlias> notUseDevicesAlias = [];
List<DeviceWithAlias> allDevicesAliasJoined = [];
List<DeviceWithAlias> onlineDevicesAliasJoined = [];
List<DeviceWithAlias> offlineDevicesAliasJoined = [];
List<DeviceWithAlias> warningDevicesAliasJoined = [];
List<DeviceWithAlias> notUseDevicesAliasJoined = [];
bool isFunctionCall = false; bool isFunctionCall = false;
Timer? getAllDevicesTimer; Timer? getAllDevicesTimer;
int notificationCount = 0; int notificationCount = 0;
@@ -49,8 +40,7 @@ class _HomeScreenState extends State<HomeScreen> {
homeBloc = BlocProvider.of(context); homeBloc = BlocProvider.of(context);
getOwnerAndJoinedDevices(); getOwnerAndJoinedDevices();
const duration = Duration(seconds: 10); const duration = Duration(seconds: 10);
getAllDevicesTimer = getAllDevicesTimer = Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices());
Timer.periodic(duration, (Timer t) => getOwnerAndJoinedDevices());
} }
@override @override
@@ -75,7 +65,7 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
SizedBox(width: context.lowValue), SizedBox(width: context.lowValue),
StreamBuilder<int>( StreamBuilder<int>(
stream: homeBloc.streamCountNotitication, stream: homeBloc.streamCountNotification,
builder: (context, countSnapshot) { builder: (context, countSnapshot) {
return Text( return Text(
"(${countSnapshot.data ?? 0})", "(${countSnapshot.data ?? 0})",
@@ -91,8 +81,7 @@ class _HomeScreenState extends State<HomeScreen> {
child: StreamBuilder<Map<String, List<DeviceWithAlias>>>( child: StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamOwnerDevicesStatus, stream: homeBloc.streamOwnerDevicesStatus,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.data?['state'] != null || if (snapshot.data?['state'] != null || snapshot.data?['battery'] != null) {
snapshot.data?['battery'] != null) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -101,8 +90,7 @@ class _HomeScreenState extends State<HomeScreen> {
...snapshot.data!['state']! ...snapshot.data!['state']!
.map( .map(
(item) => FutureBuilder<Widget>( (item) => FutureBuilder<Widget>(
future: warningCard( future: warningCard(context, apiServices, item),
context, apiServices, item),
builder: (context, warningCardSnapshot) { builder: (context, warningCardSnapshot) {
if (warningCardSnapshot.hasData) { if (warningCardSnapshot.hasData) {
return ConstrainedBox( return ConstrainedBox(
@@ -124,11 +112,7 @@ class _HomeScreenState extends State<HomeScreen> {
.map( .map(
(batteryItem) => FutureBuilder<Widget>( (batteryItem) => FutureBuilder<Widget>(
future: notificationCard( future: notificationCard(
context, context, "lowBattery", appLocalization(context).low_battery_message, batteryItem),
"lowBattery",
"Cảnh báo pin yếu",
batteryItem
),
builder: (context, warningCardSnapshot) { builder: (context, warningCardSnapshot) {
if (warningCardSnapshot.hasData) { if (warningCardSnapshot.hasData) {
return ConstrainedBox( return ConstrainedBox(
@@ -160,8 +144,7 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
SizedBox(width: context.lowValue), SizedBox(width: context.lowValue),
Text( Text(
appLocalization(context) appLocalization(context).notification_description,
.notification_description,
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
softWrap: true, softWrap: true,
@@ -176,85 +159,47 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
), ),
), ),
StreamBuilder<List<DeviceWithAlias>>( StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamAllDevicesAlias, stream: homeBloc.streamAllDevicesAliasMap,
initialData: allDevicesAlias, builder: (context, allDevicesAliasMapSnapshot) {
builder: (context, allDeviceSnapshot) { if (!allDevicesAliasMapSnapshot.hasData ||
return StreamBuilder<List<DeviceWithAlias>>( allDevicesAliasMapSnapshot.data == null) {
stream: homeBloc.streamOnlineDevicesAlias, return const Center(child: CircularProgressIndicator());
initialData: onlineDevicesAlias, }
builder: (context, onlineDeviceSnapshot) { final data = allDevicesAliasMapSnapshot.data!;
return StreamBuilder<List<DeviceWithAlias>>( return OverviewCard(
stream: homeBloc.streamOfflineDevicesAlias, isOwner: true,
initialData: offlineDevicesAlias, total: data['all']?.length ?? 0,
builder: (context, deviceDashboardSnapshot) { active: data['online']?.length ?? 0,
return StreamBuilder<List<DeviceWithAlias>>( inactive: data['offline']?.length ?? 0,
stream: homeBloc.streamWarningDevicesAlias, warning: data['warn']?.length ?? 0,
initialData: warningDevicesAlias, unused: data['not-use']?.length ?? 0);
builder: (context, warningDeviceSnapshot) { }),
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamNotUseDevicesAlias,
initialData: notUseDevicesAlias,
builder: (context, notUseSnapshot) {
return OverviewCard(
isOwner: true,
total: allDeviceSnapshot.data!.length,
active: onlineDeviceSnapshot.data!.length,
inactive:
deviceDashboardSnapshot.data!.length,
warning: warningDeviceSnapshot.data!.length,
unused: notUseSnapshot.data!.length,
);
},
);
},
);
},
);
},
);
},
),
SizedBox(height: context.lowValue), SizedBox(height: context.lowValue),
StreamBuilder<List<DeviceWithAlias>>( StreamBuilder<Map<String, List<DeviceWithAlias>>>(
stream: homeBloc.streamAllDevicesAliasJoined, stream: homeBloc.streamAllDevicesAliasJoinedMap,
initialData: allDevicesAliasJoined, builder: (context, allDevicesAliasJoinedMapSnapshot) {
builder: (context, allDeviceSnapshot) { if (!allDevicesAliasJoinedMapSnapshot.hasData ||
if (allDeviceSnapshot.data?.isEmpty ?? true) { allDevicesAliasJoinedMapSnapshot.data == null) {
return const Center(child: CircularProgressIndicator());
}
final data = allDevicesAliasJoinedMapSnapshot.data!;
final total = data['all']?.length ?? 0;
final active = data['online']?.length ?? 0;
final inactive = data['offline']?.length ?? 0;
final warning = data['warn']?.length ?? 0;
final unused = data['not-use']?.length ?? 0;
if (total == 0 && active == 0 && inactive == 0 && warning == 0 && unused == 0) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return StreamBuilder<List<DeviceWithAlias>>( return OverviewCard(
stream: homeBloc.streamOnlineDevicesAliasJoined, isOwner: false,
initialData: onlineDevicesAliasJoined, total: total,
builder: (context, onlineDeviceSnapshot) { active: active,
return StreamBuilder<List<DeviceWithAlias>>( inactive: inactive,
stream: homeBloc.streamOfflineDevicesAliasJoined, warning: warning,
initialData: offlineDevicesAliasJoined, unused: unused,
builder: (context, deviceDashboardSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamWarningDevicesAliasJoined,
initialData: warningDevicesAliasJoined,
builder: (context, warningDeviceSnapshot) {
return StreamBuilder<List<DeviceWithAlias>>(
stream: homeBloc.streamNotUseDevicesAliasJoined,
initialData: notUseDevicesAliasJoined,
builder: (context, notUseSnapshot) {
return OverviewCard(
isOwner: false,
total: allDeviceSnapshot.data!.length,
active: onlineDeviceSnapshot.data!.length,
inactive:
deviceDashboardSnapshot.data!.length,
warning: warningDeviceSnapshot.data!.length,
unused: notUseSnapshot.data!.length,
);
},
);
},
);
},
);
},
); );
}, },
), ),
@@ -271,8 +216,8 @@ class _HomeScreenState extends State<HomeScreen> {
List<dynamic> result = data["items"]; List<dynamic> result = data["items"];
devices = DeviceWithAlias.fromJsonDynamicList(result); devices = DeviceWithAlias.fromJsonDynamicList(result);
getOwnerDeviceState(devices); getOwnerDeviceState(devices);
getDevicesStatusAlias(devices); checkSettingDevice(devices);
checkSettingdevice(devices); getDeviceStatusAliasMap(devices);
} }
void getOwnerDeviceState(List<DeviceWithAlias> allDevices) async { void getOwnerDeviceState(List<DeviceWithAlias> allDevices) async {
@@ -282,23 +227,21 @@ class _HomeScreenState extends State<HomeScreen> {
ownerDevices.add(device); ownerDevices.add(device);
} }
} }
if (ownerDevicesState.isEmpty || if (ownerDevicesState.isEmpty || ownerDevicesState.length < devices.length) {
ownerDevicesState.length < devices.length) {
ownerDevicesState.clear(); ownerDevicesState.clear();
ownerDevicesStatus.clear(); ownerDevicesStatus.clear();
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
int count = 0; int count = 0;
for (var device in ownerDevices) { for (var device in ownerDevices) {
Map<String, dynamic> sensorMap = DeviceUtils.instance Map<String, dynamic> sensorMap =
.getDeviceSensors(context, device.status?.sensors ?? []); DeviceUtils.instance.getDeviceSensors(context, device.status?.sensors ?? []);
if (device.state == 1 || device.state == 3) { if (device.state == 1 || device.state == 3) {
ownerDevicesStatus["state"] ??= []; ownerDevicesStatus["state"] ??= [];
ownerDevicesStatus["state"]!.add(device); ownerDevicesStatus["state"]!.add(device);
homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus); homeBloc.sinkOwnerDevicesStatus.add(ownerDevicesStatus);
count++; count++;
} }
if (sensorMap['sensorBattery'] != if (sensorMap['sensorBattery'] != appLocalization(context).no_data_message) {
appLocalization(context).no_data_message) {
if (double.parse(sensorMap['sensorBattery']) <= 20) { if (double.parse(sensorMap['sensorBattery']) <= 20) {
ownerDevicesStatus['battery'] ??= []; ownerDevicesStatus['battery'] ??= [];
ownerDevicesStatus['battery']!.add(device); ownerDevicesStatus['battery']!.add(device);
@@ -307,63 +250,61 @@ class _HomeScreenState extends State<HomeScreen> {
} }
} }
notificationCount = count; notificationCount = count;
homeBloc.sinkCountNotitication.add(notificationCount); homeBloc.sinkCountNotification.add(notificationCount);
} }
} }
} }
void getDevicesStatusAlias(List<DeviceWithAlias> devices) async { void getDeviceStatusAliasMap(List<DeviceWithAlias> devices) {
clearAllDeviceStatusAlias(); allDevicesAliasMap.clear();
allDevicesAliasJoinedMap.clear();
for (var key in ['all', 'online', 'offline', 'warning', 'not-use']) {
allDevicesAliasMap[key] = [];
allDevicesAliasJoinedMap[key] = [];
}
for (DeviceWithAlias device in devices) { for (DeviceWithAlias device in devices) {
if (device.isOwner == true) { if (device.isOwner == true) {
allDevicesAlias.add(device); allDevicesAliasMap['all']!.add(device);
if (device.state! == 0 || device.state! == 1) { if (device.state == 0 || device.state == 1) {
onlineDevicesAlias.add(device); allDevicesAliasMap['online']!.add(device);
homeBloc.sinkOnlineDevicesAlias.add(onlineDevicesAlias);
} }
if (device.state! == -1) { if (device.state == -1) {
offlineDevicesAlias.add(device); allDevicesAliasMap['offline']!.add(device);
homeBloc.sinkOfflineDevicesAlias.add(offlineDevicesAlias);
} }
if (device.state! == 1) { if (device.state == 1) {
warningDevicesAlias.add(device); allDevicesAliasMap['warning']!.add(device);
homeBloc.sinkWarningDevicesAlias.add(warningDevicesAlias);
} }
if (device.state! == -2) { if (device.state == -2) {
notUseDevicesAlias.add(device); allDevicesAliasMap['not-use']!.add(device);
homeBloc.sinkNotUseDevicesAlias.add(notUseDevicesAlias);
} }
} else { } else {
allDevicesAliasJoined.add(device); allDevicesAliasJoinedMap['all']!.add(device);
if (device.state! == 0 || device.state! == 1) { if (device.state == 0 || device.state == 1) {
onlineDevicesAliasJoined.add(device); allDevicesAliasJoinedMap['online']!.add(device);
homeBloc.sinkOnlineDevicesAliasJoined.add(onlineDevicesAliasJoined);
} }
if (device.state! == -1) { if (device.state == -1) {
offlineDevicesAliasJoined.add(device); allDevicesAliasJoinedMap['offline']!.add(device);
homeBloc.sinkOfflineDevicesAliasJoined.add(offlineDevicesAliasJoined);
} }
if (device.state! == 1) { if (device.state == 1) {
warningDevicesAliasJoined.add(device); allDevicesAliasJoinedMap['warning']!.add(device);
homeBloc.sinkWarningDevicesAliasJoined.add(warningDevicesAliasJoined);
} }
if (device.state! == -2) { if (device.state == -2) {
notUseDevicesAliasJoined.add(device); allDevicesAliasJoinedMap['not-use']!.add(device);
homeBloc.sinkNotUseDevicesAliasJoined.add(notUseDevicesAliasJoined);
} }
} }
} }
// checkSettingdevice(allDevicesAliasJoined);
homeBloc.sinkAllDevicesAlias.add(allDevicesAlias); homeBloc.sinkAllDevicesAliasMap.add(allDevicesAliasMap);
homeBloc.sinkAllDevicesAliasJoined.add(allDevicesAliasJoined); homeBloc.sinkAllDevicesAliasJoinedMap.add(allDevicesAliasJoinedMap);
} }
void checkSettingdevice(List<DeviceWithAlias> devices) async { void checkSettingDevice(List<DeviceWithAlias> devices) async {
if (isFunctionCall) { if (isFunctionCall) {
log("Ham check setting da duoc goi"); log("Ham check setting da duoc goi");
} else { } else {
String? response = String? response = await apiServices.getAllSettingsNotificationOfDevices();
await apiServices.getAllSettingsNotificationOfDevices();
if (response != "") { if (response != "") {
final data = jsonDecode(response); final data = jsonDecode(response);
final result = data['data']; final result = data['data'];
@@ -371,13 +312,11 @@ class _HomeScreenState extends State<HomeScreen> {
List<DeviceNotificationSettings> list = List<DeviceNotificationSettings> list =
DeviceNotificationSettings.mapFromJson(result).values.toList(); DeviceNotificationSettings.mapFromJson(result).values.toList();
// log("List: $list"); // log("List: $list");
Set<String> thingIdsInList = Set<String> thingIdsInList = list.map((device) => device.thingId!).toSet();
list.map((device) => device.thingId!).toSet();
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.");
await apiServices.setupDeviceNotification( await apiServices.setupDeviceNotification(device.thingId!, device.name!);
device.thingId!, device.name!);
} else { } else {
log("All devices are in the notification settings list."); log("All devices are in the notification settings list.");
} }
@@ -388,27 +327,4 @@ class _HomeScreenState extends State<HomeScreen> {
} }
isFunctionCall = true; isFunctionCall = true;
} }
void clearAllDeviceStatusAlias() {
allDevicesAlias.clear();
homeBloc.sinkAllDevicesAlias.add(allDevicesAlias);
onlineDevicesAlias.clear();
homeBloc.sinkOnlineDevicesAlias.add(onlineDevicesAlias);
offlineDevicesAlias.clear();
homeBloc.sinkOfflineDevicesAlias.add(offlineDevicesAlias);
warningDevicesAlias.clear();
homeBloc.sinkWarningDevicesAlias.add(warningDevicesAlias);
notUseDevicesAlias.clear();
homeBloc.sinkNotUseDevicesAlias.add(notUseDevicesAlias);
allDevicesAliasJoined.clear();
homeBloc.sinkAllDevicesAliasJoined.add(allDevicesAliasJoined);
onlineDevicesAliasJoined.clear();
homeBloc.sinkOnlineDevicesAliasJoined.add(onlineDevicesAliasJoined);
offlineDevicesAliasJoined.clear();
homeBloc.sinkOfflineDevicesAliasJoined.add(offlineDevicesAliasJoined);
warningDevicesAliasJoined.clear();
homeBloc.sinkWarningDevicesAliasJoined.add(warningDevicesAliasJoined);
notUseDevicesAliasJoined.clear();
homeBloc.sinkNotUseDevicesAliasJoined.add(notUseDevicesAliasJoined);
}
} }

View File

@@ -6,7 +6,7 @@ import 'package:intl/intl.dart';
import 'package:sfm_app/feature/home/device_alias_model.dart'; import 'package:sfm_app/feature/home/device_alias_model.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/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';

View File

@@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/feature/home/shared/status_card.dart'; import 'status_card.dart';
import 'package:sfm_app/product/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import 'package:sfm_app/product/services/language_services.dart'; import '../../../product/services/language_services.dart';
class OverviewCard extends StatelessWidget { class OverviewCard extends StatelessWidget {
final bool isOwner; final bool isOwner;

View File

@@ -7,7 +7,7 @@ import 'package:badges/badges.dart' as badges;
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';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.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/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';

View File

@@ -1,12 +1,14 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
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 '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';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.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/utils/device_utils.dart'; import '../../../product/utils/device_utils.dart';
@@ -25,10 +27,22 @@ class DetailGroupScreen extends StatefulWidget {
class _DetailGroupScreenState extends State<DetailGroupScreen> { class _DetailGroupScreenState extends State<DetailGroupScreen> {
late DetailGroupBloc detailGroupBloc; late DetailGroupBloc detailGroupBloc;
final scaffoldKey = GlobalKey<ScaffoldState>(); final scaffoldKey = GlobalKey<ScaffoldState>();
Timer? getGroupDetailTimer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
detailGroupBloc = BlocProvider.of(context); detailGroupBloc = BlocProvider.of(context);
const duration = Duration(seconds: 10);
getGroupDetailTimer = Timer.periodic(
duration,
(Timer t) => detailGroupBloc.getGroupDetail(widget.group),
);
}
@override
void dispose() {
getGroupDetailTimer?.cancel();
} }
@override @override

View File

@@ -1,5 +1,7 @@
// ignore_for_file: use_build_context_synchronously // ignore_for_file: use_build_context_synchronously
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@@ -10,26 +12,38 @@ import '../inter_family_widget.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/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import 'groups_widget.dart'; import 'groups_widget.dart';
class GroupsScreen extends StatefulWidget { class GroupsScreen extends StatefulWidget {
const GroupsScreen({super.key, required this.role}); const GroupsScreen({super.key, required this.role});
final String role; final String role;
@override @override
State<GroupsScreen> createState() => _GroupsScreenState(); State<GroupsScreen> createState() => _GroupsScreenState();
} }
class _GroupsScreenState extends State<GroupsScreen> { class _GroupsScreenState extends State<GroupsScreen> {
late InterFamilyBloc interFamilyBloc; late InterFamilyBloc interFamilyBloc;
Timer? getAllGroupsTimer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
interFamilyBloc = BlocProvider.of(context); interFamilyBloc = BlocProvider.of(context);
// interFamilyBloc.getAllGroup(widget.role); const duration = Duration(seconds: 10);
getAllGroupsTimer = Timer.periodic(
duration,
(Timer t) => interFamilyBloc.getAllGroup(widget.role),
);
}
@override
void dispose() {
getAllGroupsTimer?.cancel();
} }
@override @override
@@ -51,56 +65,44 @@ class _GroupsScreenState extends State<GroupsScreen> {
return ListTile( return ListTile(
onTap: () { onTap: () {
context.pushNamed(AppRoutes.GROUP_DETAIL.name, context.pushNamed(AppRoutes.GROUP_DETAIL.name,
pathParameters: { pathParameters: {"groupId": groupsSnapshot.data![index].id!},
"groupId": groupsSnapshot.data![index].id!
},
extra: widget.role); extra: widget.role);
}, },
leading: IconConstants.instance leading: IconConstants.instance.getMaterialIcon(Icons.diversity_2),
.getMaterialIcon(Icons.diversity_2),
title: Text( title: Text(
groupsSnapshot.data![index].name ?? '', groupsSnapshot.data![index].name ?? '',
style: const TextStyle(fontWeight: FontWeight.bold), style: const TextStyle(fontWeight: FontWeight.bold),
), ),
subtitle: subtitle: Text(groupsSnapshot.data![index].description ?? ""),
Text(groupsSnapshot.data![index].description ?? ""), trailing: widget.role == ApplicationConstants.OWNER_GROUP
trailing: ? PopupMenuButton(
widget.role == ApplicationConstants.OWNER_GROUP shape: const RoundedRectangleBorder(
? PopupMenuButton( borderRadius: BorderRadius.only(
shape: const RoundedRectangleBorder( bottomLeft: Radius.circular(8.0),
borderRadius: BorderRadius.only( bottomRight: Radius.circular(8.0),
bottomLeft: Radius.circular(8.0), topLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0), topRight: Radius.circular(8.0),
topLeft: Radius.circular(8.0), ),
topRight: Radius.circular(8.0), ),
), itemBuilder: (ctx) => [
), _buildPopupMenuItem(groupsSnapshot.data![index], context,
itemBuilder: (ctx) => [ appLocalization(context).share_group_title, Icons.share, 4),
_buildPopupMenuItem( _buildPopupMenuItem(
groupsSnapshot.data![index], groupsSnapshot.data![index],
context, context,
appLocalization(context) appLocalization(context).change_group_infomation_title,
.share_group_title, Icons.settings_backup_restore,
Icons.share, 2),
4), _buildPopupMenuItem(
_buildPopupMenuItem( groupsSnapshot.data![index],
groupsSnapshot.data![index], context,
context, appLocalization(context).delete_group_title,
appLocalization(context) Icons.delete_forever_rounded,
.change_group_infomation_title, 3),
Icons.settings_backup_restore, ],
2), icon: const Icon(Icons.more_horiz),
_buildPopupMenuItem( )
groupsSnapshot.data![index], : const SizedBox.shrink(),
context,
appLocalization(context)
.delete_group_title,
Icons.delete_forever_rounded,
3),
],
icon: const Icon(Icons.more_horiz),
)
: const SizedBox.shrink(),
); );
}, },
), ),
@@ -112,16 +114,15 @@ class _GroupsScreenState extends State<GroupsScreen> {
} }
} }
PopupMenuItem _buildPopupMenuItem(Group group, BuildContext context, PopupMenuItem _buildPopupMenuItem(
String title, IconData iconData, int position) { Group group, BuildContext context, String title, IconData iconData, int position) {
return PopupMenuItem( return PopupMenuItem(
onTap: () { onTap: () {
if (title == appLocalization(context).share_group_title) { if (title == appLocalization(context).share_group_title) {
Future.delayed(context.lowDuration, () { Future.delayed(context.lowDuration, () {
shareGroup(context, group); shareGroup(context, group);
}); });
} else if (title == } else if (title == appLocalization(context).change_group_infomation_title) {
appLocalization(context).change_group_infomation_title) {
Future.delayed(context.lowDuration, () { Future.delayed(context.lowDuration, () {
createOrJoinGroupDialog( createOrJoinGroupDialog(
context, context,

View File

@@ -2,7 +2,7 @@ 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/extention/context_extention.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';

View File

@@ -6,7 +6,7 @@ import 'inter_family_widget.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/constant/icon/icon_constants.dart'; import '../../product/constant/icon/icon_constants.dart';
import '../../product/extention/context_extention.dart'; import '../../product/extension/context_extension.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';
class InterFamilyScreen extends StatefulWidget { class InterFamilyScreen extends StatefulWidget {

View File

@@ -5,13 +5,11 @@ import 'dart:developer';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
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:persistent_bottom_nav_bar_v2/persistent-tab-view.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/feature/sound_notification_test/notification_screen.dart'; import '../../product/permission/notification_permission.dart';
import 'package:sfm_app/product/permission/notification_permission.dart';
import '../settings/profile/profile_model.dart'; import '../settings/profile/profile_model.dart';
import '../../product/extention/context_extention.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';
@@ -35,7 +33,6 @@ import '../../product/constant/icon/icon_constants.dart';
import '../../product/constant/lang/language_constants.dart'; import '../../product/constant/lang/language_constants.dart';
import '../../product/services/language_services.dart'; import '../../product/services/language_services.dart';
import '../bell/bell_model.dart'; import '../bell/bell_model.dart';
import '../sound_notification_test/notification_bloc.dart';
class MainScreen extends StatefulWidget { class MainScreen extends StatefulWidget {
const MainScreen({super.key}); const MainScreen({super.key});
@@ -192,6 +189,7 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return StreamBuilder<bool>( return StreamBuilder<bool>(
stream: mainBloc.streamThemeMode, stream: mainBloc.streamThemeMode,
initialData: isLight, initialData: isLight,
@@ -344,7 +342,7 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
controller: controller, controller: controller,
screens: _buildScreens(), screens: _buildScreens(),
items: _navBarsItems(), items: _navBarsItems(),
handleAndroidBackButtonPress: false, handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: true, resizeToAvoidBottomInset: true,
stateManagement: true, stateManagement: true,
backgroundColor: backgroundColor:

View File

@@ -6,7 +6,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'show_direction_widget.dart'; import 'show_direction_widget.dart';
import 'show_nearest_place.dart'; import 'show_nearest_place.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import '../../../bloc/map_bloc.dart'; import '../../../bloc/map_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';

View File

@@ -3,9 +3,9 @@ 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 'package:maps_launcher/maps_launcher.dart'; import 'package:maps_launcher/maps_launcher.dart';
import 'package:sfm_app/product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import 'package:sfm_app/product/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import 'package:sfm_app/product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../bloc/map_bloc.dart'; import '../../../bloc/map_bloc.dart';

View File

@@ -7,7 +7,7 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
import '../../../bloc/map_bloc.dart'; import '../../../bloc/map_bloc.dart';
import 'show_direction_widget.dart'; import 'show_direction_widget.dart';
import '../../../product/constant/icon/icon_constants.dart'; import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.dart';
import '../../../product/services/language_services.dart'; import '../../../product/services/language_services.dart';
import '../../../product/services/map_services.dart'; import '../../../product/services/map_services.dart';
import '../../../product/shared/model/near_by_search_model.dart'; import '../../../product/shared/model/near_by_search_model.dart';

View File

@@ -7,7 +7,7 @@ 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';
import '../../../product/base/bloc/base_bloc.dart'; import '../../../product/base/bloc/base_bloc.dart';
import '../../../product/extention/context_extention.dart'; import '../../../product/extension/context_extension.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';

View File

@@ -6,7 +6,7 @@ import '../../../product/constant/icon/icon_constants.dart';
import '../../../product/services/api_services.dart'; import '../../../product/services/api_services.dart';
import '../../../bloc/settings_bloc.dart'; import '../../../bloc/settings_bloc.dart';
import '../../../product/shared/shared_input_decoration.dart'; import '../../../product/shared/shared_input_decoration.dart';
import '../../../product/extention/context_extention.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';

View File

@@ -5,7 +5,7 @@ import 'package:go_router/go_router.dart';
import '../../product/constant/app/app_constants.dart'; import '../../product/constant/app/app_constants.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/extention/context_extention.dart'; import '../../product/extension/context_extension.dart';
import '../../product/services/api_services.dart'; import '../../product/services/api_services.dart';
import 'profile/profile_model.dart'; import 'profile/profile_model.dart';
import '../../bloc/settings_bloc.dart'; import '../../bloc/settings_bloc.dart';

View File

@@ -1,11 +0,0 @@
import 'package:sfm_app/product/base/bloc/base_bloc.dart';
class NotificationBloc extends BlocBase{
@override
void dispose() {
// TODO: implement dispose
}
}

View File

@@ -1,77 +0,0 @@
// ignore_for_file: avoid_print
import 'dart:math' as math;
import 'dart:developer' as dev;
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'notification_bloc.dart';
import '../../product/base/bloc/base_bloc.dart';
import '../../product/services/notification_services.dart';
class NotificationScreen extends StatefulWidget {
const NotificationScreen({super.key});
@override
State<NotificationScreen> createState() => _NotificationScreenState();
}
class _NotificationScreenState extends State<NotificationScreen> {
late NotificationBloc notificationBloc;
final notificationPlugin = FlutterLocalNotificationsPlugin();
@override
void initState() {
super.initState();
initNotification();
notificationBloc = BlocProvider.of<NotificationBloc>(context);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
onPressed: () async {
showNewAlarmSoundNotification("warning_alarm");
dev.log("Da vao day");
},
child: const Text("Show new Alarm Notification"),
),
],
));
}
Future<void> initNotification() async{
const isSettingAndroid = AndroidInitializationSettings('@mipmap/ic_launcher');
const initSetting = InitializationSettings(android: isSettingAndroid);
await notificationPlugin.initialize(initSetting);
}
Future<void> showNewAlarmSoundNotification(String sound) async {
AndroidNotificationChannel androidNotificationChannel =
AndroidNotificationChannel(
math.Random.secure().nextInt(1000000).toString(),
'high Important Notification',
importance: Importance.max);
AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
"androidNotificationChannel.id.toString()",
androidNotificationChannel.name.toString(),
sound: RawResourceAndroidNotificationSound(sound),
channelDescription: "Channel description",
importance: androidNotificationChannel.importance,
priority: Priority.high,
ticker: 'ticker',
);
final NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
await FlutterLocalNotificationsPlugin().show(0, 'New Notification',
'Sound Notification Example', notificationDetails);
}
}

View File

@@ -1,7 +1,7 @@
import 'package:app_settings/app_settings.dart'; import 'package:app_settings/app_settings.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../extention/context_extention.dart'; import '../../../extension/context_extension.dart';
import '../../../services/language_services.dart'; import '../../../services/language_services.dart';
class RequestPermissionDialog { class RequestPermissionDialog {

View File

@@ -1,6 +1,4 @@
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../../feature/sound_notification_test/notification_bloc.dart';
import '../../../feature/sound_notification_test/notification_screen.dart';
import '../../../bloc/device_detail_bloc.dart'; import '../../../bloc/device_detail_bloc.dart';
import '../../../feature/devices/device_detail/device_detail_screen.dart'; import '../../../feature/devices/device_detail/device_detail_screen.dart';
import '../../../bloc/device_notification_settings_bloc.dart'; import '../../../bloc/device_notification_settings_bloc.dart';
@@ -153,14 +151,6 @@ GoRouter goRouter() {
), ),
transitionsBuilder: transitionsRightToLeft), transitionsBuilder: transitionsRightToLeft),
), ),
GoRoute(
path: "/notification",
name: 'notification',
builder: (context, state) => BlocProvider(
child: const NotificationScreen(),
blocBuilder: () => NotificationBloc(),
),
),
], ],
); );
} }

View File

@@ -11,6 +11,7 @@
"button_fake_fire_message": "False fire alarm", "button_fake_fire_message": "False fire alarm",
"in_progress_message": "In progress", "in_progress_message": "In progress",
"smoke_detecting_message": "Smoke detecting!", "smoke_detecting_message": "Smoke detecting!",
"low_battery_message": "Low Battery!",
"smoke_detecting_message_lowercase": "smoke detecting!", "smoke_detecting_message_lowercase": "smoke detecting!",
"disconnect_message_uppercase": "Disconnected", "disconnect_message_uppercase": "Disconnected",
"disconnect_message_lowercase": "disconnected", "disconnect_message_lowercase": "disconnected",

View File

@@ -11,6 +11,7 @@
"button_fake_fire_message": "Cháy giả?", "button_fake_fire_message": "Cháy giả?",
"in_progress_message": "Đang xử lý", "in_progress_message": "Đang xử lý",
"smoke_detecting_message": "Phát hiện khói!", "smoke_detecting_message": "Phát hiện khói!",
"low_battery_message": "Cảnh báo pin yếu!",
"smoke_detecting_message_lowercase": "Phát hiện khói!", "smoke_detecting_message_lowercase": "Phát hiện khói!",
"disconnect_message_uppercase": "Mất kết nối", "disconnect_message_uppercase": "Mất kết nối",
"disconnect_message_lowercase": "mất kết nối", "disconnect_message_lowercase": "mất kết nối",

View File

@@ -282,7 +282,7 @@ class APIServices {
return data; return data;
} }
Future<String> getOwnerDevieByState(Map<String, dynamic> params) async { Future<String> getOwnerDeviceByState(Map<String, dynamic> params) async {
String? data = await NetworkManager.instance! String? data = await NetworkManager.instance!
.getDataFromServerWithParams(APIPathConstants.DEVICE_PATH, params); .getDataFromServerWithParams(APIPathConstants.DEVICE_PATH, params);
return data; return data;

View File

@@ -128,8 +128,6 @@ class NotificationServices {
void handleMessage(String? payload) { void handleMessage(String? payload) {
dev.log("Handling notification tap with payload: $payload"); dev.log("Handling notification tap with payload: $payload");
// Thêm logic xử lý khi nhấn thông báo ở đây
// Ví dụ: Điều hướng màn hình hoặc xử lý dữ liệu
} }
Future<void> setupInteractMessage() async { Future<void> setupInteractMessage() async {

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../extention/context_extention.dart'; import '../extension/context_extension.dart';
InputDecoration borderRadiusTopLeftAndBottomRight( InputDecoration borderRadiusTopLeftAndBottomRight(
BuildContext context, String hintText) => BuildContext context, String hintText) =>

View File

@@ -2,10 +2,10 @@ import 'dart:developer';
import 'package:fl_chart/fl_chart.dart'; import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/bloc/devices_manager_bloc.dart'; import '../../bloc/devices_manager_bloc.dart';
import 'package:sfm_app/feature/devices/device_model.dart'; import '../../feature/devices/device_model.dart';
import 'package:sfm_app/product/extention/context_extention.dart'; import '../extension/context_extension.dart';
import 'package:sfm_app/product/services/language_services.dart'; import '../services/language_services.dart';
import '../constant/app/app_constants.dart'; import '../constant/app/app_constants.dart';
@@ -54,18 +54,18 @@ class _SharedPieChartState extends State<SharedPieChart> {
aspectRatio: 1, aspectRatio: 1,
child: PieChart( child: PieChart(
PieChartData( PieChartData(
pieTouchData: PieTouchData( // pieTouchData: PieTouchData(
touchCallback: (FlTouchEvent event, pieTouchResponse) { // touchCallback: (FlTouchEvent event, pieTouchResponse) {
if (!event.isInterestedForInteractions || // if (!event.isInterestedForInteractions ||
pieTouchResponse == null || // pieTouchResponse == null ||
pieTouchResponse.touchedSection == null) { // pieTouchResponse.touchedSection == null) {
return; // return;
} // }
int newTouchedIndex = // int newTouchedIndex =
pieTouchResponse.touchedSection!.touchedSectionIndex; // pieTouchResponse.touchedSection!.touchedSectionIndex;
updateDevicesOnTapPieChart(newTouchedIndex); // updateDevicesOnTapPieChart(newTouchedIndex);
}, // },
), // ),
sections: [ sections: [
PieChartSectionData( PieChartSectionData(
color: Colors.grey, color: Colors.grey,
@@ -96,7 +96,7 @@ class _SharedPieChartState extends State<SharedPieChart> {
titleStyle: titleStyle, titleStyle: titleStyle,
), ),
PieChartSectionData( PieChartSectionData(
color: Colors.black, // Có thể thêm màu cho trạng thái lỗi color: Colors.black,
value: errorCount.toDouble(), value: errorCount.toDouble(),
title: errorCount.toString(), title: errorCount.toString(),
radius: context.dynamicWidth(0.2), radius: context.dynamicWidth(0.2),

View File

@@ -1,5 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:sfm_app/product/extention/context_extention.dart'; import 'package:sfm_app/product/extension/context_extension.dart';
import 'package:top_snackbar_flutter/custom_snack_bar.dart'; import 'package:top_snackbar_flutter/custom_snack_bar.dart';
import 'package:top_snackbar_flutter/top_snack_bar.dart'; import 'package:top_snackbar_flutter/top_snack_bar.dart';