From 58e13da887cc0af3985f12e9383ea45d743dd7d3 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sun, 22 Sep 2024 15:32:47 +0300 Subject: [PATCH] door sensor --- assets/icons/closed_door.svg | 47 ++++ .../icons/door_notification_setting_icon.svg | 10 + assets/icons/door_records_icon.svg | 18 ++ assets/icons/opened_door.svg | 47 ++++ .../door_sensor_bloc/door_sensor_bloc.dart | 220 ++++++++++++++++++ .../door_sensor_bloc/door_sensor_event.dart | 102 ++++++++ .../door_sensor_bloc/door_sensor_state.dart | 128 ++++++++++ .../devices/model/door_sensor_model.dart | 33 +++ lib/features/devices/model/report_model.dart | 23 ++ .../door_notification_settings.dart | 123 ++++++++++ .../door_sensor/door_records_screen.dart | 77 ++++++ .../door_sensor/door_sensor_screen.dart | 207 ++++++++++++++++ .../view/widgets/room_page_switch.dart | 26 ++- lib/features/shared_widgets/battery_bar.dart | 57 +++++ lib/generated/assets.dart | 19 +- lib/services/api/api_links_endpoints.dart | 31 ++- lib/services/api/devices_api.dart | 95 +++++--- lib/utils/resource_manager/constants.dart | 149 +++++++----- 18 files changed, 1301 insertions(+), 111 deletions(-) create mode 100644 assets/icons/closed_door.svg create mode 100644 assets/icons/door_notification_setting_icon.svg create mode 100644 assets/icons/door_records_icon.svg create mode 100644 assets/icons/opened_door.svg create mode 100644 lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart create mode 100644 lib/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart create mode 100644 lib/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart create mode 100644 lib/features/devices/model/door_sensor_model.dart create mode 100644 lib/features/devices/model/report_model.dart create mode 100644 lib/features/devices/view/widgets/door_sensor/door_notification_settings.dart create mode 100644 lib/features/devices/view/widgets/door_sensor/door_records_screen.dart create mode 100644 lib/features/devices/view/widgets/door_sensor/door_sensor_screen.dart create mode 100644 lib/features/shared_widgets/battery_bar.dart diff --git a/assets/icons/closed_door.svg b/assets/icons/closed_door.svg new file mode 100644 index 0000000..3c155c2 --- /dev/null +++ b/assets/icons/closed_door.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/door_notification_setting_icon.svg b/assets/icons/door_notification_setting_icon.svg new file mode 100644 index 0000000..75e9aa8 --- /dev/null +++ b/assets/icons/door_notification_setting_icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/icons/door_records_icon.svg b/assets/icons/door_records_icon.svg new file mode 100644 index 0000000..df459ff --- /dev/null +++ b/assets/icons/door_records_icon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/icons/opened_door.svg b/assets/icons/opened_door.svg new file mode 100644 index 0000000..40aa398 --- /dev/null +++ b/assets/icons/opened_door.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 new file mode 100644 index 0000000..91f02ce --- /dev/null +++ b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_bloc.dart @@ -0,0 +1,220 @@ +import 'dart:async'; + +import 'package:dio/dio.dart'; +import 'package:firebase_database/firebase_database.dart'; +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/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()) { + on(_fetchWaterHeaterStatus); + on(fetchLogsForLastMonth); + on(_changeFirstSwitch); + on(_toggleLowBattery); + on(_toggleClosingReminder); + on(_toggleDoorAlarm); + } + Timer? _timer; + bool lowBattery = false; + bool closingReminder = false; + bool doorAlarm = false; + DoorSensorModel deviceStatus = + DoorSensorModel(doorContactState: false, batteryPercentage: 0); + void _fetchWaterHeaterStatus( + DoorSensorInitial event, Emitter emit) async { + emit(DoorSensorLoadingState()); + try { + var response = await DevicesAPI.getDeviceStatus(DSId); + List statusModelList = []; + for (var status in response['status']) { + statusModelList.add(StatusModel.fromJson(status)); + } + deviceStatus = DoorSensorModel.fromJson( + statusModelList, + ); + emit(UpdateState(doorSensor: deviceStatus)); + Future.delayed(const Duration(milliseconds: 500)); + // _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 { + emit(LoadingNewSate(doorSensor: deviceStatus)); + try { + lowBattery = event.isLowBatteryEnabled; + emit(UpdateState(doorSensor: deviceStatus)); + + // API call to update the state, if necessary + await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: DSId, + code: 'low_battery', + value: lowBattery, + ), + DSId, + ); + } catch (e) { + emit(DoorSensorFailedState(errorMessage: e.toString())); + } + } + + void _toggleClosingReminder( + ToggleClosingReminderEvent event, Emitter emit) async { + emit(LoadingNewSate(doorSensor: deviceStatus)); + try { + closingReminder = event.isClosingReminderEnabled; + emit(UpdateState(doorSensor: deviceStatus)); + + // API call to update the state, if necessary + await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: DSId, + code: 'closing_reminder', + value: closingReminder, + ), + DSId, + ); + } catch (e) { + emit(DoorSensorFailedState(errorMessage: e.toString())); + } + } + + void _toggleDoorAlarm( + ToggleDoorAlarmEvent event, Emitter emit) async { + emit(LoadingNewSate(doorSensor: deviceStatus)); + try { + doorAlarm = event.isDoorAlarmEnabled; + emit(UpdateState(doorSensor: deviceStatus)); + + // API call to update the state, if necessary + await DevicesAPI.controlDevice( + DeviceControlModel( + deviceId: DSId, + code: 'door_alarm', + value: doorAlarm, + ), + DSId, + ); + } catch (e) { + emit(DoorSensorFailedState(errorMessage: e.toString())); + } + } + + 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), + ], + ), + ]; + + Future fetchLogsForLastMonth( + ReportLogsInitial event, Emitter emit) async { + // Get the current date and time + DateTime now = DateTime.now(); + + // Calculate the date one month ago + DateTime lastMonth = DateTime(now.year, now.month - 1, now.day); + + // Convert the date to milliseconds since epoch (Unix timestamp in milliseconds) + int startTime = lastMonth.millisecondsSinceEpoch; + int endTime = now.millisecondsSinceEpoch; + try { + var response = await DevicesAPI.getReportLogs( + 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', + ); + // Process response here + print(response); + } on DioException catch (e) { + final errorData = e.response!.data; + String errorMessage = errorData['message']; + // Handle error + print('Error fetching logs: ${errorMessage}'); + } + } + + _listenToChanges() { + try { + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$DSId'); + Stream stream = ref.onValue; + + stream.listen((DatabaseEvent event) async { + if (_timer != null) { + await Future.delayed(const Duration(seconds: 2)); + } + Map usersMap = + event.snapshot.value as Map; + List statusList = []; + + usersMap['status'].forEach((element) { + statusList + .add(StatusModel(code: element['code'], value: element['value'])); + }); + + deviceStatus = DoorSensorModel.fromJson(statusList); + if (!isClosed) { + add( + DoorSensorSwitch(switchD: deviceStatus.doorContactState), + ); + } + }); + } catch (_) {} + } +} diff --git a/lib/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart new file mode 100644 index 0000000..8a99623 --- /dev/null +++ b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_event.dart @@ -0,0 +1,102 @@ +import 'package:equatable/equatable.dart'; + +abstract class DoorSensorEvent extends Equatable { + const DoorSensorEvent(); + + @override + List get props => []; +} + +class DoorSensorLoading extends DoorSensorEvent {} + +class DoorSensorSwitch extends DoorSensorEvent { + final bool switchD; + final String deviceId; + final String productId; + const DoorSensorSwitch({required this.switchD, this.deviceId = '', this.productId = ''}); + + @override + List get props => [switchD, deviceId, productId]; +} + +class DoorSensorUpdated extends DoorSensorEvent {} + +class DoorSensorInitial extends DoorSensorEvent { + const DoorSensorInitial(); +} + +class ReportLogsInitial extends DoorSensorEvent { + const ReportLogsInitial(); +} + + +class DoorSensorChangeStatus extends DoorSensorEvent {} + + +class GetCounterEvent extends DoorSensorEvent { + final String deviceCode; + const GetCounterEvent({required this.deviceCode}); + @override + List get props => [deviceCode]; +} + + + +class ToggleLowBatteryEvent extends DoorSensorEvent { + final bool isLowBatteryEnabled; + + const ToggleLowBatteryEvent(this.isLowBatteryEnabled); + + @override + List get props => [isLowBatteryEnabled]; +} + +class ToggleClosingReminderEvent extends DoorSensorEvent { + final bool isClosingReminderEnabled; + + const ToggleClosingReminderEvent(this.isClosingReminderEnabled); + + @override + List get props => [isClosingReminderEnabled]; +} + +class ToggleDoorAlarmEvent extends DoorSensorEvent { + final bool isDoorAlarmEnabled; + + const ToggleDoorAlarmEvent(this.isDoorAlarmEnabled); + + @override + List get props => [isDoorAlarmEnabled]; +} + + + +class SetCounterValue extends DoorSensorEvent { + final Duration duration; + final String deviceCode; + const SetCounterValue({required this.duration, required this.deviceCode}); + @override + List get props => [duration, deviceCode]; +} + +class StartTimer extends DoorSensorEvent { + final int duration; + + const StartTimer(this.duration); + + @override + List get props => [duration]; +} + +class TickTimer extends DoorSensorEvent { + final int remainingTime; + + const TickTimer(this.remainingTime); + + @override + List get props => [remainingTime]; +} + +class StopTimer extends DoorSensorEvent {} + +class OnClose extends DoorSensorEvent {} diff --git a/lib/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart new file mode 100644 index 0000000..b95e63d --- /dev/null +++ b/lib/features/devices/bloc/door_sensor_bloc/door_sensor_state.dart @@ -0,0 +1,128 @@ +import 'package:equatable/equatable.dart'; +import 'package:syncrow_app/features/devices/model/door_sensor_model.dart'; + + class DoorSensorState extends Equatable { + const DoorSensorState(); + + @override + List get props => []; +} + +class DoorSensorInitialState extends DoorSensorState {} + +class DoorSensorLoadingState extends DoorSensorState {} + +class DoorSensorFailedState extends DoorSensorState { + final String errorMessage; + + const DoorSensorFailedState({required this.errorMessage}); + + @override + List get props => [errorMessage]; +} + +class UpdateState extends DoorSensorState { + final DoorSensorModel doorSensor; + const UpdateState({required this.doorSensor}); + + @override + List get props => [doorSensor]; +} + + +class LoadingNewSate extends DoorSensorState { + final DoorSensorModel doorSensor; + const LoadingNewSate({required this.doorSensor}); + + @override + List get props => [doorSensor]; +} + +// class WHModifyingState extends DoorSensorState { +// final WHModel whStatusModel; +// const WHModifyingState({required this.whStatusModel}); +// +// @override +// List get props => [whStatusModel]; +// } +// +// class GetWHStatusState extends DoorSensorState { +// final WHModel whStatusModel; +// const GetWHStatusState({required this.whStatusModel}); +// +// @override +// List get props => [whStatusModel]; +// } +// +// +// class WHFailedState extends WaterHeaterState { +// final String errorMessage; +// +// const WHFailedState({required this.errorMessage}); +// +// @override +// List get props => [errorMessage]; +// } + + +// class LoadingNewSate extends WaterHeaterState { +// final WHModel whModel; +// const LoadingNewSate({required this.whModel}); +// +// @override +// List get props => [whModel]; +// } +// class TimerRunComplete extends WaterHeaterState {} +// class UpdateTimerState extends WaterHeaterState { +// final int seconds; +// const UpdateTimerState({required this.seconds}); +// +// @override +// List get props => [seconds]; +// } +// +// class TimerRunInProgress extends WaterHeaterState { +// final int remainingTime; +// +// const TimerRunInProgress(this.remainingTime); +// +// @override +// List get props => [remainingTime]; +// } +// +// class SaveSchedule extends WaterHeaterState {} +// class ChangeTimeState extends WaterHeaterState {} +// class UpdateCreateScheduleState extends WaterHeaterState { +// final bool createSchedule; +// UpdateCreateScheduleState(this.createSchedule); +// } +// class IsToggleState extends WaterHeaterState { +// final bool? onOff; +// const IsToggleState({this.onOff}); +// } +// +// +// class UpdateState extends WaterHeaterState { +// final WHModel whModel; +// const UpdateState({required this.whModel}); +// +// @override +// List get props => [WHModel]; +// } +// +// class ChangeSwitchStatusEvent extends WaterHeaterState { +// final bool value; +// final String deviceId; +// const ChangeSwitchStatusEvent({required this.value, this.deviceId = ''}); +// @override +// List get props => [value, deviceId]; +// } +// +// class ChangeSlidingSegmentState extends WaterHeaterState { +// final int value; +// +// const ChangeSlidingSegmentState({required this.value}); +// +// @override +// List get props => [value]; +// } \ No newline at end of file diff --git a/lib/features/devices/model/door_sensor_model.dart b/lib/features/devices/model/door_sensor_model.dart new file mode 100644 index 0000000..7ef8b1d --- /dev/null +++ b/lib/features/devices/model/door_sensor_model.dart @@ -0,0 +1,33 @@ + + + + +import 'package:syncrow_app/features/devices/model/status_model.dart'; + +class DoorSensorModel { + bool doorContactState; + int batteryPercentage; + + DoorSensorModel( + {required this.doorContactState, + required this.batteryPercentage, + }); + + factory DoorSensorModel.fromJson(List jsonList) { + late bool _doorContactState; + late int _batteryPercentage; + + + for (int i = 0; i < jsonList.length; i++) { + if (jsonList[i].code == 'doorcontact_state') { + _doorContactState = jsonList[i].value ?? false; + } else if (jsonList[i].code == 'battery_percentage') { + _batteryPercentage = jsonList[i].value ?? 0; + } + } + return DoorSensorModel( + doorContactState: _doorContactState, + batteryPercentage: _batteryPercentage, + ); + } +} diff --git a/lib/features/devices/model/report_model.dart b/lib/features/devices/model/report_model.dart new file mode 100644 index 0000000..7b47e47 --- /dev/null +++ b/lib/features/devices/model/report_model.dart @@ -0,0 +1,23 @@ +// Record model +class Record { + final String status; + final String time; + final bool isOpen; + + Record({ + required this.status, + required this.time, + required this.isOpen, + }); +} + +// RecordGroup model to group records by date +class RecordGroup { + final DateTime date; + final List records; + + RecordGroup({ + required this.date, + required this.records, + }); +} 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 new file mode 100644 index 0000000..6da097a --- /dev/null +++ b/lib/features/devices/view/widgets/door_sensor/door_notification_settings.dart @@ -0,0 +1,123 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_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/door_sensor_model.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; + +class NotificationSettingsPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return DefaultScaffold( + title: 'Notification Settings', + child: BlocProvider( + create: (context) => DoorSensorBloc(switchCode: 'switch_1', DSId: '') + ..add(const DoorSensorInitial()), + child: BlocBuilder( + builder: (context, state) { + final doorSensorBloc = BlocProvider.of(context); + DoorSensorModel model = DoorSensorModel( + batteryPercentage: 0, doorContactState: false); + if (state is LoadingNewSate) { + model = state.doorSensor; + } else if (state is UpdateState) { + model = state.doorSensor; + } + return state is DoorSensorLoadingState + ? const Center( + child: DefaultContainer( + width: 50, + height: 50, + child: CircularProgressIndicator()), + ) + : Column( + children: [ + DefaultContainer( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 50, + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const BodyLarge( + text: 'Low Battery', + fontWeight: FontWeight.normal, + ), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: doorSensorBloc.lowBattery, + onChanged: (value) { + context.read().add( + ToggleLowBatteryEvent(value)); + }, + applyTheme: true, + )), + ), + ), + const Divider( + color: ColorsManager.graysColor, + ), + SizedBox( + height: 50, + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const BodyLarge( + text: 'Closing Reminder', + fontWeight: FontWeight.normal, + ), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: doorSensorBloc.closingReminder, + onChanged: (value) { + context.read().add( + ToggleClosingReminderEvent( + value)); + }, + applyTheme: true, + )), + ), + ), + const Divider( + color: ColorsManager.graysColor, + ), + SizedBox( + height: 50, + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const BodyLarge( + text: 'Door Alarm', + fontWeight: FontWeight.normal, + ), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: doorSensorBloc.closingReminder, + onChanged: (value) { + context + .read() + .add(ToggleDoorAlarmEvent(value)); + }, + applyTheme: true, + )), + ), + ), + ], + ), + ), + ], + ); + }, + ), + )); + } +} 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 new file mode 100644 index 0000000..3bb9b5a --- /dev/null +++ b/lib/features/devices/view/widgets/door_sensor/door_records_screen.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:intl/intl.dart'; +import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_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/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(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]; + + 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), + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + // 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(), + ), + ), + ], + ); + }, + ), + ); + }))); + } +} 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 new file mode 100644 index 0000000..9bf0936 --- /dev/null +++ b/lib/features/devices/view/widgets/door_sensor/door_sensor_screen.dart @@ -0,0 +1,207 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_app/features/devices/bloc/door_sensor_bloc/door_sensor_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_model.dart'; +import 'package:syncrow_app/features/devices/model/door_sensor_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_notification_settings.dart'; +import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_records_screen.dart'; +import 'package:syncrow_app/features/shared_widgets/battery_bar.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; +import 'package:syncrow_app/generated/assets.dart'; + +class DoorSensorScreen extends StatelessWidget { + final DeviceModel? device; + + const DoorSensorScreen({super.key, this.device}); + + @override + Widget build(BuildContext context) { + return DefaultScaffold( + title: 'Door Sensor', + child: BlocProvider( + create: (context) => + DoorSensorBloc(switchCode: 'switch_1', DSId: device?.uuid ?? '') + ..add(const DoorSensorInitial()), + child: BlocBuilder( + builder: (context, state) { + final doorSensorBloc = BlocProvider.of(context); + DoorSensorModel model = + DoorSensorModel(batteryPercentage: 0, doorContactState: false); + if (state is LoadingNewSate) { + model = state.doorSensor; + } else if (state is UpdateState) { + model = state.doorSensor; + } + return state is DoorSensorLoadingState + ? const Center( + child: DefaultContainer( + width: 50, + height: 50, + child: CircularProgressIndicator()), + ) + : RefreshIndicator( + onRefresh: () async { + doorSensorBloc.add(const DoorSensorInitial()); + }, + child: Center( + child: ListView( + shrinkWrap: true, + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + BatteryBar( + batteryPercentage: model.batteryPercentage, + ), + InkWell( + overlayColor: + WidgetStateProperty.all(Colors.transparent), + onTap: () { + + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + decoration: BoxDecoration( + // color: Colors.white.withOpacity(0.1), + borderRadius: + BorderRadius.circular(890), + boxShadow: [ + BoxShadow( + color: + Colors.white.withOpacity(0.1), + blurRadius: 24, + offset: const Offset(-5, -5), + blurStyle: BlurStyle.outer, + ), + BoxShadow( + color: + Colors.black.withOpacity(0.11), + blurRadius: 25, + offset: const Offset(5, 5), + blurStyle: BlurStyle.outer, + ), + BoxShadow( + color: + Colors.black.withOpacity(0.13), + blurRadius: 30, + offset: const Offset(5, 5), + blurStyle: BlurStyle.inner, + ), + ], + ), + child: SvgPicture.asset( + model.doorContactState + ? Assets.doorOpen + : Assets.doorClose, + fit: BoxFit.fill, + ), + ), + ], + ), + ), + const SizedBox(height: 80), + ], + ), + SizedBox( + height: MediaQuery.of(context).size.height * 0.13, + child: Row( + children: [ + Expanded( + child: DefaultContainer( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + DoorRecordsScreen( + DSId: device!.uuid!)), + ); + }, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 46, maxWidth: 50), + child: SvgPicture.asset( + Assets.doorRecordsIcon), + ), + const SizedBox( + height: 15, + ), + const Flexible( + child: FittedBox( + child: BodySmall( + text: 'Records', + // doorLockButtons.keys.elementAt(index), + textAlign: TextAlign.center, + ), + ), + ), + ], + ), + ), + ), + const SizedBox( + width: 10, + ), + Expanded( + child: DefaultContainer( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => + NotificationSettingsPage()), + ); + }, + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 46, maxWidth: 50), + child: SvgPicture.asset( + Assets.doorNotificationSetting), + ), + const SizedBox( + height: 15, + ), + const Flexible( + child: FittedBox( + child: BodySmall( + text: 'Notification Settings', + // doorLockButtons.keys.elementAt(index), + textAlign: TextAlign.center, + ), + ), + ), + ], + ), + ), + ), + ], + ), + ) + ], + ), + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/features/devices/view/widgets/room_page_switch.dart b/lib/features/devices/view/widgets/room_page_switch.dart index acd7669..93260dd 100644 --- a/lib/features/devices/view/widgets/room_page_switch.dart +++ b/lib/features/devices/view/widgets/room_page_switch.dart @@ -9,10 +9,10 @@ import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/curtains/curtain_view.dart'; +import 'package:syncrow_app/features/devices/view/widgets/door_sensor/door_sensor_screen.dart'; import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart'; -import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_screen.dart'; import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/wall_sensor_interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart'; @@ -31,7 +31,6 @@ class RoomPageSwitch extends StatelessWidget { }); final DeviceModel device; - @override Widget build(BuildContext context) { return GestureDetector( @@ -87,7 +86,8 @@ void showDeviceInterface(DeviceModel device, BuildContext context) { Navigator.push( context, PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => ACsView(deviceModel: device))); + pageBuilder: (context, animation1, animation2) => + ACsView(deviceModel: device))); // navigateToInterface(ACsView(deviceModel: device), context); break; case DeviceType.WallSensor: @@ -110,8 +110,9 @@ void showDeviceInterface(DeviceModel device, BuildContext context) { Navigator.push( context, PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => - CurtainView(curtain: device,))); + pageBuilder: (context, animation1, animation2) => CurtainView( + curtain: device, + ))); break; case DeviceType.Blind: break; @@ -119,14 +120,16 @@ void showDeviceInterface(DeviceModel device, BuildContext context) { Navigator.push( context, PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => DoorInterface(doorLock: device))); + pageBuilder: (context, animation1, animation2) => + DoorInterface(doorLock: device))); // navigateToInterface(DoorInterface(doorlock: device), context); break; case DeviceType.Gateway: Navigator.push( context, PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => GateWayView(gatewayObj: device))); + pageBuilder: (context, animation1, animation2) => + GateWayView(gatewayObj: device))); break; case DeviceType.LightBulb: navigateToInterface(LightInterface(light: device), context); @@ -149,13 +152,18 @@ void showDeviceInterface(DeviceModel device, BuildContext context) { pageBuilder: (context, animation1, animation2) => ThreeGangInterface(gangSwitch: device))); - - case DeviceType.WH: + case DeviceType.WH: Navigator.push( context, PageRouteBuilder( pageBuilder: (context, animation1, animation2) => WaterHeaterPage(device: device))); + case DeviceType.DS: + Navigator.push( + context, + PageRouteBuilder( + pageBuilder: (context, animation1, animation2) => + DoorSensorScreen(device: device))); break; default: } diff --git a/lib/features/shared_widgets/battery_bar.dart b/lib/features/shared_widgets/battery_bar.dart new file mode 100644 index 0000000..9313bab --- /dev/null +++ b/lib/features/shared_widgets/battery_bar.dart @@ -0,0 +1,57 @@ + import 'package:flutter/material.dart'; + + + + +class BatteryBar extends StatelessWidget { + const BatteryBar({ + required this.batteryPercentage, + super.key, + }); + + final int batteryPercentage; + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox(), + Transform.rotate( + angle: 1.5708, // 90 degrees in radians (π/2 or 1.5708) + child: Icon( + _getBatteryIcon(batteryPercentage), + color: _getBatteryColor(batteryPercentage), + size: 30, + ), + ), + ], + ); + } + + IconData _getBatteryIcon(int batteryLevel) { + // if (batteryState == BatteryState.charging) { + // return Icons.battery_charging_full; + // } else + if (batteryLevel >= 80) { + return Icons.battery_full; + } else if (batteryLevel >= 60) { + return Icons.battery_4_bar; + } else if (batteryLevel >= 40) { + return Icons.battery_3_bar; + } else if (batteryLevel >= 20) { + return Icons.battery_2_bar; + } else { + return Icons.battery_alert; + } + } + + Color _getBatteryColor(int batteryLevel) { + if (batteryLevel >= 80) { + return Colors.green; + } else if (batteryLevel >= 40) { + return Colors.yellowAccent; + } else { + return Colors.red; + } + } +} diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index 20bdb39..387fd8c 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -735,7 +735,7 @@ class Assets { //assets/icons/success-white.svg //assets for success white image - static const String assetsSuccessWhite ="assets/icons/success-white.svg"; + static const String assetsSuccessWhite = "assets/icons/success-white.svg"; /// Assets for assetsImagesAutomation /// assets/images/automation.jpg @@ -1044,13 +1044,18 @@ class Assets { static const String waterHeaterOn = "assets/icons/water_heater_on.svg"; static const String waterHeaterOff = "assets/icons/water_heater_off.svg"; - static const String scheduleCelenderIcon = "assets/icons/schedule_celender_icon.svg"; - static const String scheduleCirculateIcon = "assets/icons/schedule_circulate_icon.svg"; - static const String scheduleInchingIcon = "assets/icons/schedule_Inching_icon.svg"; + static const String scheduleCelenderIcon = + "assets/icons/schedule_celender_icon.svg"; + static const String scheduleCirculateIcon = + "assets/icons/schedule_circulate_icon.svg"; + static const String scheduleInchingIcon = + "assets/icons/schedule_Inching_icon.svg"; static const String scheduleTimeIcon = "assets/icons/schedule_time_icon.svg"; static const String waterHeaterIcon = "assets/icons/water_heater_icon.svg"; - - - + static const String doorOpen = "assets/icons/opened_door.svg"; + static const String doorClose = "assets/icons/closed_door.svg"; + static const String doorNotificationSetting = + "assets/icons/door_notification_setting_icon.svg"; + static const String doorRecordsIcon = "assets/icons/door_records_icon.svg"; } diff --git a/lib/services/api/api_links_endpoints.dart b/lib/services/api/api_links_endpoints.dart index 1c3e20f..af3e506 100644 --- a/lib/services/api/api_links_endpoints.dart +++ b/lib/services/api/api_links_endpoints.dart @@ -81,7 +81,8 @@ abstract class ApiEndpoints { static const String controlGroup = '/group/control'; //GET static const String groupBySpace = '/group/{unitUuid}'; - static const String devicesByGroupName = '/group/{unitUuid}/devices/{groupName}'; + static const String devicesByGroupName = + '/group/{unitUuid}/devices/{groupName}'; static const String groupByUuid = '/group/{groupUuid}'; //DELETE @@ -93,7 +94,8 @@ abstract class ApiEndpoints { static const String addDeviceToRoom = '/device/room'; static const String addDeviceToGroup = '/device/group'; static const String controlDevice = '/device/{deviceUuid}/control'; - static const String firmwareDevice = '/device/{deviceUuid}/firmware/{firmwareVersion}'; + static const String firmwareDevice = + '/device/{deviceUuid}/firmware/{firmwareVersion}'; static const String getDevicesByUserId = '/device/user/{userId}'; static const String getDevicesByUnitId = '/device/unit/{unitUuid}'; static const String openDoorLock = '/door-lock/open/{doorLockUuid}'; @@ -103,7 +105,8 @@ abstract class ApiEndpoints { static const String deviceByUuid = '/device/{deviceUuid}'; static const String deviceFunctions = '/device/{deviceUuid}/functions'; static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices'; - static const String deviceFunctionsStatus = '/device/{deviceUuid}/functions/status'; + static const String deviceFunctionsStatus = + '/device/{deviceUuid}/functions/status'; ///Device Permission Module //POST @@ -128,24 +131,29 @@ abstract class ApiEndpoints { static const String getUnitAutomation = '/automation/{unitUuid}'; - static const String getAutomationDetails = '/automation/details/{automationId}'; + static const String getAutomationDetails = + '/automation/details/{automationId}'; /// PUT static const String updateScene = '/scene/tap-to-run/{sceneId}'; static const String updateAutomation = '/automation/{automationId}'; - static const String updateAutomationStatus = '/automation/status/{automationId}'; + static const String updateAutomationStatus = + '/automation/status/{automationId}'; /// DELETE static const String deleteScene = '/scene/tap-to-run/{unitUuid}/{sceneId}'; - static const String deleteAutomation = '/automation/{unitUuid}/{automationId}'; + static const String deleteAutomation = + '/automation/{unitUuid}/{automationId}'; //////////////////////Door Lock ////////////////////// //online - static const String addTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}'; - static const String getTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}'; + static const String addTemporaryPassword = + '/door-lock/temporary-password/online/{doorLockUuid}'; + static const String getTemporaryPassword = + '/door-lock/temporary-password/online/{doorLockUuid}'; //one-time offline static const String addOneTimeTemporaryPassword = @@ -176,11 +184,10 @@ abstract class ApiEndpoints { static const String deleteTemporaryPassword = '/door-lock/temporary-password/online/{doorLockUuid}/{passwordId}'; - static const String saveSchedule = '/schedule/{deviceUuid}'; - static const String getSchedule = '/schedule/{deviceUuid}?category={category}'; + static const String getSchedule = + '/schedule/{deviceUuid}?category={category}'; static const String changeSchedule = '/schedule/enable/{deviceUuid}'; static const String deleteSchedule = '/schedule/{deviceUuid}/{scheduleId}'; - - + static const String reportLogs = '/device/report-logs/{deviceUuid}?code={code}&startTime={startTime}&endTime={endTime}'; } diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index dccb2de..c61c584 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -39,7 +39,6 @@ class DevicesAPI { expectedResponseModel: (json) { return json; }, - ); return response; } catch (e) { @@ -72,7 +71,8 @@ class DevicesAPI { static Future> getDeviceStatus(String deviceId) async { final response = await _httpService.get( - path: ApiEndpoints.deviceFunctionsStatus.replaceAll('{deviceUuid}', deviceId), + path: ApiEndpoints.deviceFunctionsStatus + .replaceAll('{deviceUuid}', deviceId), showServerMessage: false, expectedResponseModel: (json) { return json; @@ -82,7 +82,9 @@ class DevicesAPI { } static Future> renamePass( - {required String name, required String doorLockUuid, required String passwordId}) async { + {required String name, + required String doorLockUuid, + required String passwordId}) async { final response = await _httpService.put( path: ApiEndpoints.renamePassword .replaceAll('{doorLockUuid}', doorLockUuid) @@ -107,7 +109,8 @@ class DevicesAPI { return response; } - static Future> getDeviceByGroupName(String unitId, String groupName) async { + static Future> getDeviceByGroupName( + String unitId, String groupName) async { final response = await _httpService.get( path: ApiEndpoints.devicesByGroupName .replaceAll('{unitUuid}', unitId) @@ -146,7 +149,8 @@ class DevicesAPI { return response; } - static Future> getDevicesByGatewayId(String gatewayId) async { + static Future> getDevicesByGatewayId( + String gatewayId) async { final response = await _httpService.get( path: ApiEndpoints.gatewayApi.replaceAll('{gatewayUuid}', gatewayId), showServerMessage: false, @@ -168,7 +172,8 @@ class DevicesAPI { String deviceId, ) async { final response = await _httpService.get( - path: ApiEndpoints.getTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), + path: ApiEndpoints.getTemporaryPassword + .replaceAll('{doorLockUuid}', deviceId), showServerMessage: false, expectedResponseModel: (json) { return json; @@ -179,7 +184,8 @@ class DevicesAPI { static Future getOneTimePasswords(String deviceId) async { final response = await _httpService.get( - path: ApiEndpoints.getOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), + path: ApiEndpoints.getOneTimeTemporaryPassword + .replaceAll('{doorLockUuid}', deviceId), showServerMessage: false, expectedResponseModel: (json) { return json; @@ -190,7 +196,8 @@ class DevicesAPI { static Future getTimeLimitPasswords(String deviceId) async { final response = await _httpService.get( - path: ApiEndpoints.getMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), + path: ApiEndpoints.getMultipleTimeTemporaryPassword + .replaceAll('{doorLockUuid}', deviceId), showServerMessage: false, expectedResponseModel: (json) { return json; @@ -215,10 +222,12 @@ class DevicesAPI { "invalidTime": invalidTime, }; if (scheduleList != null) { - body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); + body["scheduleList"] = + scheduleList.map((schedule) => schedule.toJson()).toList(); } final response = await _httpService.post( - path: ApiEndpoints.addTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), + path: ApiEndpoints.addTemporaryPassword + .replaceAll('{doorLockUuid}', deviceId), body: body, showServerMessage: false, expectedResponseModel: (json) => json, @@ -229,7 +238,8 @@ class DevicesAPI { static Future generateOneTimePassword({deviceId}) async { try { final response = await _httpService.post( - path: ApiEndpoints.addOneTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), + path: ApiEndpoints.addOneTimeTemporaryPassword + .replaceAll('{doorLockUuid}', deviceId), showServerMessage: false, expectedResponseModel: (json) { return json; @@ -241,10 +251,12 @@ class DevicesAPI { } } - static Future generateMultiTimePassword({deviceId, effectiveTime, invalidTime}) async { + static Future generateMultiTimePassword( + {deviceId, effectiveTime, invalidTime}) async { try { final response = await _httpService.post( - path: ApiEndpoints.addMultipleTimeTemporaryPassword.replaceAll('{doorLockUuid}', deviceId), + path: ApiEndpoints.addMultipleTimeTemporaryPassword + .replaceAll('{doorLockUuid}', deviceId), showServerMessage: true, body: {"effectiveTime": effectiveTime, "invalidTime": invalidTime}, expectedResponseModel: (json) { @@ -277,21 +289,22 @@ class DevicesAPI { required String time, required String code, required bool value, - required List days, + required List days, }) async { final response = await _httpService.post( path: ApiEndpoints.saveSchedule.replaceAll('{deviceUuid}', deviceId), showServerMessage: false, - body: - jsonEncode({ - "category": category, - "time": time, - "function":{ - "code": code, - "value":value, + body: jsonEncode( + { + "category": category, + "time": time, + "function": { + "code": code, + "value": value, + }, + "days": days }, - "days": days - },), + ), expectedResponseModel: (json) { return json; }, @@ -304,7 +317,9 @@ class DevicesAPI { required String deviceId, }) async { final response = await _httpService.get( - path: ApiEndpoints.getSchedule.replaceAll('{deviceUuid}', deviceId).replaceAll('{category}', category), + path: ApiEndpoints.getSchedule + .replaceAll('{deviceUuid}', deviceId) + .replaceAll('{category}', category), showServerMessage: false, expectedResponseModel: (json) { return json; @@ -320,10 +335,7 @@ class DevicesAPI { }) async { final response = await _httpService.put( path: ApiEndpoints.changeSchedule.replaceAll('{deviceUuid}', deviceUuid), - body: { - "scheduleId": scheduleId, - "enable": enable - }, + body: {"scheduleId": scheduleId, "enable": enable}, expectedResponseModel: (json) { return json['success']; }, @@ -336,11 +348,36 @@ class DevicesAPI { required String scheduleId, }) async { final response = await _httpService.delete( - path: ApiEndpoints.deleteSchedule.replaceAll('{deviceUuid}', deviceUuid).replaceAll('{scheduleId}', scheduleId), + path: ApiEndpoints.deleteSchedule + .replaceAll('{deviceUuid}', deviceUuid) + .replaceAll('{scheduleId}', scheduleId), expectedResponseModel: (json) { return json; }, ); return response; } + + static Future getReportLogs({ + required String deviceUuid, + required String code, + required String startTime, + required String endTime, + }) async { + // print( + // '---------${ApiEndpoints.reportLogs.replaceAll('{deviceUuid}', deviceUuid).replaceAll('{code}', code).replaceAll('{startTime}', startTime).replaceAll('{endTime}', endTime)}'); + final response = await _httpService.get( + path: ApiEndpoints.reportLogs + .replaceAll('{deviceUuid}', deviceUuid) + .replaceAll('{code}', code) + .replaceAll('{startTime}', startTime) + .replaceAll('{endTime}', endTime), + expectedResponseModel: (json) { + print('====---------${json}'); + return json; + }, + ); + + return response; + } } diff --git a/lib/utils/resource_manager/constants.dart b/lib/utils/resource_manager/constants.dart index 4f3ba8a..2ce280f 100644 --- a/lib/utils/resource_manager/constants.dart +++ b/lib/utils/resource_manager/constants.dart @@ -1,6 +1,5 @@ //ignore_for_file: constant_identifier_names import 'dart:ui'; - import 'package:syncrow_app/features/devices/model/function_model.dart'; import 'package:syncrow_app/features/menu/view/widgets/create_home/create_home_view.dart'; import 'package:syncrow_app/features/menu/view/widgets/join_home/join_home_view.dart'; @@ -50,6 +49,7 @@ enum DeviceType { CeilingSensor, WallSensor, WH, + DS, Other, } @@ -75,11 +75,14 @@ Map devicesTypesMap = { "1G": DeviceType.OneGang, "CUR": DeviceType.Curtain, "WH": DeviceType.WH, + "DS": DeviceType.DS, }; Map> devicesFunctionsMap = { DeviceType.AC: [ FunctionModel( - code: 'switch', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'switch', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( code: 'mode', type: functionTypesMap['Enum'], @@ -102,7 +105,9 @@ Map> devicesFunctionsMap = { // "range": ["low", "middle", "high", "auto"] })), FunctionModel( - code: 'child_lock', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'child_lock', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), ], DeviceType.Gateway: [ FunctionModel( @@ -116,7 +121,9 @@ Map> devicesFunctionsMap = { "range": ["normal", "alarm"] })), FunctionModel( - code: 'factory_reset', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'factory_reset', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( code: 'alarm_active', type: functionTypesMap['String'], @@ -126,7 +133,8 @@ Map> devicesFunctionsMap = { FunctionModel( code: 'sensitivity', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "", "min": 1, "max": 10, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "", "min": 1, "max": 10, "scale": 0, "step": 1})), ], DeviceType.DoorLock: [ FunctionModel( @@ -134,7 +142,9 @@ Map> devicesFunctionsMap = { type: functionTypesMap['Raw'], values: ValueModel.fromJson({})), FunctionModel( - code: 'remote_no_dp_key', type: functionTypesMap['Raw'], values: ValueModel.fromJson({})), + code: 'remote_no_dp_key', + type: functionTypesMap['Raw'], + values: ValueModel.fromJson({})), FunctionModel( code: 'normal_open_switch', type: functionTypesMap['Boolean'], @@ -144,120 +154,143 @@ Map> devicesFunctionsMap = { FunctionModel( code: 'far_detection', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "cm", "min": 75, "max": 600, "scale": 0, "step": 75})), + values: ValueModel.fromJson( + {"unit": "cm", "min": 75, "max": 600, "scale": 0, "step": 75})), FunctionModel( code: 'presence_time', type: functionTypesMap['Integer'], - values: - ValueModel.fromJson({"unit": "Min", "min": 0, "max": 65535, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "Min", "min": 0, "max": 65535, "scale": 0, "step": 1})), FunctionModel( code: 'motion_sensitivity_value', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "", "min": 1, "max": 5, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "", "min": 1, "max": 5, "scale": 0, "step": 1})), FunctionModel( code: 'motionless_sensitivity', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "", "min": 1, "max": 5, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "", "min": 1, "max": 5, "scale": 0, "step": 1})), FunctionModel( - code: 'indicator', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'indicator', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), ], - DeviceType.OneGang:[ + DeviceType.OneGang: [ FunctionModel( - code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'switch_1', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( code: 'countdown_1', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), ], - DeviceType.TwoGang:[ + DeviceType.TwoGang: [ FunctionModel( - code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({}) - ), + code: 'switch_1', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( - code: 'switch_2', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({}) - ), + code: 'switch_2', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( code: 'countdown_1', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1}) - ), + values: ValueModel.fromJson( + {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), FunctionModel( code: 'countdown_2', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1}) - ), + values: ValueModel.fromJson( + {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), ], DeviceType.ThreeGang: [ FunctionModel( - code: 'switch_1', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'switch_1', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( - code: 'switch_2', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'switch_2', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( - code: 'switch_3', type: functionTypesMap['Boolean'], values: ValueModel.fromJson({})), + code: 'switch_3', + type: functionTypesMap['Boolean'], + values: ValueModel.fromJson({})), FunctionModel( code: 'countdown_1', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), FunctionModel( code: 'countdown_2', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), FunctionModel( code: 'countdown_3', type: functionTypesMap['Integer'], - values: ValueModel.fromJson({"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), + values: ValueModel.fromJson( + {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), ], DeviceType.Curtain: [ FunctionModel( code: 'control', type: functionTypesMap['Enum'], - values: ValueModel.fromJson( - {"range": ["open","stop","close"]} - ) - ), + values: ValueModel.fromJson({ + "range": ["open", "stop", "close"] + })), FunctionModel( code: 'percent_control', type: functionTypesMap['Integer'], values: ValueModel.fromJson( - {"unit": "%", "min": 0, "max": 100, "scale": 0, "step": 1}) - ), + {"unit": "%", "min": 0, "max": 100, "scale": 0, "step": 1})), ], DeviceType.WH: [ FunctionModel( code: 'switch_1', type: functionTypesMap['Boolean'], - values: ValueModel.fromJson({}) - ), + values: ValueModel.fromJson({})), FunctionModel( code: 'countdown_1', type: functionTypesMap['Integer'], values: ValueModel.fromJson( - {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1}) - ), + {"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})), FunctionModel( code: 'relay_status', type: functionTypesMap['Enum'], - values: ValueModel.fromJson( - {"range": [ "off", "on"]}) - ), + values: ValueModel.fromJson({ + "range": ["off", "on"] + })), FunctionModel( code: 'switch_backlight', type: functionTypesMap['Boolean'], - values: ValueModel.fromJson( - {}) - ), + values: ValueModel.fromJson({})), FunctionModel( code: 'switch_inching', type: functionTypesMap['String'], - values: ValueModel.fromJson( - {"maxlen": 255,}) - ), + values: ValueModel.fromJson({ + "maxlen": 255, + })), FunctionModel( code: 'cycle_timing', type: functionTypesMap['Raw'], - values: ValueModel.fromJson( - {"maxlen": 255}) - ), + values: ValueModel.fromJson({"maxlen": 255})), + ], + DeviceType.DS: [ + FunctionModel( + code: 'doorcontact_state', + type: functionTypesMap['Raw'], + values: ValueModel.fromJson({}) + ), + FunctionModel( + code: 'battery_percentage', + type: functionTypesMap['Integer'], + values: ValueModel.fromJson({}) + ), ], }; @@ -404,7 +437,11 @@ List> menuSections = [ 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsMessages, 'page': null }, - {'title': 'FAQs', 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsFAQs, 'page': null}, + { + 'title': 'FAQs', + 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsFAQs, + 'page': null + }, { 'title': 'Help & Feedback', 'Icon': Assets.assetsIconsMenuIconsMessagesCenterIconsHelpAndFeedback, @@ -434,7 +471,11 @@ List> menuSections = [ 'title': 'Legal Information', 'color': const Color(0xFF001B72), 'buttons': [ - {'title': 'About', 'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsAbout, 'page': null}, + { + 'title': 'About', + 'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsAbout, + 'page': null + }, { 'title': 'Privacy Policy', 'Icon': Assets.assetsIconsMenuIconsLeagalInfoIconsPrivacyPolicy,