From d97efe229db4f3b58b957cdf3281bf8ca0db7204 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sun, 22 Sep 2024 17:27:29 +0300 Subject: [PATCH] door sensor --- assets/icons/door_sensor_icon.svg | 23 +++ .../door_sensor_bloc/door_sensor_bloc.dart | 67 ++------ .../devices/model/device_category_model.dart | 8 +- lib/features/devices/model/device_model.dart | 5 +- .../devices/model/device_report_model.dart | 51 ++++++ .../door_notification_settings.dart | 4 +- .../door_sensor/door_records_screen.dart | 152 +++++++++++------- .../door_sensor/door_sensor_screen.dart | 2 +- lib/generated/assets.dart | 1 + lib/services/api/devices_api.dart | 5 +- 10 files changed, 202 insertions(+), 116 deletions(-) create mode 100644 assets/icons/door_sensor_icon.svg create mode 100644 lib/features/devices/model/device_report_model.dart diff --git a/assets/icons/door_sensor_icon.svg b/assets/icons/door_sensor_icon.svg new file mode 100644 index 0000000..5357720 --- /dev/null +++ b/assets/icons/door_sensor_icon.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart index 91f02ce..971682d 100644 --- a/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart +++ b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart @@ -6,19 +6,18 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart'; import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; +import 'package:syncrow_app/features/devices/model/device_report_model.dart'; import 'package:syncrow_app/features/devices/model/door_sensor_model.dart'; -import 'package:syncrow_app/features/devices/model/report_model.dart'; import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/services/api/devices_api.dart'; class DoorSensorBloc extends Bloc { final String DSId; - final String switchCode; - DoorSensorBloc({required this.DSId, required this.switchCode}) - : super(const DoorSensorState()) { + DoorSensorBloc({ + required this.DSId, + }) : super(const DoorSensorState()) { on(_fetchWaterHeaterStatus); on(fetchLogsForLastMonth); - on(_changeFirstSwitch); on(_toggleLowBattery); on(_toggleClosingReminder); on(_toggleDoorAlarm); @@ -29,6 +28,7 @@ class DoorSensorBloc extends Bloc { bool doorAlarm = false; DoorSensorModel deviceStatus = DoorSensorModel(doorContactState: false, batteryPercentage: 0); + void _fetchWaterHeaterStatus( DoorSensorInitial event, Emitter emit) async { emit(DoorSensorLoadingState()); @@ -43,34 +43,13 @@ class DoorSensorBloc extends Bloc { ); emit(UpdateState(doorSensor: deviceStatus)); Future.delayed(const Duration(milliseconds: 500)); - // _listenToChanges(); + _listenToChanges(); } catch (e) { emit(DoorSensorFailedState(errorMessage: e.toString())); return; } } - void _changeFirstSwitch( - DoorSensorSwitch event, Emitter emit) async { - emit(LoadingNewSate(doorSensor: deviceStatus)); - try { - deviceStatus.doorContactState = !event.switchD; - emit(UpdateState(doorSensor: deviceStatus)); - final response = await DevicesAPI.controlDevice( - DeviceControlModel( - deviceId: DSId, - code: 'doorcontact_state', - value: deviceStatus.doorContactState), - DSId); - - if (!response['success']) { - // add(InitialEvent(groupScreen: oneGangGroup)); - } - } catch (_) { - emit(DoorSensorFailedState(errorMessage: _.toString())); - } - } - // Toggle functions for each switch void _toggleLowBattery( ToggleLowBatteryEvent event, Emitter emit) async { @@ -135,31 +114,8 @@ class DoorSensorBloc extends Bloc { } } - final List recordGroups = [ - RecordGroup( - date: DateTime(2024, 8, 31), - records: [ - Record(status: 'Opened', time: '15:10:25', isOpen: false), - Record(status: 'Closed', time: '12:24:45', isOpen: false), - Record(status: 'Opened', time: '12:20:05', isOpen: true), - ], - ), - RecordGroup( - date: DateTime(2024, 8, 30), - records: [ - Record(status: 'Opened', time: '14:15:30', isOpen: true), - Record(status: 'Closed', time: '10:22:45', isOpen: false), - ], - ), - RecordGroup( - date: DateTime(2024, 8, 29), - records: [ - Record(status: 'Opened', time: '13:45:00', isOpen: true), - Record(status: 'Closed', time: '11:30:15', isOpen: false), - Record(status: 'Opened', time: '09:20:10', isOpen: true), - ], - ), - ]; + DeviceReport recordGroups = DeviceReport(startTime: 0, endTime: 0, data: []); + Future fetchLogsForLastMonth( ReportLogsInitial event, Emitter emit) async { @@ -174,11 +130,13 @@ class DoorSensorBloc extends Bloc { int endTime = now.millisecondsSinceEpoch; try { var response = await DevicesAPI.getReportLogs( - startTime: startTime.toString(), // Convert to String if the API expects it + startTime: + startTime.toString(), // Convert to String if the API expects it endTime: endTime.toString(), // Convert to String if the API expects it deviceUuid: DSId, code: 'doorcontact_state', ); + recordGroups = response; // Process response here print(response); } on DioException catch (e) { @@ -204,8 +162,7 @@ class DoorSensorBloc extends Bloc { List statusList = []; usersMap['status'].forEach((element) { - statusList - .add(StatusModel(code: element['code'], value: element['value'])); + statusList.add(StatusModel(code: element['code'], value: true)); }); deviceStatus = DoorSensorModel.fromJson(statusList); diff --git a/lib/features/devices/model/device_category_model.dart b/lib/features/devices/model/device_category_model.dart index 99ed743..e391d3a 100644 --- a/lib/features/devices/model/device_category_model.dart +++ b/lib/features/devices/model/device_category_model.dart @@ -42,7 +42,9 @@ class DevicesCategoryModel { : name = json['groupName'], // id = json['groupId'], type = devicesTypesMap[json['groupName']] ?? DeviceType.Other, - icon = deviceTypeIconMap[devicesTypesMap[json['groupName']] ?? DeviceType.Other] ?? '', + icon = deviceTypeIconMap[ + devicesTypesMap[json['groupName']] ?? DeviceType.Other] ?? + '', devices = [], isSelected = false; @@ -60,5 +62,9 @@ Map deviceTypeIconMap = { DeviceType.CeilingSensor: Assets.assetsIconsSensors, DeviceType.WallSensor: Assets.assetsIconsSensors, DeviceType.ThreeGang: Assets.assetsIconsGang, + DeviceType.OneGang: Assets.oneGang, + DeviceType.TwoGang: Assets.twoGang, + DeviceType.WH: Assets.waterHeaterIcon, + DeviceType.DS: Assets.doorSensorIcon, DeviceType.Other: Assets.assetsIconsAC, }; diff --git a/lib/features/devices/model/device_model.dart b/lib/features/devices/model/device_model.dart index 2e961f5..866c51a 100644 --- a/lib/features/devices/model/device_model.dart +++ b/lib/features/devices/model/device_model.dart @@ -62,11 +62,14 @@ class DeviceModel { tempIcon = Assets.oneGang; } else if (type == DeviceType.TwoGang) { tempIcon = Assets.twoGang; - }else if (type == DeviceType.WH) { + } else if (type == DeviceType.WH) { tempIcon = Assets.waterHeaterIcon; + } else if (type == DeviceType.DS) { + tempIcon = Assets.doorSensorIcon; } else { tempIcon = Assets.assetsIconsLogo; } + return DeviceModel( icon: tempIcon, activeTime: json['activeTime'], diff --git a/lib/features/devices/model/device_report_model.dart b/lib/features/devices/model/device_report_model.dart new file mode 100644 index 0000000..05604b2 --- /dev/null +++ b/lib/features/devices/model/device_report_model.dart @@ -0,0 +1,51 @@ +class DeviceReport { + final String? deviceUuid; + final int? startTime; + final int? endTime; + final List? data; + + DeviceReport({ + this.deviceUuid, + this.startTime, + this.endTime, + this.data, + }); + + DeviceReport.fromJson(Map json) + : deviceUuid = json['deviceUuid'] as String?, + startTime = json['startTime'] as int?, + endTime = json['endTime'] as int?, + data = (json['data'] as List?) + ?.map((e) => DeviceEvent.fromJson(e as Map)) + .toList(); + + Map toJson() => { + 'deviceUuid': deviceUuid, + 'startTime': startTime, + 'endTime': endTime, + 'data': data?.map((e) => e.toJson()).toList(), + }; +} + +class DeviceEvent { + final String? code; + final int? eventTime; + final String? value; + + DeviceEvent({ + this.code, + this.eventTime, + this.value, + }); + + DeviceEvent.fromJson(Map json) + : code = json['code'] as String?, + eventTime = json['eventTime'] as int?, + value = json['value'] as String?; + + Map toJson() => { + 'code': code, + 'eventTime': eventTime, + 'value': value, + }; +} diff --git a/lib/features/devices/view/widgets/door_sensor/door_notification_settings.dart b/lib/features/devices/view/widgets/door_sensor/door_notification_settings.dart index 6da097a..462e28c 100644 --- a/lib/features/devices/view/widgets/door_sensor/door_notification_settings.dart +++ b/lib/features/devices/view/widgets/door_sensor/door_notification_settings.dart @@ -16,8 +16,8 @@ class NotificationSettingsPage extends StatelessWidget { return DefaultScaffold( title: 'Notification Settings', child: BlocProvider( - create: (context) => DoorSensorBloc(switchCode: 'switch_1', DSId: '') - ..add(const DoorSensorInitial()), + create: (context) => + DoorSensorBloc(DSId: '')..add(const DoorSensorInitial()), child: BlocBuilder( builder: (context, state) { final doorSensorBloc = BlocProvider.of(context); diff --git a/lib/features/devices/view/widgets/door_sensor/door_records_screen.dart b/lib/features/devices/view/widgets/door_sensor/door_records_screen.dart index 3bb9b5a..39635c8 100644 --- a/lib/features/devices/view/widgets/door_sensor/door_records_screen.dart +++ b/lib/features/devices/view/widgets/door_sensor/door_records_screen.dart @@ -7,71 +7,115 @@ import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_s import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; +// // class DoorRecordsScreen extends StatelessWidget { +// final String DSId; +// const DoorRecordsScreen({super.key, required this.DSId}); +// @override +// Widget build(BuildContext context) { +// return DefaultScaffold( +// title: 'Records', +// child: BlocProvider( +// create: (context) => +// DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()), +// child: BlocBuilder( +// builder: (context, state) { +// final doorSensorBloc = BlocProvider.of(context); +// return SizedBox( +// child: ListView.builder( +// itemCount: doorSensorBloc.recordGroups!.data!.length, +// itemBuilder: (context, index) { +// final recordGroup = doorSensorBloc.recordGroups!.data![index]; + class DoorRecordsScreen extends StatelessWidget { - final String DSId; - const DoorRecordsScreen({super.key,required this.DSId}); + final String DSId; + const DoorRecordsScreen({super.key, required this.DSId}); @override Widget build(BuildContext context) { return DefaultScaffold( - title: 'Records', - child: BlocProvider( - create: (context) => - DoorSensorBloc(switchCode: 'switch_1', DSId:DSId ) - ..add(const ReportLogsInitial()), - child: BlocBuilder( - builder: (context, state) { - final doorSensorBloc = BlocProvider.of(context); - return SizedBox( - child: ListView.builder( - itemCount: doorSensorBloc.recordGroups.length, - itemBuilder: (context, index) { - final recordGroup = doorSensorBloc.recordGroups[index]; + title: 'Records', + child: BlocProvider( + create: (context) => + DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()), + child: BlocBuilder( + builder: (context, state) { + if (state is DoorSensorLoadingState) { + return const Center(child: CircularProgressIndicator()); + } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Date header - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - DateFormat('EEEE, dd/MM/yyyy') - .format(recordGroup.date), + if (state is DoorSensorFailedState) { + return Center( + child: Text('Failed to load data: ${state.errorMessage}'), + ); + } + + if (state is UpdateState && state.doorSensor != null) { + final recordGroups = context.read().recordGroups; + + if (recordGroups == null || + recordGroups.data == null || + recordGroups.data!.isEmpty) { + return const Center(child: Text('No records available.')); + } + + return ListView.builder( + itemCount: recordGroups.data!.length, + itemBuilder: (context, index) { + final record = recordGroups.data![index]; + + // Convert eventTime to a human-readable format + final DateTime eventDateTime = + DateTime.fromMillisecondsSinceEpoch(record.eventTime!); + final String formattedDate = + DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime); + final String formattedTime = + DateFormat('HH:mm:ss').format(eventDateTime); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Date header + Padding( + padding: const EdgeInsets.all(16.0), + child: Text( + formattedDate, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + // Display the event details in DefaultContainer + DefaultContainer( + child: ListTile( + leading: Icon( + record.value == 'true' + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + color: record.value == 'true' + ? Colors.blue + : Colors.grey, + ), + title: Text( + 'Status: ${record.value}', style: const TextStyle( - fontSize: 18, fontWeight: FontWeight.bold, + fontSize: 18, ), ), + subtitle: Text('Time: $formattedTime'), ), - // Display each record for the date - DefaultContainer( - child: Column( - children: recordGroup.records.map((record) { - return ListTile( - leading: Icon( - record.isOpen - ? Icons.radio_button_checked - : Icons.radio_button_unchecked, - color: - record.isOpen ? Colors.blue : Colors.grey, - ), - title: Text( - record.status, - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - subtitle: Text(record.time), - ); - }).toList(), - ), - ), - ], - ); - }, - ), + ), + ], + ); + }, ); - }))); + } + + return const Center(child: Text('No data available.')); + }, + ), + ), + ); } } diff --git a/lib/features/devices/view/widgets/door_sensor/door_sensor_screen.dart b/lib/features/devices/view/widgets/door_sensor/door_sensor_screen.dart index 9bf0936..51c70be 100644 --- a/lib/features/devices/view/widgets/door_sensor/door_sensor_screen.dart +++ b/lib/features/devices/view/widgets/door_sensor/door_sensor_screen.dart @@ -25,7 +25,7 @@ class DoorSensorScreen extends StatelessWidget { title: 'Door Sensor', child: BlocProvider( create: (context) => - DoorSensorBloc(switchCode: 'switch_1', DSId: device?.uuid ?? '') + DoorSensorBloc( DSId: device?.uuid ?? '') ..add(const DoorSensorInitial()), child: BlocBuilder( builder: (context, state) { diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index 387fd8c..2699f62 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -1058,4 +1058,5 @@ class Assets { static const String doorNotificationSetting = "assets/icons/door_notification_setting_icon.svg"; static const String doorRecordsIcon = "assets/icons/door_records_icon.svg"; + static const String doorSensorIcon = "assets/icons/door_sensor_icon.svg"; } diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index c61c584..f8a8101 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:syncrow_app/features/devices/model/device_category_model.dart'; import 'package:syncrow_app/features/devices/model/device_control_model.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/model/device_report_model.dart'; import 'package:syncrow_app/features/devices/model/function_model.dart'; import 'package:syncrow_app/services/api/api_links_endpoints.dart'; import 'package:syncrow_app/services/api/http_service.dart'; @@ -358,7 +359,7 @@ class DevicesAPI { return response; } - static Future getReportLogs({ + static Future getReportLogs({ required String deviceUuid, required String code, required String startTime, @@ -373,7 +374,7 @@ class DevicesAPI { .replaceAll('{startTime}', startTime) .replaceAll('{endTime}', endTime), expectedResponseModel: (json) { - print('====---------${json}'); + return DeviceReport.fromJson(json); return json; }, );