Update Pie Chart In DeviceManagerScreen

This commit is contained in:
anhtunz
2024-12-24 11:16:00 +07:00
parent e047fe1e27
commit 77afc09d19
6 changed files with 297 additions and 29 deletions

View File

@@ -1,6 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'package:sfm_app/product/constant/app/app_constants.dart';
import 'device_model.dart';
import '../../product/base/bloc/base_bloc.dart';
import '../../product/services/api_services.dart';
@@ -18,18 +20,54 @@ class DevicesManagerBloc extends BlocBase {
StreamSink<List<Device>> get sinkAllDevices => allDevices.sink;
Stream<List<Device>> get streamAllDevices => allDevices.stream;
final deviceByState = StreamController<Map<String, List<Device>>>.broadcast();
StreamSink<Map<String, List<Device>>> get sinkDeviceByState =>
deviceByState.sink;
Stream<Map<String, List<Device>>> get streamDeviceByState =>
deviceByState.stream;
@override
void dispose() {}
void getDevice() async {
String body = await apiServices.getOwnerDevices();
if (body != "") {
Map<String, List<Device>> deviceByState = {
ApplicationConstants.OFFLINE_STATE: [],
ApplicationConstants.NORMAL_STATE: [],
ApplicationConstants.WARNING_STATE: [],
ApplicationConstants.INPROGRESS_STATE: [],
ApplicationConstants.ERROR_STATE: [],
};
if (body.isNotEmpty) {
final data = jsonDecode(body);
List<dynamic> items = data['items'];
List<Device> originalDevices = Device.fromJsonDynamicList(items);
List<Device> devices =
DeviceUtils.instance.sortDeviceByState(originalDevices);
for (var device in devices) {
String stateKey;
switch (device.state) {
case -1:
stateKey = ApplicationConstants.OFFLINE_STATE;
break;
case 0:
stateKey = ApplicationConstants.NORMAL_STATE;
break;
case 1:
stateKey = ApplicationConstants.WARNING_STATE;
break;
case 2:
stateKey = ApplicationConstants.INPROGRESS_STATE;
break;
default:
stateKey = ApplicationConstants.ERROR_STATE;
break;
}
deviceByState[stateKey]!.add(device);
}
sinkAllDevices.add(devices);
sinkDeviceByState.add(deviceByState);
}
}
}

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:sfm_app/product/shared/shared_pie_chart.dart';
import 'add_new_device_widget.dart';
import 'delete_device_widget.dart';
import 'device_model.dart';
@@ -50,6 +51,7 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
// backgroundColor: Colors.grey.withOpacity(0.6),
body: SafeArea(
child: StreamBuilder<List<Device>>(
stream: devicesManagerBloc.streamAllDevices,
@@ -61,7 +63,7 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
} else {
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
// mainAxisSize: MainAxisSize.min,
children: [
StreamBuilder<String>(
stream: devicesManagerBloc.streamUserRole,
@@ -81,35 +83,51 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_action))),
.paginated_data_table_column_action),
),
),
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_deviceName))),
.paginated_data_table_column_deviceName),
),
),
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_deviceStatus))),
.paginated_data_table_column_deviceStatus),
),
),
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_deviceBaterry))),
.paginated_data_table_column_deviceBaterry),
),
),
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_deviceSignal))),
.paginated_data_table_column_deviceSignal),
),
),
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_deviceTemperature))),
.paginated_data_table_column_deviceTemperature),
),
),
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_deviceHump))),
.paginated_data_table_column_deviceHump),
),
),
DataColumn(
label: Center(
child: Text(appLocalization(context)
.paginated_data_table_column_devicePower))),
.paginated_data_table_column_devicePower),
),
),
],
onPageChanged: (int pageIndex) {
// log('Chuyen page: $pageIndex');
@@ -143,7 +161,30 @@ class _DevicesManagerScreenState extends State<DevicesManagerScreen> {
),
);
},
)
),
SizedBox(height: context.lowValue),
Text(
appLocalization(context).overview_message,
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: context.lowValue),
StreamBuilder<Map<String, List<Device>>>(
stream: devicesManagerBloc.streamDeviceByState,
builder: (context, devicesByStateSnapshot) {
if (devicesByStateSnapshot.data == null) {
devicesManagerBloc.getDevice();
return const Center(
child: CircularProgressIndicator());
} else {
return SharedPieChart(
deviceByState: devicesByStateSnapshot.data ?? {});
}
},
),
SizedBox(height: context.mediumValue),
],
),
);

View File

@@ -3,6 +3,11 @@
class ApplicationConstants {
static const APP_NAME = "Smatec SFM";
static const DOMAIN = "sfm.smatec.com.vn";
static const OFFLINE_STATE = "offline";
static const NORMAL_STATE = "normal";
static const WARNING_STATE = "warning";
static const INPROGRESS_STATE = "inprogress";
static const ERROR_STATE = "error";
static const MAP_KEY = "AIzaSyDI8b-PUgKUgj5rHdtgEHCwWjUXYJrqYhE";
static const LOGIN_PATH = "/login";
static const LOGOUT_PATH = "/logout";

View File

@@ -21,7 +21,7 @@
"let_PCCC_handle_message": "Hãy để Đội PCCC xử lý!",
"overview_message": "Tổng quan",
"total_nof_devices_message": "Tổng số",
"active_devices_message": "Đang hoạt động",
"active_devices_message": "Bình thường",
"inactive_devices_message": "Đang tắt",
"warning_devices_message": "Cảnh báo",
"unused_devices_message": "Không sử dụng",

View File

@@ -0,0 +1,180 @@
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:sfm_app/feature/devices/device_model.dart';
import 'package:sfm_app/product/extention/context_extention.dart';
import 'package:sfm_app/product/services/language_services.dart';
import '../constant/app/app_constants.dart';
class SharedPieChart extends StatelessWidget {
const SharedPieChart({
super.key,
required this.deviceByState,
});
final Map<String, List<Device>> deviceByState;
@override
Widget build(BuildContext context) {
TextStyle titleStyle = const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
);
int offlineCount =
deviceByState[ApplicationConstants.OFFLINE_STATE]?.length ?? 0;
int normalCount =
deviceByState[ApplicationConstants.NORMAL_STATE]?.length ?? 0;
int warningCount =
deviceByState[ApplicationConstants.WARNING_STATE]?.length ?? 0;
int inProgressCount =
deviceByState[ApplicationConstants.INPROGRESS_STATE]?.length ?? 0;
int errorCount =
deviceByState[ApplicationConstants.ERROR_STATE]?.length ?? 0;
return Padding(
padding: context.paddingLowHorizontal,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
width: context.dynamicWidth(0.5),
height: context.dynamicHeight(0.3),
padding: const EdgeInsets.all(10),
child: PieChart(
PieChartData(
sections: [
PieChartSectionData(
color: Colors.grey,
value: offlineCount.toDouble(),
title: offlineCount.toString(),
radius: context.dynamicWidth(0.3),
titleStyle: titleStyle,
),
PieChartSectionData(
color: Colors.green,
value: normalCount.toDouble(),
title: normalCount.toString(),
radius: context.dynamicWidth(0.3),
titleStyle: titleStyle,
),
PieChartSectionData(
color: Colors.red,
value: warningCount.toDouble(),
title: warningCount.toString(),
radius: context.dynamicWidth(0.3),
titleStyle: titleStyle,
),
PieChartSectionData(
color: Colors.yellow,
value: inProgressCount.toDouble(),
title: inProgressCount.toString(),
radius: context.dynamicWidth(0.3),
titleStyle: titleStyle,
),
PieChartSectionData(
color: Colors.black, // Có thể thêm màu cho trạng thái lỗi
value: errorCount.toDouble(),
title: errorCount.toString(),
radius: context.dynamicWidth(0.3),
titleStyle: titleStyle,
),
],
centerSpaceRadius: 0,
sectionsSpace: 1,
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Indicator(
color: Colors.grey,
text: appLocalization(context).inactive_devices_message,
isSquare: true,
),
SizedBox(
height: context.lowValue,
),
Indicator(
color: Colors.green,
text: appLocalization(context).active_devices_message,
isSquare: true,
),
SizedBox(
height: context.lowValue,
),
Indicator(
color: Colors.red,
text: appLocalization(context).warning_devices_message,
isSquare: true,
),
SizedBox(
height: context.lowValue,
),
Indicator(
color: Colors.yellow,
text: appLocalization(context).in_progress_message,
isSquare: true,
),
SizedBox(
height: context.lowValue,
),
Indicator(
color: Colors.black,
text: appLocalization(context).error_message_uppercase,
isSquare: true,
),
// const SizedBox(
// height: 18,
// ),
],
),
],
),
);
}
}
class Indicator extends StatelessWidget {
const Indicator({
super.key,
required this.color,
required this.text,
required this.isSquare,
this.size = 16,
this.textColor,
});
final Color color;
final String text;
final bool isSquare;
final double size;
final Color? textColor;
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: isSquare ? BoxShape.rectangle : BoxShape.circle,
color: color,
),
),
SizedBox(
width: context.lowValue,
),
Text(
text,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: textColor,
),
)
],
);
}
}

View File

@@ -148,8 +148,12 @@ class DeviceUtils {
return Colors.red;
} else if (state == 0) {
return Colors.green;
} else {
} else if (state == 2) {
return Colors.orange;
} else if (state == -1) {
return Colors.grey;
} else {
return Colors.black87;
}
}