diff --git a/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart b/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart index 05476977..1ccf849b 100644 --- a/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart +++ b/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/helper/fake_report_data.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/state.dart'; @@ -14,6 +15,9 @@ class CeilingSensorBloc extends Bloc { CeilingSensorBloc({required this.deviceId}) : super(CeilingInitialState()) { on(_fetchCeilingSensorStatus); on(_changeValue); + on(_getDeviceReports); + on(_showDescription); + on(_backToGridView); } void _fetchCeilingSensorStatus( @@ -49,7 +53,8 @@ class CeilingSensorBloc extends Bloc { // } catch (_) {} // } - void _changeValue(CeilingChangeValueEvent event, Emitter emit) async { + void _changeValue( + CeilingChangeValueEvent event, Emitter emit) async { emit(CeilingLoadingNewSate(ceilingSensorModel: deviceStatus)); if (event.code == 'sensitivity') { deviceStatus.sensitivity = event.value; @@ -59,7 +64,8 @@ class CeilingSensorBloc extends Bloc { deviceStatus.maxDistance = event.value; } emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); - await _runDeBouncer(deviceId: deviceId, code: event.code, value: event.value); + await _runDeBouncer( + deviceId: deviceId, code: event.code, value: event.value); } _runDeBouncer({ @@ -72,8 +78,8 @@ class CeilingSensorBloc extends Bloc { } _timer = Timer(const Duration(seconds: 1), () async { try { - final response = - await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value)); + final response = await DevicesManagementApi() + .deviceControl(deviceId, Status(code: code, value: value)); if (!response) { add(CeilingInitialEvent()); @@ -84,4 +90,30 @@ class CeilingSensorBloc extends Bloc { } }); } + + FutureOr _getDeviceReports(GetCeilingDeviceReportsEvent event, + Emitter emit) async { + emit(CeilingReportsLoadingState()); + + try { + //await DevicesManagementApi.getDeviceReports(deviceId, event.code) + // .then((value) { + final fakeReport = FakeDeviceReport.generateFakeReport(); + emit(CeilingReportsState(deviceReport: fakeReport)); + // }); + } catch (e) { + emit(CeilingReportsFailedState(error: e.toString())); + return; + } + } + + void _showDescription( + ShowCeilingDescriptionEvent event, Emitter emit) { + emit(ShowCeilingDescriptionState(description: event.description)); + } + + void _backToGridView( + BackToCeilingGridViewEvent event, Emitter emit) { + emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); + } } diff --git a/lib/pages/device_managment/ceiling_sensor/bloc/event.dart b/lib/pages/device_managment/ceiling_sensor/bloc/event.dart index 97840b31..0d509f41 100644 --- a/lib/pages/device_managment/ceiling_sensor/bloc/event.dart +++ b/lib/pages/device_managment/ceiling_sensor/bloc/event.dart @@ -17,3 +17,25 @@ class CeilingChangeValueEvent extends CeilingSensorEvent { @override List get props => [value, code]; } + +class GetCeilingDeviceReportsEvent extends CeilingSensorEvent { + final String code; + final String deviceUuid; + + const GetCeilingDeviceReportsEvent( + {required this.code, required this.deviceUuid}); + + @override + List get props => [code, deviceUuid]; +} + +class ShowCeilingDescriptionEvent extends CeilingSensorEvent { + final String description; + + const ShowCeilingDescriptionEvent({required this.description}); + + @override + List get props => [description]; +} + +class BackToCeilingGridViewEvent extends CeilingSensorEvent {} diff --git a/lib/pages/device_managment/ceiling_sensor/bloc/state.dart b/lib/pages/device_managment/ceiling_sensor/bloc/state.dart index 9cc77f59..0bd7e4ed 100644 --- a/lib/pages/device_managment/ceiling_sensor/bloc/state.dart +++ b/lib/pages/device_managment/ceiling_sensor/bloc/state.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart'; class CeilingSensorState extends Equatable { @@ -36,3 +37,32 @@ class CeilingFailedState extends CeilingSensorState { @override List get props => [error]; } + +class CeilingReportsState extends CeilingSensorState { + final DeviceReport deviceReport; + + const CeilingReportsState({required this.deviceReport}); + + @override + List get props => [deviceReport]; +} + +class CeilingReportsLoadingState extends CeilingSensorState {} + +class CeilingReportsFailedState extends CeilingSensorState { + final String error; + + const CeilingReportsFailedState({required this.error}); + + @override + List get props => [error]; +} + +class ShowCeilingDescriptionState extends CeilingSensorState { + final String description; + + const ShowCeilingDescriptionState({required this.description}); + + @override + List get props => [description]; +} diff --git a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart index 0d7271b9..a086f372 100644 --- a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart +++ b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart @@ -4,10 +4,13 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/bloc.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/ceiling_sensor/bloc/state.dart'; +import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_display_data.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_static_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_status.dart'; import 'package:syncrow_web/pages/device_managment/shared/sensors_widgets/presence_update_data.dart'; +import 'package:syncrow_web/pages/device_managment/shared/table/description_view.dart'; +import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; @@ -29,99 +32,133 @@ class CeilingSensorControls extends StatelessWidget if (state is CeilingLoadingInitialState) { return const Center(child: CircularProgressIndicator()); } else if (state is CeilingUpdateState) { - return GridView( - padding: const EdgeInsets.symmetric(horizontal: 50), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge - ? 3 - : isMedium - ? 2 - : 1, - mainAxisExtent: 133, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - ), - children: [ - PresenceState( - value: state.ceilingSensorModel.presenceState, - ), - PresenceDisplayValue( - value: state.ceilingSensorModel.sportsPara.toString(), - postfix: '', - description: 'Sports para', - ), - PresenceDisplayValue( - value: state.ceilingSensorModel.presenceRange.toString(), - postfix: 'm', - description: 'Detection Range', - ), - PresenceUpdateData( - value: state.ceilingSensorModel.sensitivity.toDouble(), - title: 'Sensitivity:', - minValue: 1, - maxValue: 5, - steps: 1, - action: (int value) { - context.read().add( - CeilingChangeValueEvent( - code: 'sensitivity', - value: value, - ), - ); - }, - ), - PresenceUpdateData( - value: state.ceilingSensorModel.maxDistance.toDouble(), - title: 'Maximum Distance:', - minValue: 0, - maxValue: 500, - steps: 50, - description: 'm', - action: (int value) => context.read().add( - CeilingChangeValueEvent( - code: 'moving_max_dis', - value: value, - ), - ), - ), - PresenceUpdateData( - value: - (state.ceilingSensorModel.noBodyTime.toDouble() / 3600) - .roundToDouble(), - title: 'Nobody Time:', - minValue: 0, - maxValue: 300000, - steps: 5000, - description: 'hr', - action: (int value) => context - .read() - .add(CeilingChangeValueEvent( - code: 'none_body_time', - value: value, - ))), - GestureDetector( - onTap: () {}, - child: const PresenceStaticWidget( - icon: Assets.illuminanceRecordIcon, - description: 'Presence Record', - ), - ), - GestureDetector( - onTap: () {}, - child: const PresenceStaticWidget( - icon: Assets.helpDescriptionIcon, - description: 'Help Description', - ), - ), - ], + return _buildGridView( + context, state.ceilingSensorModel, isLarge, isMedium); + } else if (state is CeilingReportsState) { + return ReportsTable( + report: state.deviceReport, + onRowTap: (index) { + final entry = state.deviceReport.data![index]; + context.read().add( + ShowCeilingDescriptionEvent( + description: entry['description']), + ); + }, + onClose: () { + context.read().add(BackToCeilingGridViewEvent()); + }, ); - } else { - return const Center(child: Text('Error fetching status')); + } else if (state is ShowCeilingDescriptionState) { + return DescriptionView( + description: state.description, + onClose: () { + context.read().add(BackToCeilingGridViewEvent()); + }, + ); + } else if (state is CeilingReportsFailedState) { + final model = context.read().deviceStatus; + return _buildGridView(context, model, isLarge, isMedium); } + return const Center(child: Text('Error fetching status')); }, ), ); } + + Widget _buildGridView(BuildContext context, CeilingSensorModel model, + bool isLarge, bool isMedium) { + return GridView( + padding: const EdgeInsets.symmetric(horizontal: 50), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: isLarge + ? 3 + : isMedium + ? 2 + : 1, + mainAxisExtent: 133, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + children: [ + PresenceState( + value: model.presenceState, + ), + PresenceDisplayValue( + value: model.sportsPara.toString(), + postfix: '', + description: 'Sports para', + ), + PresenceDisplayValue( + value: model.presenceRange.toString(), + postfix: 'm', + description: 'Detection Range', + ), + PresenceUpdateData( + value: model.sensitivity.toDouble(), + title: 'Sensitivity:', + minValue: 1, + maxValue: 5, + steps: 1, + action: (int value) { + context.read().add( + CeilingChangeValueEvent( + code: 'sensitivity', + value: value, + ), + ); + }, + ), + PresenceUpdateData( + value: model.maxDistance.toDouble(), + title: 'Maximum Distance:', + minValue: 0, + maxValue: 500, + steps: 50, + description: 'm', + action: (int value) => context.read().add( + CeilingChangeValueEvent( + code: 'moving_max_dis', + value: value, + ), + ), + ), + PresenceUpdateData( + value: + (model.noBodyTime.toDouble() / 3600).roundToDouble(), + title: 'Nobody Time:', + minValue: 0, + maxValue: 300000, + steps: 5000, + description: 'hr', + action: (int value) => context + .read() + .add(CeilingChangeValueEvent( + code: 'none_body_time', + value: value, + ))), + GestureDetector( + onTap: () { + context.read().add(GetCeilingDeviceReportsEvent( + code: 'illuminance_record', deviceUuid: device.uuid!)); + }, + child: const PresenceStaticWidget( + icon: Assets.illuminanceRecordIcon, + description: 'Presence Record', + ), + ), + GestureDetector( + onTap: () { + context.read().add(GetCeilingDeviceReportsEvent( + code: 'presence_record', deviceUuid: device.uuid!)); + }, + child: const PresenceStaticWidget( + icon: Assets.presenceRecordIcon, + description: 'Presence Record', + ), + ), + ], + ); + } } diff --git a/lib/pages/device_managment/shared/table/description_view.dart b/lib/pages/device_managment/shared/table/description_view.dart new file mode 100644 index 00000000..8c68e841 --- /dev/null +++ b/lib/pages/device_managment/shared/table/description_view.dart @@ -0,0 +1,48 @@ +import 'package:flutter/material.dart'; + +class DescriptionView extends StatelessWidget { + final String description; + final VoidCallback onClose; + + const DescriptionView({ + super.key, + required this.description, + required this.onClose, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 50), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Help Description', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Colors.grey), + ), + GestureDetector( + onTap: onClose, + child: Text( + 'Close', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Colors.grey), + ), + ), + ], + ), + const SizedBox(height: 10), + Text(description), + ], + ), + ); + } +} diff --git a/lib/pages/device_managment/shared/table/report_table.dart b/lib/pages/device_managment/shared/table/report_table.dart new file mode 100644 index 00000000..d4804397 --- /dev/null +++ b/lib/pages/device_managment/shared/table/report_table.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart'; +import 'package:syncrow_web/pages/device_managment/shared/table/table_cell_widget.dart'; +import 'package:syncrow_web/pages/device_managment/shared/table/table_header.dart'; + +class ReportsTable extends StatelessWidget { + final DeviceReport report; + final Function(int index) onRowTap; + final VoidCallback onClose; + + const ReportsTable({ + super.key, + required this.report, + required this.onRowTap, + required this.onClose, + }); + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + Padding( + padding: const EdgeInsets.all(20.0), + child: Table( + border: TableBorder.all(color: Colors.grey.shade300, width: 1), + columnWidths: const { + 0: FlexColumnWidth(), + 1: FlexColumnWidth(), + 2: FlexColumnWidth(), + }, + children: [ + TableRow( + decoration: BoxDecoration(color: Colors.grey.shade200), + children: const [ + TableHeader(title: 'Date'), + TableHeader(title: 'Time'), + TableHeader(title: 'Status'), + ], + ), + ...report.data!.asMap().entries.map((entry) { + int index = entry.key; + var data = entry.value; + return TableRow( + children: [ + TableCellWidget(value: data['date']), + TableCellWidget(value: data['time']), + TableCellWidget( + value: data['status'], + onTap: () => onRowTap(index), + ), + ], + ); + }).toList(), + ], + ), + ), + Positioned( + top: 0, + right: 0, + child: IconButton( + icon: const Icon( + Icons.close, + color: Colors.red, + size: 18, + ), + onPressed: onClose, + ), + ), + ], + ); + } +} diff --git a/lib/pages/device_managment/shared/table/table_cell_widget.dart b/lib/pages/device_managment/shared/table/table_cell_widget.dart new file mode 100644 index 00000000..171e1462 --- /dev/null +++ b/lib/pages/device_managment/shared/table/table_cell_widget.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class TableCellWidget extends StatelessWidget { + final String value; + final Function()? onTap; + + const TableCellWidget({ + super.key, + required this.value, + this.onTap, + }); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: onTap, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(value), + ), + ); + } +} diff --git a/lib/pages/device_managment/shared/table/table_header.dart b/lib/pages/device_managment/shared/table/table_header.dart new file mode 100644 index 00000000..39bc1c73 --- /dev/null +++ b/lib/pages/device_managment/shared/table/table_header.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; + +class TableHeader extends StatelessWidget { + final String title; + + const TableHeader({ + super.key, + required this.title, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + title, + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ); + } +} diff --git a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart index 727f1d2e..49b4f18b 100644 --- a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart +++ b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; +import 'package:syncrow_web/pages/device_managment/shared/table/description_view.dart'; +import 'package:syncrow_web/pages/device_managment/shared/table/report_table.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/bloc.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/event.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/bloc/state.dart'; @@ -33,9 +34,25 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { return _buildGridView( context, state.wallSensorModel, isLarge, isMedium); } else if (state is DeviceReportsState) { - return _buildReportsTable(context, state.deviceReport); + return ReportsTable( + report: state.deviceReport, + onRowTap: (index) { + final entry = state.deviceReport.data![index]; + context.read().add( + ShowDescriptionEvent(description: entry['description']), + ); + }, + onClose: () { + context.read().add(BackToGridViewEvent()); + }, + ); } else if (state is WallSensorShowDescriptionState) { - return _buildDescriptionView(context, state.description); + return DescriptionView( + description: state.description, + onClose: () { + context.read().add(BackToGridViewEvent()); + }, + ); } else if (state is DeviceReportsFailedState) { final model = context.read().deviceStatus; return _buildGridView(context, model, isLarge, isMedium); @@ -159,119 +176,6 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ); } - Widget _buildReportsTable(BuildContext context, DeviceReport report) { - return Stack( - children: [ - Padding( - padding: const EdgeInsets.all(20.0), - child: Table( - border: TableBorder.all(color: Colors.grey.shade300, width: 1), - columnWidths: const { - 0: FlexColumnWidth(), - 1: FlexColumnWidth(), - 2: FlexColumnWidth(), - }, - children: [ - TableRow( - decoration: BoxDecoration(color: Colors.grey.shade200), - children: [ - _buildTableHeader('Date'), - _buildTableHeader('Time'), - _buildTableHeader('Status'), - ], - ), - ...report.data!.map((entry) { - return TableRow( - children: [ - _buildTableCell(entry['date']), - _buildTableCell(entry['time']), - GestureDetector( - onTap: () { - context.read().add( - ShowDescriptionEvent( - description: entry['description']), - ); - }, - child: _buildTableCell(entry['status']), - ), - ], - ); - }).toList(), - ], - ), - ), - Positioned( - top: 0, - right: 0, - child: IconButton( - icon: const Icon( - Icons.close, - color: Colors.red, - size: 18, - ), - onPressed: () { - context.read().add(BackToGridViewEvent()); - }, - ), - ), - ], - ); - } - - Widget _buildDescriptionView(BuildContext context, String description) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 50), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Help Description', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.grey), - ), - GestureDetector( - onTap: () { - context.read().add(BackToGridViewEvent()); - }, - child: Text( - 'Close', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.grey), - ), - ), - ], - ), - const SizedBox(height: 10), - Text(description), - ], - ), - ); - } - - Widget _buildTableHeader(String title) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - title, - style: const TextStyle(fontWeight: FontWeight.bold), - ), - ); - } - - Widget _buildTableCell(String value) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Text(value), - ); - } - // BlocBuilder( // builder: (context, state) { // if (state is WallSensorLoadingInitialState) {