mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
Merge branch 'dev' of https://github.com/SyncrowIOT/web into feat/refactoring
This commit is contained in:
@ -40,7 +40,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
: 1,
|
||||
mainAxisExtent: 140,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
mainAxisSpacing: 16,
|
||||
),
|
||||
children: [
|
||||
ToggleWidget(
|
||||
@ -81,6 +81,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.remove,
|
||||
@ -108,6 +109,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
),
|
||||
Text('m', style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor)),
|
||||
IconButton(
|
||||
padding: const EdgeInsets.all(0),
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.add,
|
||||
@ -127,7 +129,7 @@ class AcDeviceControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
deviceId: device.uuid!,
|
||||
code: 'child_lock',
|
||||
value: state.status.childLock,
|
||||
label: 'Child Lock',
|
||||
label: 'Lock',
|
||||
icon: state.status.childLock ? Assets.acLock : Assets.unlock,
|
||||
onChange: (value) {
|
||||
context.read<AcBloc>().add(
|
||||
|
@ -18,6 +18,8 @@ import 'package:syncrow_web/pages/device_managment/main_door_sensor/view/main_do
|
||||
import 'package:syncrow_web/pages/device_managment/one_g_glass_switch/view/one_gang_glass_batch_control_view.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/view/wall_light_batch_control.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/one_gang_switch/view/wall_light_device_control.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_clamp_batch_control_view.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/smart_power_device_control.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/view/three_gang_glass_switch_batch_control_view.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/three_g_glass_switch/view/three_gang_glass_switch_control_view.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/three_gang_switch/view/living_room_batch_controls.dart';
|
||||
@ -94,6 +96,10 @@ mixin RouteControlsBasedCode {
|
||||
return WaterLeakView(
|
||||
deviceId: device.uuid!,
|
||||
);
|
||||
case 'PC':
|
||||
return SmartPowerDeviceControl(
|
||||
deviceId: device.uuid!,
|
||||
);
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
@ -224,6 +230,13 @@ mixin RouteControlsBasedCode {
|
||||
.map((e) => e.uuid!)
|
||||
.toList(),
|
||||
);
|
||||
case 'PC':
|
||||
return PowerClampBatchControlView(
|
||||
deviceIds: devices
|
||||
.where((e) => (e.productType == 'PC'))
|
||||
.map((e) => e.uuid!)
|
||||
.toList(),
|
||||
);
|
||||
default:
|
||||
return const SizedBox();
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_search_filters.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_control_dialog.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
@ -146,7 +145,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
||||
.add(SelectDevice(selectedDevice));
|
||||
},
|
||||
withCheckBox: true,
|
||||
size: context.screenSize,
|
||||
size: MediaQuery.of(context).size,
|
||||
uuidIndex: 2,
|
||||
headers: const [
|
||||
'Device Name',
|
||||
|
@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/common/text_field/custom_text_field.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart';
|
||||
import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class DeviceSearchFilters extends StatefulWidget {
|
||||
const DeviceSearchFilters({super.key});
|
||||
@ -12,7 +13,8 @@ class DeviceSearchFilters extends StatefulWidget {
|
||||
State<DeviceSearchFilters> createState() => _DeviceSearchFiltersState();
|
||||
}
|
||||
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperResponsiveLayout {
|
||||
class _DeviceSearchFiltersState extends State<DeviceSearchFilters>
|
||||
with HelperResponsiveLayout {
|
||||
final TextEditingController communityController = TextEditingController();
|
||||
final TextEditingController unitNameController = TextEditingController();
|
||||
final TextEditingController productNameController = TextEditingController();
|
||||
@ -34,7 +36,8 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Space Name", unitNameController, 200),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchField("Device Name / Product Name", productNameController, 300),
|
||||
_buildSearchField(
|
||||
"Device Name / Product Name", productNameController, 300),
|
||||
const SizedBox(width: 20),
|
||||
_buildSearchResetButtons(),
|
||||
],
|
||||
@ -59,19 +62,22 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSearchField(String title, TextEditingController controller, double width) {
|
||||
return StatefulTextField(
|
||||
title: title,
|
||||
width: width,
|
||||
elevation: 2,
|
||||
controller: controller,
|
||||
onSubmitted: () {
|
||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
||||
productName: productNameController.text,
|
||||
unitName: unitNameController.text,
|
||||
community: communityController.text,
|
||||
searchField: true));
|
||||
},
|
||||
Widget _buildSearchField(
|
||||
String title, TextEditingController controller, double width) {
|
||||
return Container(
|
||||
child: StatefulTextField(
|
||||
title: title,
|
||||
width: width,
|
||||
elevation: 2,
|
||||
controller: controller,
|
||||
onSubmitted: () {
|
||||
context.read<DeviceManagementBloc>().add(SearchDevices(
|
||||
productName: productNameController.text,
|
||||
unitName: unitNameController.text,
|
||||
community: communityController.text,
|
||||
searchField: true));
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/device_managment/gateway/bloc/gate_way_bloc.da
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
|
||||
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
@ -25,25 +26,61 @@ class GateWayControlsView extends StatelessWidget with HelperResponsiveLayout {
|
||||
if (state is GatewayLoadingState) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is UpdateGatewayState) {
|
||||
return GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: isLarge || isExtraLarge
|
||||
? 3
|
||||
: isMedium
|
||||
? 2
|
||||
: 1,
|
||||
mainAxisExtent: 140,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
itemCount: state.list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final device = state.list[index];
|
||||
return _DeviceItem(device: device);
|
||||
},
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Bluetooth Devices:",
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
"No devices found",
|
||||
style: context.textTheme.bodySmall!.copyWith(
|
||||
color: ColorsManager.blackColor,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
Text(
|
||||
"ZigBee Devices:",
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
GridView.builder(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: isLarge || isExtraLarge
|
||||
? 3
|
||||
: isMedium
|
||||
? 2
|
||||
: 1,
|
||||
mainAxisExtent: 140,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
itemCount: state.list.length,
|
||||
itemBuilder: (context, index) {
|
||||
final device = state.list[index];
|
||||
return _DeviceItem(device: device);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return const Center(child: Text('Error fetching status'));
|
||||
|
@ -0,0 +1,792 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_state.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/device_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_batch_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_chart.dart';
|
||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||
|
||||
class SmartPowerBloc extends Bloc<SmartPowerEvent, SmartPowerState> {
|
||||
SmartPowerBloc({required this.deviceId}) : super(SmartPowerInitial()) {
|
||||
on<SmartPowerFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||
on<SmartPowerArrowPressedEvent>(_onArrowPressed);
|
||||
on<SmartPowerFetchBatchEvent>(_onFetchBatchStatus);
|
||||
on<SmartPowerPageChangedEvent>(_onPageChanged);
|
||||
on<PowerBatchControlEvent>(_onBatchControl);
|
||||
on<FilterRecordsByDateEvent>(_filterRecordsByDate);
|
||||
on<SelectDateEvent>(checkDayMonthYearSelected);
|
||||
on<SmartPowerFactoryReset>(_onFactoryReset);
|
||||
}
|
||||
|
||||
late PowerClampModel deviceStatus;
|
||||
late PowerClampBatchModel deviceBatchStatus;
|
||||
final String deviceId;
|
||||
Timer? _timer;
|
||||
List<Map<String, dynamic>> phaseData = [];
|
||||
int currentPage = 0;
|
||||
|
||||
List<EventDevice> record = [
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:15:43'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:15:35'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:15:29'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:15:25'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:15:21'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:15:17'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:15:07'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:14:47'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:14:40'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:14:23'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2024-10-23 11:14:13'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:15:43'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:15:35'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:15:29'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:15:25'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:15:21'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:15:17'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:15:07'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:14:47'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:14:40'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:14:23'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-10-23 11:14:13'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:15:43'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:15:35'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:15:29'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:15:25'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:15:21'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:15:17'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:15:07'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:14:47'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:14:40'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:14:23'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-23 11:14:13'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-11 11:15:43'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-11 11:15:35'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-12 11:15:29'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-13 11:15:25'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-14 11:15:21'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-15 11:15:17'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-16 11:15:07'),
|
||||
value: '2286'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-17 11:14:47'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-18 11:14:40'),
|
||||
value: '2284'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-19 11:14:23'),
|
||||
value: '2285'),
|
||||
EventDevice(
|
||||
code: 'VoltageA',
|
||||
eventTime: DateTime.parse('2023-02-20 11:14:13'),
|
||||
value: '2284'),
|
||||
];
|
||||
|
||||
FutureOr<void> _onFetchDeviceStatus(
|
||||
SmartPowerFetchDeviceEvent event, Emitter<SmartPowerState> emit) async {
|
||||
emit(SmartPowerLoading());
|
||||
try {
|
||||
var status =
|
||||
await DevicesManagementApi().getPowerClampInfo(event.deviceId);
|
||||
deviceStatus = PowerClampModel.fromJson(status);
|
||||
|
||||
phaseData = [
|
||||
{
|
||||
'name': 'Phase A',
|
||||
'voltage': '${deviceStatus.status.phaseA.dataPoints[0].value / 10} V',
|
||||
'current': '${deviceStatus.status.phaseA.dataPoints[1].value / 10} A',
|
||||
'activePower': '${deviceStatus.status.phaseA.dataPoints[2].value} W',
|
||||
'powerFactor': '${deviceStatus.status.phaseA.dataPoints[3].value}',
|
||||
},
|
||||
{
|
||||
'name': 'Phase B',
|
||||
'voltage': '${deviceStatus.status.phaseB.dataPoints[0].value / 10} V',
|
||||
'current': '${deviceStatus.status.phaseB.dataPoints[1].value / 10} A',
|
||||
'activePower': '${deviceStatus.status.phaseB.dataPoints[2].value} W',
|
||||
'powerFactor': '${deviceStatus.status.phaseB.dataPoints[3].value}',
|
||||
},
|
||||
{
|
||||
'name': 'Phase C',
|
||||
'voltage': '${deviceStatus.status.phaseC.dataPoints[0].value / 10} V',
|
||||
'current': '${deviceStatus.status.phaseC.dataPoints[1].value / 10} A',
|
||||
'activePower': '${deviceStatus.status.phaseC.dataPoints[2].value} W',
|
||||
'powerFactor': '${deviceStatus.status.phaseC.dataPoints[3].value}',
|
||||
},
|
||||
];
|
||||
emit(GetDeviceStatus());
|
||||
} catch (e) {
|
||||
emit(SmartPowerError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
FutureOr<void> _onArrowPressed(
|
||||
SmartPowerArrowPressedEvent event, Emitter<SmartPowerState> emit) {
|
||||
currentPage = (currentPage + event.direction + 4) % 4;
|
||||
emit(SmartPowerStatusLoaded(deviceStatus, currentPage));
|
||||
emit(GetDeviceStatus());
|
||||
}
|
||||
|
||||
FutureOr<void> _onPageChanged(
|
||||
SmartPowerPageChangedEvent event, Emitter<SmartPowerState> emit) {
|
||||
currentPage = event.page;
|
||||
emit(SmartPowerStatusLoaded(deviceStatus, currentPage));
|
||||
emit(GetDeviceStatus());
|
||||
}
|
||||
|
||||
Future<void> _onFactoryReset(
|
||||
SmartPowerFactoryReset event, Emitter<SmartPowerState> emit) async {
|
||||
emit(SmartPowerLoading());
|
||||
try {
|
||||
final response = await DevicesManagementApi().factoryReset(
|
||||
event.factoryReset,
|
||||
event.deviceId,
|
||||
);
|
||||
if (response) {
|
||||
emit(SmartPowerInitial());
|
||||
} else {
|
||||
emit(SmartPowerError('Factory reset failed'));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(SmartPowerError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onBatchControl(
|
||||
PowerBatchControlEvent event, Emitter<SmartPowerState> emit) async {
|
||||
final oldValue = deviceStatus.status;
|
||||
|
||||
_updateLocalValue(event.code, event.value);
|
||||
// emit(WaterLeakBatchStatusLoadedState(deviceStatus!));
|
||||
|
||||
await _runDebounce(
|
||||
deviceId: event.deviceIds,
|
||||
code: event.code,
|
||||
value: event.value,
|
||||
oldValue: oldValue,
|
||||
emit: emit,
|
||||
isBatch: true,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onFetchBatchStatus(
|
||||
SmartPowerFetchBatchEvent event, Emitter<SmartPowerState> emit) async {
|
||||
emit(SmartPowerLoading());
|
||||
try {
|
||||
final response =
|
||||
await DevicesManagementApi().getPowerStatus(event.devicesIds);
|
||||
PowerClampBatchModel deviceStatus =
|
||||
PowerClampBatchModel.fromJson(response);
|
||||
|
||||
emit(SmartPowerLoadBatchControll(deviceStatus));
|
||||
} catch (e) {
|
||||
debugPrint('=========error====$e');
|
||||
emit(SmartPowerError(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _runDebounce({
|
||||
required dynamic deviceId,
|
||||
required String code,
|
||||
required dynamic value,
|
||||
required dynamic oldValue,
|
||||
required Emitter<SmartPowerState> emit,
|
||||
required bool isBatch,
|
||||
}) async {
|
||||
late String id;
|
||||
if (deviceId is List) {
|
||||
id = deviceId.first;
|
||||
} else {
|
||||
id = deviceId;
|
||||
}
|
||||
|
||||
if (_timer != null) {
|
||||
_timer!.cancel();
|
||||
}
|
||||
|
||||
_timer = Timer(const Duration(milliseconds: 500), () async {
|
||||
try {
|
||||
late bool response;
|
||||
if (isBatch) {
|
||||
response = await DevicesManagementApi()
|
||||
.deviceBatchControl(deviceId, code, value);
|
||||
} else {
|
||||
response = await DevicesManagementApi()
|
||||
.deviceControl(deviceId, Status(code: code, value: value));
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
_revertValueAndEmit(id, code, oldValue, emit);
|
||||
}
|
||||
} catch (e) {
|
||||
_revertValueAndEmit(id, code, oldValue, emit);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _updateLocalValue(String code, dynamic value) {
|
||||
if (code == 'watersensor_state') {
|
||||
deviceStatus = deviceStatus.copyWith(statusPower: value);
|
||||
} else if (code == 'battery_percentage') {
|
||||
deviceStatus = deviceStatus.copyWith(statusPower: value);
|
||||
}
|
||||
}
|
||||
|
||||
void _revertValueAndEmit(String deviceId, String code, dynamic oldValue,
|
||||
Emitter<SmartPowerState> emit) {
|
||||
_updateLocalValue(code, oldValue);
|
||||
emit(SmartPowerLoadBatchControll(deviceBatchStatus));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_timer?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
List<EventDevice> filteredRecords = [];
|
||||
|
||||
int currentIndex = 0;
|
||||
final List<String> views = ['Day', 'Month', 'Year'];
|
||||
|
||||
Widget dateSwitcher() {
|
||||
void switchView(int direction) {
|
||||
currentIndex = (currentIndex + direction + views.length) % views.length;
|
||||
}
|
||||
|
||||
return StatefulBuilder(
|
||||
builder: (BuildContext context, StateSetter setState) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_left),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
switchView(-1);
|
||||
});
|
||||
},
|
||||
),
|
||||
Text(
|
||||
views[currentIndex],
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_right),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
switchView(1);
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<DateTime?> selectMonthAndYear(BuildContext context) async {
|
||||
int selectedYear = DateTime.now().year;
|
||||
int selectedMonth = DateTime.now().month;
|
||||
|
||||
FixedExtentScrollController yearController =
|
||||
FixedExtentScrollController(initialItem: selectedYear - 1905);
|
||||
FixedExtentScrollController monthController =
|
||||
FixedExtentScrollController(initialItem: selectedMonth - 1);
|
||||
|
||||
return await showDialog<DateTime>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
height: 350,
|
||||
width: 350,
|
||||
child: Column(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'Select Month and Year',
|
||||
style:
|
||||
TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Expanded(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Spacer(),
|
||||
Expanded(
|
||||
child: ListWheelScrollView.useDelegate(
|
||||
controller: yearController,
|
||||
overAndUnderCenterOpacity: 0.2,
|
||||
itemExtent: 50,
|
||||
onSelectedItemChanged: (index) {
|
||||
selectedYear = 1905 + index;
|
||||
},
|
||||
childDelegate: ListWheelChildBuilderDelegate(
|
||||
builder: (context, index) {
|
||||
return Center(
|
||||
child: Text(
|
||||
(1905 + index).toString(),
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: 200,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: ListWheelScrollView.useDelegate(
|
||||
controller: monthController,
|
||||
overAndUnderCenterOpacity: 0.2,
|
||||
itemExtent: 50,
|
||||
onSelectedItemChanged: (index) {
|
||||
selectedMonth = index + 1;
|
||||
},
|
||||
childDelegate: ListWheelChildBuilderDelegate(
|
||||
builder: (context, index) {
|
||||
return Center(
|
||||
child: Text(
|
||||
DateFormat.MMMM()
|
||||
.format(DateTime(0, index + 1)),
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0, vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
child: const Text('Cancel'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () {
|
||||
final selectedDateTime =
|
||||
DateTime(selectedYear, selectedMonth);
|
||||
Navigator.of(context).pop(selectedDateTime);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<DateTime?> selectYear(BuildContext context) async {
|
||||
int selectedYear = DateTime.now().year;
|
||||
FixedExtentScrollController yearController =
|
||||
FixedExtentScrollController(initialItem: selectedYear - 1905);
|
||||
|
||||
return await showDialog<DateTime>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
height: 350,
|
||||
width: 350,
|
||||
child: Column(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
'Select Year',
|
||||
style:
|
||||
TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Expanded(
|
||||
child: ListWheelScrollView.useDelegate(
|
||||
controller: yearController,
|
||||
overAndUnderCenterOpacity: 0.2,
|
||||
itemExtent: 50,
|
||||
onSelectedItemChanged: (index) {
|
||||
selectedYear = 1905 + index;
|
||||
},
|
||||
childDelegate: ListWheelChildBuilderDelegate(
|
||||
builder: (context, index) {
|
||||
return Center(
|
||||
child: Text(
|
||||
(1905 + index).toString(),
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: 200,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0, vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
child: const Text('Cancel'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () {
|
||||
final selectedDateTime = DateTime(selectedYear);
|
||||
Navigator.of(context).pop(selectedDateTime);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<DateTime?> dayMonthYearPicker({
|
||||
required BuildContext context,
|
||||
}) async {
|
||||
DateTime selectedDate = DateTime.now();
|
||||
|
||||
return await showDialog<DateTime>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 350,
|
||||
width: 350,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: CupertinoDatePicker(
|
||||
mode: CupertinoDatePickerMode.date,
|
||||
initialDateTime: DateTime.now(),
|
||||
minimumYear: 1900,
|
||||
maximumYear: DateTime.now().year,
|
||||
onDateTimeChanged: (DateTime newDateTime) {
|
||||
selectedDate = newDateTime;
|
||||
},
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16.0, vertical: 8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
child: const Text('Cancel'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('OK'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(selectedDate);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
DateTime? dateTime = DateTime.now();
|
||||
|
||||
String formattedDate = DateFormat('yyyy/MM/dd').format(DateTime.now());
|
||||
|
||||
void checkDayMonthYearSelected(
|
||||
SelectDateEvent event, Emitter<SmartPowerState> emit) async {
|
||||
Future<DateTime?> Function(BuildContext context)? dateSelector;
|
||||
String dateFormat;
|
||||
switch (currentIndex) {
|
||||
case 0:
|
||||
dateSelector = (context) {
|
||||
return dayMonthYearPicker(context: context);
|
||||
};
|
||||
dateFormat = 'yyyy/MM/dd';
|
||||
break;
|
||||
case 1:
|
||||
dateSelector = (context) {
|
||||
return selectMonthAndYear(context);
|
||||
};
|
||||
dateFormat = 'yyyy-MM';
|
||||
break;
|
||||
case 2:
|
||||
dateSelector = (context) {
|
||||
return selectYear(context);
|
||||
};
|
||||
dateFormat = 'yyyy';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
emit(FakeState());
|
||||
});
|
||||
// Use the selected picker
|
||||
await dateSelector(event.context).then((newDate) {
|
||||
if (newDate.toString() == 'null') {
|
||||
emit(GetDeviceStatus());
|
||||
} else {
|
||||
dateTime = newDate;
|
||||
add(FilterRecordsByDateEvent(
|
||||
selectedDate: newDate!,
|
||||
viewType: views[currentIndex],
|
||||
));
|
||||
}
|
||||
// formattedDate = newDate.toString();
|
||||
});
|
||||
emit(FilterRecordsState(filteredRecords: energyDataList));
|
||||
}
|
||||
|
||||
List<EnergyData> energyDataList = [];
|
||||
void _filterRecordsByDate(
|
||||
FilterRecordsByDateEvent event, Emitter<SmartPowerState> emit) {
|
||||
// emit(SmartPowerLoading());
|
||||
|
||||
if (event.viewType == 'Year') {
|
||||
formattedDate = event.selectedDate.year.toString();
|
||||
filteredRecords = record
|
||||
.where((record) => record.eventTime!.year == event.selectedDate.year)
|
||||
.toList();
|
||||
} else if (event.viewType == 'Month') {
|
||||
formattedDate =
|
||||
"${event.selectedDate.year.toString()}-${getMonthShortName(event.selectedDate.month)}";
|
||||
|
||||
filteredRecords = record
|
||||
.where((record) =>
|
||||
record.eventTime!.year == event.selectedDate.year &&
|
||||
record.eventTime!.month == event.selectedDate.month)
|
||||
.toList();
|
||||
} else if (event.viewType == 'Day') {
|
||||
formattedDate =
|
||||
"${event.selectedDate.year.toString()}-${getMonthShortName(event.selectedDate.month)}-${event.selectedDate.day}";
|
||||
|
||||
filteredRecords = record
|
||||
.where((record) =>
|
||||
record.eventTime!.year == event.selectedDate.year &&
|
||||
record.eventTime!.month == event.selectedDate.month &&
|
||||
record.eventTime!.day == event.selectedDate.day)
|
||||
.toList();
|
||||
}
|
||||
|
||||
selectDateRange();
|
||||
energyDataList = filteredRecords.map((eventDevice) {
|
||||
return EnergyData(
|
||||
event.viewType == 'Year'
|
||||
? getMonthShortName(
|
||||
int.tryParse(DateFormat('MM').format(eventDevice.eventTime!))!)
|
||||
: event.viewType == 'Month'
|
||||
? DateFormat('yyyy/MM/dd').format(eventDevice.eventTime!)
|
||||
: DateFormat('HH:mm:ss').format(eventDevice.eventTime!),
|
||||
double.parse(eventDevice.value!),
|
||||
);
|
||||
}).toList();
|
||||
emit(FilterRecordsState(filteredRecords: energyDataList));
|
||||
}
|
||||
|
||||
String getMonthShortName(int month) {
|
||||
final date = DateTime(0, month);
|
||||
return DateFormat.MMM().format(date);
|
||||
}
|
||||
|
||||
String endChartDate = '';
|
||||
|
||||
void selectDateRange() async {
|
||||
DateTime startDate = dateTime!;
|
||||
DateTime endDate = DateTime(startDate.year, startDate.month + 1, 1)
|
||||
.subtract(Duration(days: 1));
|
||||
String formattedEndDate = DateFormat('dd/MM/yyyy').format(endDate);
|
||||
endChartDate = ' - $formattedEndDate';
|
||||
}
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
|
||||
class SmartPowerEvent extends Equatable {
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class SmartPowerFetchDeviceEvent extends SmartPowerEvent {
|
||||
final String deviceId;
|
||||
|
||||
SmartPowerFetchDeviceEvent(this.deviceId);
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceId];
|
||||
}
|
||||
|
||||
class SmartPowerControl extends SmartPowerEvent {
|
||||
final String deviceId;
|
||||
final String code;
|
||||
final bool value;
|
||||
|
||||
SmartPowerControl(
|
||||
{required this.deviceId, required this.code, required this.value});
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceId, code, value];
|
||||
}
|
||||
|
||||
class SmartPowerFetchBatchEvent extends SmartPowerEvent {
|
||||
final List<String> devicesIds;
|
||||
|
||||
SmartPowerFetchBatchEvent(this.devicesIds);
|
||||
|
||||
@override
|
||||
List<Object> get props => [devicesIds];
|
||||
}
|
||||
|
||||
class SmartPowerBatchControl extends SmartPowerEvent {
|
||||
final List<String> devicesIds;
|
||||
final String code;
|
||||
final bool value;
|
||||
|
||||
SmartPowerBatchControl(
|
||||
{required this.devicesIds, required this.code, required this.value});
|
||||
|
||||
@override
|
||||
List<Object> get props => [devicesIds, code, value];
|
||||
}
|
||||
|
||||
class SmartPowerFactoryReset extends SmartPowerEvent {
|
||||
final String deviceId;
|
||||
final FactoryResetModel factoryReset;
|
||||
|
||||
SmartPowerFactoryReset({required this.deviceId, required this.factoryReset});
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceId, factoryReset];
|
||||
}
|
||||
|
||||
class PageChangedEvent extends SmartPowerEvent {
|
||||
final int newPage;
|
||||
PageChangedEvent(this.newPage);
|
||||
}
|
||||
|
||||
class PageArrowPressedEvent extends SmartPowerEvent {
|
||||
final int direction;
|
||||
PageArrowPressedEvent(this.direction);
|
||||
}
|
||||
|
||||
class SmartPowerArrowPressedEvent extends SmartPowerEvent {
|
||||
final int direction;
|
||||
SmartPowerArrowPressedEvent(this.direction);
|
||||
}
|
||||
|
||||
class SmartPowerPageChangedEvent extends SmartPowerEvent {
|
||||
final int page;
|
||||
SmartPowerPageChangedEvent(this.page);
|
||||
}
|
||||
|
||||
class SelectDateEvent extends SmartPowerEvent {
|
||||
BuildContext context;
|
||||
SelectDateEvent({required this.context});
|
||||
}
|
||||
|
||||
class FilterRecordsByDateEvent extends SmartPowerEvent {
|
||||
final DateTime selectedDate;
|
||||
final String viewType; // 'Day', 'Month', 'Year'
|
||||
|
||||
FilterRecordsByDateEvent(
|
||||
{required this.selectedDate, required this.viewType});
|
||||
}
|
||||
|
||||
class FetchPowerClampBatchStatusEvent extends SmartPowerEvent {
|
||||
final List<String> deviceIds;
|
||||
|
||||
FetchPowerClampBatchStatusEvent(this.deviceIds);
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceIds];
|
||||
}class PowerBatchControlEvent extends SmartPowerEvent {
|
||||
final List<String> deviceIds;
|
||||
final String code;
|
||||
final dynamic value;
|
||||
|
||||
PowerBatchControlEvent({
|
||||
required this.deviceIds,
|
||||
required this.code,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [deviceIds, code, value];
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_batch_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_chart.dart';
|
||||
|
||||
class SmartPowerState extends Equatable {
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class SmartPowerInitial extends SmartPowerState {}
|
||||
|
||||
class SmartPowerLoading extends SmartPowerState {}
|
||||
|
||||
class GetDeviceStatus extends SmartPowerState {}
|
||||
//GetDeviceStatus
|
||||
|
||||
class SmartPowerLoadBatchControll extends SmartPowerState {
|
||||
final PowerClampBatchModel status;
|
||||
|
||||
SmartPowerLoadBatchControll(this.status);
|
||||
|
||||
@override
|
||||
List<Object> get props => [status];
|
||||
}
|
||||
|
||||
class DateSelectedState extends SmartPowerState {}
|
||||
|
||||
class FakeState extends SmartPowerState {}
|
||||
|
||||
class SmartPowerStatusLoaded extends SmartPowerState {
|
||||
final PowerClampModel deviceStatus;
|
||||
final int currentPage;
|
||||
SmartPowerStatusLoaded(this.deviceStatus, this.currentPage);
|
||||
}
|
||||
|
||||
class SmartPowerError extends SmartPowerState {
|
||||
final String message;
|
||||
|
||||
SmartPowerError(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
class SmartPowerControlError extends SmartPowerState {
|
||||
final String message;
|
||||
|
||||
SmartPowerControlError(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
class SmartPowerBatchControlError extends SmartPowerState {
|
||||
final String message;
|
||||
|
||||
SmartPowerBatchControlError(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
class SmartPowerBatchStatusLoaded extends SmartPowerState {
|
||||
final List<String> status;
|
||||
|
||||
SmartPowerBatchStatusLoaded(this.status);
|
||||
|
||||
@override
|
||||
List<Object> get props => [status];
|
||||
}
|
||||
|
||||
class FilterRecordsState extends SmartPowerState {
|
||||
final List<EnergyData> filteredRecords;
|
||||
|
||||
FilterRecordsState({required this.filteredRecords});
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
|
||||
class EventDevice {
|
||||
final String? code;
|
||||
final DateTime? eventTime;
|
||||
final String? value;
|
||||
|
||||
EventDevice({
|
||||
this.code,
|
||||
this.eventTime,
|
||||
this.value,
|
||||
});
|
||||
|
||||
EventDevice.fromJson(Map<String, dynamic> json)
|
||||
: code = json['code'] as String?,
|
||||
eventTime = json['eventTime'] ,
|
||||
value = json['value'] as String?;
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'code': code,
|
||||
'eventTime': eventTime,
|
||||
'value': value,
|
||||
};
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||
|
||||
abstract class PowerClampModel1 {
|
||||
String get productUuid;
|
||||
String get productType;
|
||||
}
|
||||
|
||||
class PowerClampBatchModel extends PowerClampModel1 {
|
||||
@override
|
||||
final String productUuid;
|
||||
@override
|
||||
final String productType;
|
||||
final List<Status> status;
|
||||
|
||||
PowerClampBatchModel({
|
||||
required this.productUuid,
|
||||
required this.productType,
|
||||
required this.status,
|
||||
});
|
||||
|
||||
factory PowerClampBatchModel.fromJson(Map<String, dynamic> json) {
|
||||
String productUuid = json['productUuid'] ?? '';
|
||||
String productType = json['productType'] ?? '';
|
||||
|
||||
List<Status> statusList = [];
|
||||
if (json['status'] != null && json['status'] is List) {
|
||||
statusList =
|
||||
(json['status'] as List).map((e) => Status.fromJson(e)).toList();
|
||||
}
|
||||
|
||||
return PowerClampBatchModel(
|
||||
productUuid: productUuid,
|
||||
productType: productType,
|
||||
status: statusList,
|
||||
);
|
||||
}
|
||||
|
||||
PowerClampBatchModel copyWith({
|
||||
String? productUuid,
|
||||
String? productType,
|
||||
List<Status>? status,
|
||||
}) {
|
||||
return PowerClampBatchModel(
|
||||
productUuid: productUuid ?? this.productUuid,
|
||||
productType: productType ?? this.productType,
|
||||
status: status ?? this.status,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
// PowerClampModel class to represent the response
|
||||
class PowerClampModel {
|
||||
String productUuid;
|
||||
String productType;
|
||||
PowerStatus status;
|
||||
|
||||
PowerClampModel({
|
||||
required this.productUuid,
|
||||
required this.productType,
|
||||
required this.status,
|
||||
});
|
||||
|
||||
factory PowerClampModel.fromJson(Map<String, dynamic> json) {
|
||||
return PowerClampModel(
|
||||
productUuid: json['productUuid'],
|
||||
productType: json['productType'],
|
||||
status: PowerStatus.fromJson(json['status']),
|
||||
);
|
||||
}
|
||||
|
||||
PowerClampModel copyWith({
|
||||
String? productUuid,
|
||||
String? productType,
|
||||
PowerStatus? statusPower,
|
||||
}) {
|
||||
return PowerClampModel(
|
||||
productUuid: productUuid ?? this.productUuid,
|
||||
productType: productType ?? this.productType,
|
||||
status: statusPower ?? this.status,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PowerStatus {
|
||||
Phase phaseA;
|
||||
Phase phaseB;
|
||||
Phase phaseC;
|
||||
Phase general;
|
||||
|
||||
PowerStatus({
|
||||
required this.phaseA,
|
||||
required this.phaseB,
|
||||
required this.phaseC,
|
||||
required this.general,
|
||||
});
|
||||
|
||||
factory PowerStatus.fromJson(Map<String, dynamic> json) {
|
||||
return PowerStatus(
|
||||
phaseA: Phase.fromJson(json['phaseA']),
|
||||
phaseB: Phase.fromJson(json['phaseB']),
|
||||
phaseC: Phase.fromJson(json['phaseC']),
|
||||
general: Phase.fromJson(json['general']
|
||||
// List<DataPoint>.from(
|
||||
// json['general'].map((x) => DataPoint.fromJson(x))),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class Phase {
|
||||
List<DataPoint> dataPoints;
|
||||
|
||||
Phase({required this.dataPoints});
|
||||
|
||||
factory Phase.fromJson(List<dynamic> json) {
|
||||
return Phase(
|
||||
dataPoints: json.map((x) => DataPoint.fromJson(x)).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DataPoint {
|
||||
dynamic code;
|
||||
dynamic customName;
|
||||
dynamic dpId;
|
||||
dynamic time;
|
||||
dynamic type;
|
||||
dynamic value;
|
||||
|
||||
DataPoint({
|
||||
required this.code,
|
||||
required this.customName,
|
||||
required this.dpId,
|
||||
required this.time,
|
||||
required this.type,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
factory DataPoint.fromJson(Map<String, dynamic> json) {
|
||||
return DataPoint(
|
||||
code: json['code'],
|
||||
customName: json['customName'],
|
||||
dpId: json['dpId'],
|
||||
time: json['time'],
|
||||
type: json['type'],
|
||||
value: json['value'],
|
||||
);
|
||||
}
|
||||
}
|
124
lib/pages/device_managment/power_clamp/view/phase_widget.dart
Normal file
124
lib/pages/device_managment/power_clamp/view/phase_widget.dart
Normal file
@ -0,0 +1,124 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_info_card.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class PhaseWidget extends StatefulWidget {
|
||||
final List<Map<String, dynamic>> phaseData;
|
||||
|
||||
PhaseWidget({
|
||||
required this.phaseData,
|
||||
});
|
||||
@override
|
||||
_PhaseWidgetState createState() => _PhaseWidgetState();
|
||||
}
|
||||
|
||||
class _PhaseWidgetState extends State<PhaseWidget> {
|
||||
int _selectedPhaseIndex = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(height: 10),
|
||||
Row(
|
||||
children: List.generate(widget.phaseData.length, (index) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_selectedPhaseIndex = index;
|
||||
});
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||
child: Text(
|
||||
widget.phaseData[index]['name'],
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: _selectedPhaseIndex == index
|
||||
? Colors.black
|
||||
: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
_selectedPhaseIndex == 0
|
||||
? phase(
|
||||
totalActive: widget.phaseData[0]['activePower'] ?? '0',
|
||||
totalCurrent: widget.phaseData[0]['current'] ?? '0',
|
||||
totalFactor: widget.phaseData[0]['powerFactor'] ?? '0',
|
||||
totalVoltage: widget.phaseData[0]['voltage'] ?? '0',
|
||||
)
|
||||
: _selectedPhaseIndex == 1
|
||||
? phase(
|
||||
totalActive: widget.phaseData[1]['activePower'] ?? '0',
|
||||
totalCurrent: widget.phaseData[1]['current'] ?? '0',
|
||||
totalFactor: widget.phaseData[1]['powerFactor'] ?? '0',
|
||||
totalVoltage: widget.phaseData[1]['voltage'] ?? '0',
|
||||
)
|
||||
: phase(
|
||||
totalActive: widget.phaseData[2]['activePower'] ?? '0',
|
||||
totalCurrent: widget.phaseData[2]['current'] ?? '0',
|
||||
totalFactor: widget.phaseData[2]['powerFactor'] ?? '0',
|
||||
totalVoltage: widget.phaseData[2]['voltage'] ?? '0',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class phase extends StatelessWidget {
|
||||
const phase({
|
||||
super.key,
|
||||
required this.totalVoltage,
|
||||
required this.totalCurrent,
|
||||
required this.totalActive,
|
||||
required this.totalFactor,
|
||||
});
|
||||
|
||||
final String totalVoltage;
|
||||
final String totalCurrent;
|
||||
final String totalActive;
|
||||
final String totalFactor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
PowerClampInfoCard(
|
||||
iconPath: Assets.voltageIcon,
|
||||
title: 'Voltage',
|
||||
value: totalVoltage,
|
||||
unit: '',
|
||||
),
|
||||
PowerClampInfoCard(
|
||||
iconPath: Assets.voltMeterIcon,
|
||||
title: 'Current',
|
||||
value: totalCurrent,
|
||||
unit: '',
|
||||
),
|
||||
PowerClampInfoCard(
|
||||
iconPath: Assets.powerActiveIcon,
|
||||
title: 'Active Power',
|
||||
value: totalActive,
|
||||
unit: '',
|
||||
),
|
||||
PowerClampInfoCard(
|
||||
iconPath: Assets.speedoMeter,
|
||||
title: 'Power Factor',
|
||||
value: totalFactor,
|
||||
unit: '',
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
281
lib/pages/device_managment/power_clamp/view/power_chart.dart
Normal file
281
lib/pages/device_managment/power_clamp/view/power_chart.dart
Normal file
@ -0,0 +1,281 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class EnergyConsumptionPage extends StatefulWidget {
|
||||
final List<dynamic> chartData;
|
||||
final double totalConsumption;
|
||||
final String date;
|
||||
final String formattedDate;
|
||||
final Widget widget;
|
||||
final Function()? onTap;
|
||||
|
||||
EnergyConsumptionPage({
|
||||
required this.chartData,
|
||||
required this.totalConsumption,
|
||||
required this.date,
|
||||
required this.widget,
|
||||
required this.onTap,
|
||||
required this.formattedDate,
|
||||
});
|
||||
|
||||
@override
|
||||
_EnergyConsumptionPageState createState() => _EnergyConsumptionPageState();
|
||||
}
|
||||
|
||||
class _EnergyConsumptionPageState extends State<EnergyConsumptionPage> {
|
||||
late List<dynamic> _chartData;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_chartData = widget.chartData;
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: Column(
|
||||
children: [
|
||||
const Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'Total Consumption',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'8623.20 kWh',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const Row(
|
||||
children: [
|
||||
Text(
|
||||
'Energy consumption',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.formattedDate,
|
||||
style: const TextStyle(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 8,
|
||||
),
|
||||
),
|
||||
const Text(
|
||||
'1000.00 kWh',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.grayColor,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 8,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height * 0.11,
|
||||
child: LineChart(
|
||||
LineChartData(
|
||||
lineTouchData: LineTouchData(
|
||||
handleBuiltInTouches: true,
|
||||
touchSpotThreshold: 2,
|
||||
getTouchLineEnd: (barData, spotIndex) {
|
||||
return 10.0;
|
||||
},
|
||||
touchTooltipData: LineTouchTooltipData(
|
||||
getTooltipColor: (touchTooltipItem) => Colors.white,
|
||||
tooltipRoundedRadius: 10.0,
|
||||
tooltipPadding: const EdgeInsets.all(8.0),
|
||||
tooltipBorder: const BorderSide(
|
||||
color: ColorsManager.grayColor, width: 1),
|
||||
getTooltipItems: (List<LineBarSpot> touchedSpots) {
|
||||
return touchedSpots.map((spot) {
|
||||
return LineTooltipItem(
|
||||
'${spot.x},\n ${spot.y.toStringAsFixed(2)} kWh',
|
||||
const TextStyle(
|
||||
color: Colors.blue,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
),
|
||||
);
|
||||
}).toList();
|
||||
},
|
||||
)),
|
||||
titlesData: FlTitlesData(
|
||||
bottomTitles: const AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: false,
|
||||
),
|
||||
),
|
||||
leftTitles: const AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: false,
|
||||
),
|
||||
),
|
||||
rightTitles: const AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: false,
|
||||
),
|
||||
),
|
||||
topTitles: AxisTitles(
|
||||
sideTitles: SideTitles(
|
||||
showTitles: false,
|
||||
reservedSize: 70,
|
||||
getTitlesWidget: (value, meta) {
|
||||
int index = value.toInt();
|
||||
if (index >= 0 && index < _chartData.length) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: RotatedBox(
|
||||
quarterTurns: -1,
|
||||
child: Text(_chartData[index].time,
|
||||
style: TextStyle(fontSize: 10)),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
gridData: FlGridData(
|
||||
show: true,
|
||||
drawVerticalLine: true,
|
||||
horizontalInterval: 1,
|
||||
verticalInterval: 1,
|
||||
getDrawingVerticalLine: (value) {
|
||||
return FlLine(
|
||||
color: Colors.grey.withOpacity(0.2),
|
||||
dashArray: [8, 8],
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
getDrawingHorizontalLine: (value) {
|
||||
return FlLine(
|
||||
color: Colors.grey.withOpacity(0.2),
|
||||
dashArray: [5, 5],
|
||||
strokeWidth: 1,
|
||||
);
|
||||
},
|
||||
drawHorizontalLine: false,
|
||||
),
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
preventCurveOvershootingThreshold: 0.1,
|
||||
curveSmoothness: 0.5,
|
||||
preventCurveOverShooting: true,
|
||||
aboveBarData: BarAreaData(),
|
||||
spots: _chartData
|
||||
.asMap()
|
||||
.entries
|
||||
.map((entry) => FlSpot(entry.key.toDouble(),
|
||||
entry.value.consumption))
|
||||
.toList(),
|
||||
isCurved: true,
|
||||
color: ColorsManager.primaryColor.withOpacity(0.6),
|
||||
show: true,
|
||||
shadow: const Shadow(color: Colors.black12),
|
||||
belowBarData: BarAreaData(
|
||||
show: true,
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
ColorsManager.primaryColor.withOpacity(0.5),
|
||||
Colors.blue.withOpacity(0.1),
|
||||
],
|
||||
begin: Alignment.center,
|
||||
end: Alignment.bottomCenter,
|
||||
),
|
||||
),
|
||||
dotData: const FlDotData(
|
||||
show: false,
|
||||
),
|
||||
isStrokeCapRound: true,
|
||||
barWidth: 2,
|
||||
),
|
||||
],
|
||||
borderData: FlBorderData(
|
||||
show: false,
|
||||
border: Border.all(
|
||||
color: Color(0xff023DFE).withOpacity(0.7),
|
||||
width: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.graysColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Container(child: widget.widget),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 20,
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(5.0),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.graysColor,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: widget.onTap,
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Text(widget.date),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EnergyData {
|
||||
EnergyData(this.time, this.consumption);
|
||||
final String time;
|
||||
final double consumption;
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_state.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/models/power_clamp_batch_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/factory_reset.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/batch_control/firmware_update.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
class PowerClampBatchControlView extends StatelessWidget
|
||||
with HelperResponsiveLayout {
|
||||
final List<String> deviceIds;
|
||||
|
||||
const PowerClampBatchControlView({Key? key, required this.deviceIds})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => SmartPowerBloc(deviceId: deviceIds.first)
|
||||
..add(SmartPowerFetchBatchEvent(deviceIds)),
|
||||
child: BlocBuilder<SmartPowerBloc, SmartPowerState>(
|
||||
builder: (context, state) {
|
||||
if (state is SmartPowerLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is SmartPowerLoadBatchControll) {
|
||||
return _buildStatusControls(context, state.status);
|
||||
} else if (state is SmartPowerError) {
|
||||
return Center(child: Text('Error: ${state.message}'));
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusControls(
|
||||
BuildContext context, PowerClampBatchModel status) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 170,
|
||||
// height: 140,
|
||||
child: FirmwareUpdateWidget(deviceId: deviceIds.first, version: 2)),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
SizedBox(
|
||||
width: 170,
|
||||
height: 140,
|
||||
child: FactoryResetWidget(
|
||||
callFactoryReset: () {
|
||||
context.read<SmartPowerBloc>().add(SmartPowerFactoryReset(
|
||||
deviceId: deviceIds.first,
|
||||
factoryReset: FactoryResetModel(devicesUuid: deviceIds)));
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class PowerClampInfoCard extends StatelessWidget {
|
||||
final String iconPath;
|
||||
final String title;
|
||||
final String value;
|
||||
final String unit;
|
||||
|
||||
const PowerClampInfoCard({
|
||||
Key? key,
|
||||
required this.iconPath,
|
||||
required this.title,
|
||||
required this.value,
|
||||
required this.unit,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Expanded(
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(horizontal: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
height: 55,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
SvgPicture.asset(
|
||||
iconPath,
|
||||
fit: BoxFit.fill,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 18,
|
||||
),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
unit,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_event.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/bloc/smart_power_state.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/phase_widget.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_chart.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/power_clamp/view/power_info_card.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||
|
||||
//Smart Power Clamp
|
||||
class SmartPowerDeviceControl extends StatelessWidget
|
||||
with HelperResponsiveLayout {
|
||||
final String deviceId;
|
||||
|
||||
const SmartPowerDeviceControl({super.key, required this.deviceId});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (context) => SmartPowerBloc(deviceId: deviceId)
|
||||
..add(SmartPowerFetchDeviceEvent(deviceId)),
|
||||
child: BlocBuilder<SmartPowerBloc, SmartPowerState>(
|
||||
builder: (context, state) {
|
||||
final _blocProvider = BlocProvider.of<SmartPowerBloc>(context);
|
||||
|
||||
if (state is SmartPowerLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (state is FakeState) {
|
||||
return _buildStatusControls(
|
||||
currentPage: _blocProvider.currentPage,
|
||||
context: context,
|
||||
blocProvider: _blocProvider,
|
||||
);
|
||||
} else if (state is GetDeviceStatus) {
|
||||
return _buildStatusControls(
|
||||
currentPage: _blocProvider.currentPage,
|
||||
context: context,
|
||||
blocProvider: _blocProvider,
|
||||
);
|
||||
} else if (state is FilterRecordsState) {
|
||||
return _buildStatusControls(
|
||||
currentPage: _blocProvider.currentPage,
|
||||
context: context,
|
||||
blocProvider: _blocProvider,
|
||||
);
|
||||
}
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
// }
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStatusControls({
|
||||
required BuildContext context,
|
||||
required SmartPowerBloc blocProvider,
|
||||
required int currentPage,
|
||||
}) {
|
||||
PageController _pageController = PageController(initialPage: currentPage);
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 50),
|
||||
child: DeviceControlsContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
const Row(
|
||||
children: [
|
||||
Text(
|
||||
'Live',
|
||||
style: TextStyle(
|
||||
fontSize: 32,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: ColorsManager.textPrimaryColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
PowerClampInfoCard(
|
||||
iconPath: Assets.powerActiveIcon,
|
||||
title: 'Active',
|
||||
value: blocProvider
|
||||
.deviceStatus.status.general.dataPoints[2].value
|
||||
.toString(),
|
||||
unit: '',
|
||||
),
|
||||
PowerClampInfoCard(
|
||||
iconPath: Assets.voltMeterIcon,
|
||||
title: 'Current',
|
||||
value: blocProvider
|
||||
.deviceStatus.status.general.dataPoints[1].value
|
||||
.toString(),
|
||||
unit: ' A',
|
||||
),
|
||||
PowerClampInfoCard(
|
||||
iconPath: Assets.frequencyIcon,
|
||||
title: 'Frequency',
|
||||
value: blocProvider
|
||||
.deviceStatus.status.general.dataPoints[4].value
|
||||
.toString(),
|
||||
unit: ' Hz',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
PhaseWidget(
|
||||
phaseData: blocProvider.phaseData,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 10,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
height: 300,
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.graysColor,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
height: 50,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_left),
|
||||
onPressed: () {
|
||||
blocProvider.add(SmartPowerArrowPressedEvent(-1));
|
||||
_pageController.previousPage(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
},
|
||||
),
|
||||
Text(
|
||||
currentPage == 0
|
||||
? 'Total'
|
||||
: currentPage == 1
|
||||
? 'Phase A'
|
||||
: currentPage == 2
|
||||
? 'Phase B'
|
||||
: 'Phase C',
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.arrow_right),
|
||||
onPressed: () {
|
||||
blocProvider.add(SmartPowerArrowPressedEvent(1));
|
||||
_pageController.nextPage(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 5,
|
||||
),
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: PageView(
|
||||
controller: _pageController,
|
||||
onPageChanged: (int page) {
|
||||
blocProvider.add(SmartPowerPageChangedEvent(page));
|
||||
},
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
EnergyConsumptionPage(
|
||||
formattedDate:
|
||||
'${blocProvider.dateTime!.day}/${blocProvider.dateTime!.month}/${blocProvider.dateTime!.year} ${blocProvider.endChartDate}',
|
||||
onTap: () {
|
||||
blocProvider.add(SelectDateEvent(context: context));
|
||||
blocProvider.add(FilterRecordsByDateEvent(
|
||||
selectedDate: blocProvider.dateTime!,
|
||||
viewType: blocProvider
|
||||
.views[blocProvider.currentIndex]));
|
||||
},
|
||||
widget: blocProvider.dateSwitcher(),
|
||||
chartData: blocProvider.energyDataList.isNotEmpty
|
||||
? blocProvider.energyDataList
|
||||
: [
|
||||
EnergyData('12:00 AM', 4.0),
|
||||
EnergyData('01:00 AM', 3.5),
|
||||
EnergyData('02:00 AM', 3.8),
|
||||
EnergyData('03:00 AM', 3.2),
|
||||
EnergyData('04:00 AM', 4.0),
|
||||
EnergyData('05:00 AM', 3.4),
|
||||
EnergyData('06:00 AM', 3.2),
|
||||
EnergyData('07:00 AM', 3.5),
|
||||
EnergyData('08:00 AM', 3.8),
|
||||
EnergyData('09:00 AM', 3.6),
|
||||
EnergyData('10:00 AM', 3.9),
|
||||
EnergyData('11:00 AM', 4.0),
|
||||
],
|
||||
totalConsumption: 10000,
|
||||
date: blocProvider.formattedDate,
|
||||
),
|
||||
EnergyConsumptionPage(
|
||||
formattedDate:
|
||||
'${blocProvider.dateTime!.day}/${blocProvider.dateTime!.month}/${blocProvider.dateTime!.year} ${blocProvider.endChartDate}',
|
||||
onTap: () {
|
||||
blocProvider.add(SelectDateEvent(context: context));
|
||||
},
|
||||
widget: blocProvider.dateSwitcher(),
|
||||
chartData: blocProvider.energyDataList.isNotEmpty
|
||||
? blocProvider.energyDataList
|
||||
: [
|
||||
EnergyData('12:00 AM', 4.0),
|
||||
EnergyData('01:00 AM', 3.5),
|
||||
EnergyData('02:00 AM', 3.8),
|
||||
EnergyData('03:00 AM', 3.2),
|
||||
EnergyData('04:00 AM', 4.0),
|
||||
EnergyData('05:00 AM', 3.4),
|
||||
EnergyData('06:00 AM', 3.2),
|
||||
EnergyData('07:00 AM', 3.5),
|
||||
EnergyData('08:00 AM', 3.8),
|
||||
EnergyData('09:00 AM', 3.6),
|
||||
EnergyData('10:00 AM', 3.9),
|
||||
EnergyData('11:00 AM', 4.0),
|
||||
],
|
||||
totalConsumption: 10000,
|
||||
date: blocProvider.formattedDate,
|
||||
),
|
||||
EnergyConsumptionPage(
|
||||
formattedDate:
|
||||
'${blocProvider.dateTime!.day}/${blocProvider.dateTime!.month}/${blocProvider.dateTime!.year} ${blocProvider.endChartDate}',
|
||||
onTap: () {
|
||||
blocProvider.add(SelectDateEvent(context: context));
|
||||
},
|
||||
widget: blocProvider.dateSwitcher(),
|
||||
chartData: blocProvider.energyDataList.isNotEmpty
|
||||
? blocProvider.energyDataList
|
||||
: [
|
||||
EnergyData('12:00 AM', 4.0),
|
||||
EnergyData('01:00 AM', 6.5),
|
||||
EnergyData('02:00 AM', 3.8),
|
||||
EnergyData('03:00 AM', 3.2),
|
||||
EnergyData('04:00 AM', 6.0),
|
||||
EnergyData('05:00 AM', 3.4),
|
||||
EnergyData('06:00 AM', 5.2),
|
||||
EnergyData('07:00 AM', 3.5),
|
||||
EnergyData('08:00 AM', 3.8),
|
||||
EnergyData('09:00 AM', 5.6),
|
||||
EnergyData('10:00 AM', 6.9),
|
||||
EnergyData('11:00 AM', 6.0),
|
||||
],
|
||||
totalConsumption: 10000,
|
||||
date: blocProvider.formattedDate,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -52,6 +52,7 @@ class _FactoryResetWidgetState extends State<FactoryResetWidget> {
|
||||
child: DefaultButton(
|
||||
height: 20,
|
||||
elevation: 0,
|
||||
padding: 0,
|
||||
onPressed: _toggleConfirmation,
|
||||
backgroundColor: ColorsManager.greyColor,
|
||||
child: Text(
|
||||
@ -69,14 +70,16 @@ class _FactoryResetWidgetState extends State<FactoryResetWidget> {
|
||||
child: DefaultButton(
|
||||
height: 20,
|
||||
elevation: 0,
|
||||
padding: 0,
|
||||
onPressed: widget.callFactoryReset,
|
||||
backgroundColor: ColorsManager.red,
|
||||
child: Text(
|
||||
'Reset',
|
||||
style: context.textTheme.bodyMedium!.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12),
|
||||
color: ColorsManager.whiteColors,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -7,7 +7,8 @@ import 'package:syncrow_web/pages/device_managment/all_devices/helper/route_cont
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DeviceBatchControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
class DeviceBatchControlDialog extends StatelessWidget
|
||||
with RouteControlsBasedCode {
|
||||
final List<AllDevicesModel> devices;
|
||||
|
||||
const DeviceBatchControlDialog({super.key, required this.devices});
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/helper/route_controls_based_code.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/device_batch_control_dialog.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/format_date_time.dart';
|
||||
|
||||
@ -31,7 +32,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
children: [
|
||||
const SizedBox(),
|
||||
Text(
|
||||
device.productName ?? 'Device Control',
|
||||
getBatchDialogName(device),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 22,
|
||||
@ -64,7 +65,7 @@ class DeviceControlDialog extends StatelessWidget with RouteControlsBasedCode {
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildDeviceInfoSection(),
|
||||
const SizedBox(height: 20),
|
||||
//const SizedBox(height: 20),
|
||||
//// BUILD DEVICE CONTROLS
|
||||
///
|
||||
//// ROUTE TO SPECIFIC CONTROL VIEW BASED ON DEVICE CATEGORY
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DeviceControlsContainer extends StatelessWidget {
|
||||
const DeviceControlsContainer({required this.child, this.padding, super.key});
|
||||
@ -8,21 +7,21 @@ class DeviceControlsContainer extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
return Card(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: ColorsManager.greyColor.withOpacity(0.2),
|
||||
|
||||
// boxShadow: <BoxShadow>[
|
||||
// BoxShadow(
|
||||
// color: ColorsManager.blackColor.withOpacity(0.05),
|
||||
// blurRadius: 6.0,
|
||||
// offset: const Offset(0, 5),
|
||||
// spreadRadius: 0)
|
||||
// ],
|
||||
),
|
||||
padding: EdgeInsets.all(padding ?? 12),
|
||||
child: child,
|
||||
elevation: 3,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(vertical: padding ?? 10, horizontal: padding ?? 16), //EdgeInsets.all(padding ?? 12),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user