From 58e13da887cc0af3985f12e9383ea45d743dd7d3 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sun, 22 Sep 2024 15:32:47 +0300 Subject: [PATCH 1/9] 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, From d97efe229db4f3b58b957cdf3281bf8ca0db7204 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sun, 22 Sep 2024 17:27:29 +0300 Subject: [PATCH 2/9] 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; }, ); From 62e80c89a256a088d0909bde3b0be9fec09ffb41 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Mon, 23 Sep 2024 00:35:07 +0300 Subject: [PATCH 3/9] Bug fixes --- .../door_sensor_bloc/door_sensor_bloc.dart | 27 +- .../bloc/one_gang_bloc/one_gang_bloc.dart | 49 ++- .../bloc/one_gang_bloc/one_gang_state.dart | 15 +- .../bloc/three_gang_bloc/three_gang_bloc.dart | 53 ++- .../bloc/two_gang_bloc/two_gang_bloc.dart | 109 +++--- .../bloc/two_gang_bloc/two_gang_state.dart | 8 +- .../devices/model/device_report_model.dart | 8 +- .../devices/model/group_one_gang_model.dart | 11 + ...ngModel.dart => group_two_gang_model.dart} | 0 .../view/widgets/curtains/curtain_list.dart | 3 - .../view/widgets/curtains/curtain_view.dart | 11 +- .../devices/view/widgets/device_appbar.dart | 32 +- .../door_notification_settings.dart | 27 +- .../door_sensor/door_records_screen.dart | 19 +- .../view/widgets/gateway/gateway_view.dart | 25 +- .../view/widgets/lights/lights_view_list.dart | 1 - .../offline_one_time_password_page.dart | 304 ++++++++-------- .../widgets/one_gang/one_gang_Interface.dart | 1 - .../view/widgets/one_gang/one_gang_list.dart | 66 ++++ .../widgets/one_gang/one_gang_screen.dart | 250 ++++++------- .../devices/view/widgets/room_page.dart | 2 - .../smart_door/create_temporary_password.dart | 263 +++++++------- .../view/widgets/smart_door/door_dialog.dart | 115 +++--- .../view/widgets/smart_door/door_grid.dart | 48 ++- .../smart_door/onetime_password_page.dart | 181 +++++----- .../smart_door/timelimited_password_page.dart | 159 ++++----- .../view/widgets/three_gang/gang_switch.dart | 2 +- .../view/widgets/three_gang/timer_screen.dart | 333 +++++++++--------- .../view/widgets/two_gang/two_gang_list.dart | 26 +- .../widgets/two_gang/two_gang_screen.dart | 21 +- .../devices/view/widgets/wizard_page.dart | 14 + .../shared_widgets/schedule_list.dart | 172 +++++---- lib/services/api/devices_api.dart | 40 +-- 33 files changed, 1203 insertions(+), 1192 deletions(-) create mode 100644 lib/features/devices/model/group_one_gang_model.dart rename lib/features/devices/model/{groupTwoGangModel.dart => group_two_gang_model.dart} (100%) create mode 100644 lib/features/devices/view/widgets/one_gang/one_gang_list.dart 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 971682d..636edc7 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 @@ -26,11 +26,9 @@ class DoorSensorBloc extends Bloc { bool lowBattery = false; bool closingReminder = false; bool doorAlarm = false; - DoorSensorModel deviceStatus = - DoorSensorModel(doorContactState: false, batteryPercentage: 0); + DoorSensorModel deviceStatus = DoorSensorModel(doorContactState: false, batteryPercentage: 0); - void _fetchWaterHeaterStatus( - DoorSensorInitial event, Emitter emit) async { + void _fetchWaterHeaterStatus(DoorSensorInitial event, Emitter emit) async { emit(DoorSensorLoadingState()); try { var response = await DevicesAPI.getDeviceStatus(DSId); @@ -51,8 +49,7 @@ class DoorSensorBloc extends Bloc { } // Toggle functions for each switch - void _toggleLowBattery( - ToggleLowBatteryEvent event, Emitter emit) async { + void _toggleLowBattery(ToggleLowBatteryEvent event, Emitter emit) async { emit(LoadingNewSate(doorSensor: deviceStatus)); try { lowBattery = event.isLowBatteryEnabled; @@ -93,8 +90,7 @@ class DoorSensorBloc extends Bloc { } } - void _toggleDoorAlarm( - ToggleDoorAlarmEvent event, Emitter emit) async { + void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter emit) async { emit(LoadingNewSate(doorSensor: deviceStatus)); try { doorAlarm = event.isDoorAlarmEnabled; @@ -114,11 +110,9 @@ class DoorSensorBloc extends Bloc { } } - DeviceReport recordGroups = DeviceReport(startTime: 0, endTime: 0, data: []); + DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []); - - Future fetchLogsForLastMonth( - ReportLogsInitial event, Emitter emit) async { + Future fetchLogsForLastMonth(ReportLogsInitial event, Emitter emit) async { // Get the current date and time DateTime now = DateTime.now(); @@ -130,8 +124,7 @@ 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', @@ -149,16 +142,14 @@ class DoorSensorBloc extends Bloc { _listenToChanges() { try { - DatabaseReference ref = - FirebaseDatabase.instance.ref('device-status/$DSId'); + 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; + Map usersMap = event.snapshot.value as Map; List statusList = []; usersMap['status'].forEach((element) { diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart index 987b873..061dbca 100644 --- a/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart @@ -24,7 +24,7 @@ class OneGangBloc extends Bloc { bool oneGangGroup = false; List devicesList = []; - OneGangBloc({required this.oneGangId,required this.switchCode}) : super(InitialState()) { + OneGangBloc({required this.oneGangId, required this.switchCode}) : super(InitialState()) { on(_fetchOneGangStatus); on(_oneGangUpdated); on(_changeFirstSwitch); @@ -34,9 +34,6 @@ class OneGangBloc extends Bloc { on(_onTickTimer); on(_onClose); - - - on(toggleDaySelection); on(saveSchedule); on(getSchedule); @@ -114,7 +111,6 @@ class OneGangBloc extends Bloc { } } - void _changeSliding(ChangeSlidingSegment event, Emitter emit) async { emit(ChangeSlidingSegmentState(value: event.value)); } @@ -199,11 +195,14 @@ class OneGangBloc extends Bloc { {"day": "Sat", "key": "Sat"}, ]; - Future saveSchedule(ThreeGangSave event, Emitter emit,) async { + Future saveSchedule( + ThreeGangSave event, + Emitter emit, + ) async { try { - if(selectedDays.isNotEmpty) { + if (selectedDays.isNotEmpty) { emit(LoadingInitialState()); - final response = await DevicesAPI.postSchedule( + await DevicesAPI.postSchedule( category: switchCode, deviceId: oneGangId, time: getTimeStampWithoutSeconds(selectedTime).toString(), @@ -214,7 +213,7 @@ class OneGangBloc extends Bloc { add(GetScheduleEvent()); emit(ThreeGangSaveSchedule()); toggleCreateSchedule(); - }else{ + } else { CustomSnackBar.displaySnackBar('Please select days'); } } catch (e) { @@ -222,13 +221,15 @@ class OneGangBloc extends Bloc { } } - - Future getSchedule(GetScheduleEvent event, Emitter emit,) async { + Future getSchedule( + GetScheduleEvent event, + Emitter emit, + ) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.getSchedule( category: switchCode, - deviceId: oneGangId , + deviceId: oneGangId, ); List jsonData = response; listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); @@ -242,13 +243,12 @@ class OneGangBloc extends Bloc { int? getTimeStampWithoutSeconds(DateTime? dateTime) { if (dateTime == null) return null; - DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month, - dateTime.day, dateTime.hour, dateTime.minute); + DateTime dateTimeWithoutSeconds = + DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; } - Future toggleChange( - ToggleScheduleEvent event, Emitter emit) async { + Future toggleChange(ToggleScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.changeSchedule( @@ -267,13 +267,13 @@ class OneGangBloc extends Bloc { } } - Future deleteSchedule( - DeleteScheduleEvent event, Emitter emit) async { + Future deleteSchedule(DeleteScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.deleteSchedule( scheduleId: event.id, - deviceUuid: oneGangId, ); + deviceUuid: oneGangId, + ); if (response == true) { add(GetScheduleEvent()); return toggleSchedule; @@ -291,7 +291,7 @@ class OneGangBloc extends Bloc { emit(LoadingInitialState()); createSchedule = !createSchedule; selectedDays.clear(); - selectedTime=DateTime.now(); + selectedTime = DateTime.now(); emit(UpdateCreateScheduleState(createSchedule)); emit(ChangeSlidingSegmentState(value: 1)); } @@ -300,11 +300,11 @@ class OneGangBloc extends Bloc { List selectedDays = []; bool createSchedule = false; List listSchedule = []; - DateTime? selectedTime=DateTime.now(); + DateTime? selectedTime = DateTime.now(); Future toggleDaySelection( - ToggleDaySelectionEvent event, - Emitter emit, - ) async { + ToggleDaySelectionEvent event, + Emitter emit, + ) async { emit(LoadingInitialState()); if (selectedDays.contains(event.key)) { selectedDays.remove(event.key); @@ -322,5 +322,4 @@ class OneGangBloc extends Bloc { selectedTabIndex = index; emit(ChangeSlidingSegmentState(value: selectedTabIndex)); } - } diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart index 17f375a..4078ccf 100644 --- a/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart @@ -1,9 +1,8 @@ import 'package:equatable/equatable.dart'; -import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/group_one_gang_model.dart'; import 'package:syncrow_app/features/devices/model/one_gang_model.dart'; import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; - class OneGangState extends Equatable { const OneGangState(); @@ -32,13 +31,13 @@ class LoadingNewSate extends OneGangState { } class UpdateGroupState extends OneGangState { - final List twoGangList; + final List oneGangList; final bool allSwitches; - const UpdateGroupState({required this.twoGangList, required this.allSwitches}); + const UpdateGroupState({required this.oneGangList, required this.allSwitches}); @override - List get props => [twoGangList, allSwitches]; + List get props => [oneGangList, allSwitches]; } class FailedState extends OneGangState { @@ -77,13 +76,17 @@ class TimerRunInProgress extends OneGangState { } class TimerRunComplete extends OneGangState {} + class ThreeGangSaveSchedule extends OneGangState {} + class IsToggleState extends OneGangState { final bool? onOff; const IsToggleState({this.onOff}); } + class ChangeTimeState extends OneGangState {} + class UpdateCreateScheduleState extends OneGangState { final bool createSchedule; UpdateCreateScheduleState(this.createSchedule); -} \ No newline at end of file +} diff --git a/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart b/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart index a707013..2822b1b 100644 --- a/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart +++ b/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart @@ -14,7 +14,6 @@ import 'package:syncrow_app/features/devices/model/three_gang_model.dart'; import 'package:syncrow_app/services/api/devices_api.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart'; - class ThreeGangBloc extends Bloc { final String threeGangId; final String switchCode; @@ -35,7 +34,7 @@ class ThreeGangBloc extends Bloc { List groupThreeGangList = []; bool allSwitchesOn = true; - ThreeGangBloc({required this.threeGangId,required this.switchCode}) : super(InitialState()) { + ThreeGangBloc({required this.threeGangId, required this.switchCode}) : super(InitialState()) { on(_fetchThreeGangStatus); on(_threeGangUpdated); on(_changeFirstSwitch); @@ -51,8 +50,6 @@ class ThreeGangBloc extends Bloc { on(_groupAllOn); on(_groupAllOff); - - on(toggleDaySelection); on(saveSchedule); on(getSchedule); @@ -490,9 +487,6 @@ class ThreeGangBloc extends Bloc { } } - - - List> days = [ {"day": "Sun", "key": "Sun"}, {"day": "Mon", "key": "Mon"}, @@ -504,9 +498,9 @@ class ThreeGangBloc extends Bloc { ]; Future toggleDaySelection( - ToggleDaySelectionEvent event, - Emitter emit, - ) async { + ToggleDaySelectionEvent event, + Emitter emit, + ) async { emit(LoadingInitialState()); if (selectedDays.contains(event.key)) { selectedDays.remove(event.key); @@ -517,11 +511,14 @@ class ThreeGangBloc extends Bloc { add(ChangeSlidingSegment(value: 1)); } - Future saveSchedule(ThreeGangSave event, Emitter emit,) async { + Future saveSchedule( + ThreeGangSave event, + Emitter emit, + ) async { try { - if(selectedDays.isNotEmpty) { + if (selectedDays.isNotEmpty) { emit(LoadingInitialState()); - final response = await DevicesAPI.postSchedule( + await DevicesAPI.postSchedule( category: switchCode, deviceId: threeGangId, time: getTimeStampWithoutSeconds(selectedTime).toString(), @@ -532,7 +529,7 @@ class ThreeGangBloc extends Bloc { add(GetScheduleEvent()); emit(ThreeGangSaveSchedule()); toggleCreateSchedule(); - }else{ + } else { CustomSnackBar.displaySnackBar('Please select days'); } } catch (e) { @@ -540,13 +537,15 @@ class ThreeGangBloc extends Bloc { } } - - Future getSchedule(GetScheduleEvent event, Emitter emit,) async { + Future getSchedule( + GetScheduleEvent event, + Emitter emit, + ) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.getSchedule( category: switchCode, - deviceId: threeGangId , + deviceId: threeGangId, ); List jsonData = response; listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); @@ -560,13 +559,12 @@ class ThreeGangBloc extends Bloc { int? getTimeStampWithoutSeconds(DateTime? dateTime) { if (dateTime == null) return null; - DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month, - dateTime.day, dateTime.hour, dateTime.minute); + DateTime dateTimeWithoutSeconds = + DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; } - Future toggleChange( - ToggleScheduleEvent event, Emitter emit) async { + Future toggleChange(ToggleScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.changeSchedule( @@ -585,13 +583,13 @@ class ThreeGangBloc extends Bloc { } } - Future deleteSchedule( - DeleteScheduleEvent event, Emitter emit) async { + Future deleteSchedule(DeleteScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.deleteSchedule( - scheduleId: event.id, - deviceUuid: threeGangId, ); + scheduleId: event.id, + deviceUuid: threeGangId, + ); if (response == true) { add(GetScheduleEvent()); return toggleSchedule; @@ -609,7 +607,7 @@ class ThreeGangBloc extends Bloc { emit(LoadingInitialState()); createSchedule = !createSchedule; selectedDays.clear(); - selectedTime=DateTime.now(); + selectedTime = DateTime.now(); emit(UpdateCreateScheduleState(createSchedule)); emit(ChangeSlidingSegmentState(value: 1)); } @@ -626,6 +624,5 @@ class ThreeGangBloc extends Bloc { List selectedDays = []; bool createSchedule = false; List listSchedule = []; - DateTime? selectedTime=DateTime.now(); - + DateTime? selectedTime = DateTime.now(); } diff --git a/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart b/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart index b2f1e45..bb1c329 100644 --- a/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart @@ -7,7 +7,7 @@ import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_event.d import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_state.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/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/group_two_gang_model.dart'; import 'package:syncrow_app/features/devices/model/schedule_model.dart'; import 'package:syncrow_app/features/devices/model/status_model.dart'; import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; @@ -35,7 +35,7 @@ class TwoGangBloc extends Bloc { bool createSchedule = false; List listSchedule = []; - TwoGangBloc({required this.twoGangId,required this.switchCode}) : super(InitialState()) { + TwoGangBloc({required this.twoGangId, required this.switchCode}) : super(InitialState()) { on(_fetchTwoGangStatus); on(_twoGangUpdated); on(_changeFirstSwitch); @@ -54,7 +54,6 @@ class TwoGangBloc extends Bloc { on(getSchedule); on(toggleRepeat); on(deleteSchedule); - } DateTime? selectedTime = DateTime.now(); @@ -63,10 +62,11 @@ class TwoGangBloc extends Bloc { emit(LoadingInitialState()); createSchedule = !createSchedule; selectedDays.clear(); - selectedTime=DateTime.now(); + selectedTime = DateTime.now(); emit(UpdateCreateScheduleState(createSchedule)); emit(ChangeSlidingSegmentState(value: 1)); } + int selectedTabIndex = 0; void toggleSelectedIndex(index) { @@ -87,8 +87,7 @@ class TwoGangBloc extends Bloc { HomeCubit.getInstance().selectedSpace?.id ?? '', '2G'); for (int i = 0; i < devicesList.length; i++) { - var response = - await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); + var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); List statusModelList = []; for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status)); @@ -111,8 +110,7 @@ class TwoGangBloc extends Bloc { return true; }); } - emit(UpdateGroupState( - twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); + emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); } else { var response = await DevicesAPI.getDeviceStatus(twoGangId); List statusModelList = []; @@ -131,21 +129,18 @@ class TwoGangBloc extends Bloc { _listenToChanges() { try { - DatabaseReference ref = - FirebaseDatabase.instance.ref('device-status/$twoGangId'); + DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoGangId'); 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; + Map usersMap = event.snapshot.value as Map; List statusList = []; usersMap['status'].forEach((element) { - statusList - .add(StatusModel(code: element['code'], value: element['value'])); + statusList.add(StatusModel(code: element['code'], value: element['value'])); }); deviceStatus = TwoGangModel.fromJson(statusList); @@ -160,8 +155,7 @@ class TwoGangBloc extends Bloc { emit(UpdateState(twoGangModel: deviceStatus)); } - void _changeFirstSwitch( - ChangeFirstSwitchStatusEvent event, Emitter emit) async { + void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { deviceStatus.firstSwitch = !event.value; @@ -187,8 +181,7 @@ class TwoGangBloc extends Bloc { } } - void _changeSecondSwitch( - ChangeSecondSwitchStatusEvent event, Emitter emit) async { + void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { deviceStatus.secondSwitch = !event.value; @@ -224,15 +217,11 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, - code: 'switch_1', - value: deviceStatus.firstSwitch), + deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), twoGangId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, - code: 'switch_2', - value: deviceStatus.secondSwitch), + deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), twoGangId), ]); @@ -255,15 +244,11 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, - code: 'switch_1', - value: deviceStatus.firstSwitch), + deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), twoGangId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, - code: 'switch_2', - value: deviceStatus.secondSwitch), + deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), twoGangId), ]); if (response.every((element) => !element['success'])) { @@ -289,15 +274,11 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, - code: 'switch_1', - value: true), + deviceId: groupTwoGangList[i].deviceId, code: 'switch_1', value: true), groupTwoGangList[i].deviceId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, - code: 'switch_2', - value: true), + deviceId: groupTwoGangList[i].deviceId, code: 'switch_2', value: true), groupTwoGangList[i].deviceId), ]); @@ -326,15 +307,11 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, - code: 'switch_1', - value: false), + deviceId: groupTwoGangList[i].deviceId, code: 'switch_1', value: false), groupTwoGangList[i].deviceId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, - code: 'switch_2', - value: false), + deviceId: groupTwoGangList[i].deviceId, code: 'switch_2', value: false), groupTwoGangList[i].deviceId), ]); @@ -350,29 +327,23 @@ class TwoGangBloc extends Bloc { } } - void _changeSliding( - ChangeSlidingSegment event, Emitter emit) async { + void _changeSliding(ChangeSlidingSegment event, Emitter emit) async { emit(ChangeSlidingSegmentState(value: event.value)); } - void _setCounterValue( - SetCounterValue event, Emitter emit) async { + void _setCounterValue(SetCounterValue event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); int seconds = 0; try { seconds = event.duration.inSeconds; final response = await DevicesAPI.controlDevice( - DeviceControlModel( - deviceId: twoGangId, - code: event.deviceCode, - value: seconds), + DeviceControlModel(deviceId: twoGangId, code: event.deviceCode, value: seconds), twoGangId); if (response['success'] ?? false) { if (event.deviceCode == 'countdown_1') { deviceStatus.firstCountDown = seconds; - } - else if (event.deviceCode == 'countdown_2') { + } else if (event.deviceCode == 'countdown_2') { deviceStatus.secondCountDown = seconds; } } else { @@ -391,8 +362,7 @@ class TwoGangBloc extends Bloc { } } - void _getCounterValue( - GetCounterEvent event, Emitter emit) async { + void _getCounterValue(GetCounterEvent event, Emitter emit) async { emit(LoadingInitialState()); try { add(GetScheduleEvent()); @@ -462,9 +432,12 @@ class TwoGangBloc extends Bloc { add(ChangeSlidingSegment(value: 1)); } - Future saveSchedule(TwoGangSave event, Emitter emit,) async { + Future saveSchedule( + TwoGangSave event, + Emitter emit, + ) async { try { - if(selectedDays.isNotEmpty) { + if (selectedDays.isNotEmpty) { emit(LoadingInitialState()); final response = await DevicesAPI.postSchedule( category: switchCode, @@ -477,7 +450,7 @@ class TwoGangBloc extends Bloc { add(GetScheduleEvent()); emit(TwoGangSaveSchedule()); toggleCreateSchedule(); - }else{ + } else { CustomSnackBar.displaySnackBar('Please select days'); } } catch (e) { @@ -485,7 +458,10 @@ class TwoGangBloc extends Bloc { } } - Future getSchedule(GetScheduleEvent event, Emitter emit,) async { + Future getSchedule( + GetScheduleEvent event, + Emitter emit, + ) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.getSchedule( @@ -504,19 +480,16 @@ class TwoGangBloc extends Bloc { int? getTimeStampWithoutSeconds(DateTime? dateTime) { if (dateTime == null) return null; - DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month, - dateTime.day, dateTime.hour, dateTime.minute); + DateTime dateTimeWithoutSeconds = + DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; } - Future toggleRepeat( - ToggleScheduleEvent event, Emitter emit) async { + Future toggleRepeat(ToggleScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.changeSchedule( - scheduleId: event.id, - deviceUuid: twoGangId, - enable: event.toggle); + scheduleId: event.id, deviceUuid: twoGangId, enable: event.toggle); if (response == true) { add(GetScheduleEvent()); toggleSchedule = event.toggle; @@ -531,13 +504,13 @@ class TwoGangBloc extends Bloc { } } - Future deleteSchedule( - DeleteScheduleEvent event, Emitter emit) async { + Future deleteSchedule(DeleteScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.deleteSchedule( scheduleId: event.id, - deviceUuid: twoGangId, ); + deviceUuid: twoGangId, + ); if (response == true) { add(GetScheduleEvent()); return toggleSchedule; diff --git a/lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart b/lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart index 72c8537..3435e4d 100644 --- a/lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_state.dart @@ -1,8 +1,7 @@ import 'package:equatable/equatable.dart'; -import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/group_two_gang_model.dart'; import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; - class TwoGangState extends Equatable { const TwoGangState(); @@ -11,7 +10,9 @@ class TwoGangState extends Equatable { } class InitialState extends TwoGangState {} + class TwoGangSaveSchedule extends TwoGangState {} + class ChangeTimeState extends TwoGangState {} class LoadingInitialState extends TwoGangState {} @@ -78,13 +79,12 @@ class TimerRunInProgress extends TwoGangState { } class TimerRunComplete extends TwoGangState {} + class IsToggleState extends TwoGangState { final bool? onOff; const IsToggleState({this.onOff}); } - - // two_gang_state.dart class UpdateCreateScheduleState extends TwoGangState { final bool createSchedule; diff --git a/lib/features/devices/model/device_report_model.dart b/lib/features/devices/model/device_report_model.dart index 05604b2..b73dc77 100644 --- a/lib/features/devices/model/device_report_model.dart +++ b/lib/features/devices/model/device_report_model.dart @@ -1,7 +1,7 @@ class DeviceReport { final String? deviceUuid; - final int? startTime; - final int? endTime; + final String? startTime; + final String? endTime; final List? data; DeviceReport({ @@ -13,8 +13,8 @@ class DeviceReport { DeviceReport.fromJson(Map json) : deviceUuid = json['deviceUuid'] as String?, - startTime = json['startTime'] as int?, - endTime = json['endTime'] as int?, + startTime = json['startTime'] as String?, + endTime = json['endTime'] as String?, data = (json['data'] as List?) ?.map((e) => DeviceEvent.fromJson(e as Map)) .toList(); diff --git a/lib/features/devices/model/group_one_gang_model.dart b/lib/features/devices/model/group_one_gang_model.dart new file mode 100644 index 0000000..419f127 --- /dev/null +++ b/lib/features/devices/model/group_one_gang_model.dart @@ -0,0 +1,11 @@ +class GroupOneGangModel { + final String deviceId; + final String deviceName; + bool firstSwitch; + + GroupOneGangModel({ + required this.deviceId, + required this.deviceName, + required this.firstSwitch, + }); +} diff --git a/lib/features/devices/model/groupTwoGangModel.dart b/lib/features/devices/model/group_two_gang_model.dart similarity index 100% rename from lib/features/devices/model/groupTwoGangModel.dart rename to lib/features/devices/model/group_two_gang_model.dart diff --git a/lib/features/devices/view/widgets/curtains/curtain_list.dart b/lib/features/devices/view/widgets/curtains/curtain_list.dart index bf3900d..4c66149 100644 --- a/lib/features/devices/view/widgets/curtains/curtain_list.dart +++ b/lib/features/devices/view/widgets/curtains/curtain_list.dart @@ -1,9 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; 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/universal_switch.dart'; -import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; class CurtainList extends StatelessWidget { diff --git a/lib/features/devices/view/widgets/curtains/curtain_view.dart b/lib/features/devices/view/widgets/curtains/curtain_view.dart index 153bce8..9f89aa2 100644 --- a/lib/features/devices/view/widgets/curtains/curtain_view.dart +++ b/lib/features/devices/view/widgets/curtains/curtain_view.dart @@ -20,16 +20,16 @@ class CurtainView extends StatelessWidget { child: BlocBuilder( builder: (context, state) { double curtainWidth = 270; - double blindHeight = 310; + // double blindHeight = 310; if (state is CurtainsOpening) { curtainWidth = state.curtainWidth; - blindHeight = state.blindHeight; + // blindHeight = state.blindHeight; } else if (state is CurtainsClosing) { curtainWidth = state.curtainWidth; - blindHeight = state.blindHeight; + // blindHeight = state.blindHeight; } else if (state is CurtainsPaused) { curtainWidth = state.curtainWidth; - blindHeight = state.blindHeight; + // blindHeight = state.blindHeight; } return DefaultScaffold( title: curtain.name, @@ -58,7 +58,8 @@ class CurtainView extends StatelessWidget { width: curtainWidth, child: Stack( children: List.generate( - 10, (index) { + 10, + (index) { double spacing = curtainWidth / 9; double leftMostPosition = index * spacing; return AnimatedPositioned( diff --git a/lib/features/devices/view/widgets/device_appbar.dart b/lib/features/devices/view/widgets/device_appbar.dart index 7de34d7..9640429 100644 --- a/lib/features/devices/view/widgets/device_appbar.dart +++ b/lib/features/devices/view/widgets/device_appbar.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart'; import 'package:syncrow_app/features/devices/view/widgets/popup_menu_widget.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; @@ -11,30 +10,33 @@ class DeviceAppbar extends StatelessWidget implements PreferredSizeWidget { final String deviceUuid; final double appBarHeight = 56.0; final void Function()? onPressed; - const DeviceAppbar({super.key, required this.deviceName, required this.deviceUuid,this.onPressed}); + const DeviceAppbar( + {super.key, required this.deviceName, required this.deviceUuid, this.onPressed}); @override Widget build(BuildContext context) { - return AppBar( + return AppBar( backgroundColor: Colors.transparent, centerTitle: true, title: BodyLarge( - text: deviceName ?? "", + text: deviceName, fontColor: ColorsManager.primaryColor, fontWeight: FontsManager.bold, ), actions: [ - IconButton(onPressed: () { - showPopupMenu(context: context, items: [ - PopupMenuItem( - onTap: () async { - HomeCubit.getInstance().updateDevice(deviceUuid); - }, - value: 'Update', - child: const Text('Update'), - ) - ]); - }, icon: Icon(Icons.edit)) + IconButton( + onPressed: () { + showPopupMenu(context: context, items: [ + PopupMenuItem( + onTap: () async { + HomeCubit.getInstance().updateDevice(deviceUuid); + }, + value: 'Update', + child: const Text('Update'), + ) + ]); + }, + icon: Icon(Icons.edit)) ], ); } 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 462e28c..6bb6d6f 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 @@ -4,7 +4,6 @@ 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'; @@ -16,24 +15,15 @@ class NotificationSettingsPage extends StatelessWidget { return DefaultScaffold( title: 'Notification Settings', child: BlocProvider( - create: (context) => - DoorSensorBloc(DSId: '')..add(const DoorSensorInitial()), + create: (context) => DoorSensorBloc(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()), + width: 50, height: 50, child: CircularProgressIndicator()), ) : Column( children: [ @@ -56,8 +46,9 @@ class NotificationSettingsPage extends StatelessWidget { child: CupertinoSwitch( value: doorSensorBloc.lowBattery, onChanged: (value) { - context.read().add( - ToggleLowBatteryEvent(value)); + context + .read() + .add(ToggleLowBatteryEvent(value)); }, applyTheme: true, )), @@ -79,9 +70,9 @@ class NotificationSettingsPage extends StatelessWidget { child: CupertinoSwitch( value: doorSensorBloc.closingReminder, onChanged: (value) { - context.read().add( - ToggleClosingReminderEvent( - value)); + context + .read() + .add(ToggleClosingReminderEvent(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 index 39635c8..11b5d34 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 @@ -35,8 +35,7 @@ class DoorRecordsScreen extends StatelessWidget { return DefaultScaffold( title: 'Records', child: BlocProvider( - create: (context) => - DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()), + create: (context) => DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()), child: BlocBuilder( builder: (context, state) { if (state is DoorSensorLoadingState) { @@ -49,12 +48,10 @@ class DoorRecordsScreen extends StatelessWidget { ); } - if (state is UpdateState && state.doorSensor != null) { + if (state is UpdateState) { final recordGroups = context.read().recordGroups; - if (recordGroups == null || - recordGroups.data == null || - recordGroups.data!.isEmpty) { + if (recordGroups.data == null || recordGroups.data!.isEmpty) { return const Center(child: Text('No records available.')); } @@ -66,10 +63,8 @@ class DoorRecordsScreen extends StatelessWidget { // 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); + final String formattedDate = DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime); + final String formattedTime = DateFormat('HH:mm:ss').format(eventDateTime); return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -92,9 +87,7 @@ class DoorRecordsScreen extends StatelessWidget { record.value == 'true' ? Icons.radio_button_checked : Icons.radio_button_unchecked, - color: record.value == 'true' - ? Colors.blue - : Colors.grey, + color: record.value == 'true' ? Colors.blue : Colors.grey, ), title: Text( 'Status: ${record.value}', diff --git a/lib/features/devices/view/widgets/gateway/gateway_view.dart b/lib/features/devices/view/widgets/gateway/gateway_view.dart index 62ce1ed..0fa9831 100644 --- a/lib/features/devices/view/widgets/gateway/gateway_view.dart +++ b/lib/features/devices/view/widgets/gateway/gateway_view.dart @@ -8,12 +8,10 @@ import 'package:syncrow_app/features/devices/bloc/gateway_bloc/gateway_state.dar import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart'; import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart'; -import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; -import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; class GateWayView extends StatelessWidget { final DeviceModel gatewayObj; @@ -38,9 +36,10 @@ class GateWayView extends StatelessWidget { backgroundColor: ColorsManager.backgroundColor, extendBodyBehindAppBar: true, extendBody: true, - appBar:DeviceAppbar( - deviceName: 'Gateway', - deviceUuid: gatewayObj.uuid!,), + appBar: DeviceAppbar( + deviceName: 'Gateway', + deviceUuid: gatewayObj.uuid!, + ), body: Container( width: MediaQuery.sizeOf(context).width, height: MediaQuery.sizeOf(context).height, @@ -55,11 +54,11 @@ class GateWayView extends StatelessWidget { ), ), child: RefreshIndicator( - onRefresh:()async { - BlocProvider.of(context).add(GatewayInitial(gatewayId: gatewayObj.uuid ?? '')); - }, - child: ListView( - + onRefresh: () async { + BlocProvider.of(context) + .add(GatewayInitial(gatewayId: gatewayObj.uuid ?? '')); + }, + child: ListView( children: [ Container( height: MediaQuery.of(context).size.height, @@ -120,7 +119,8 @@ class GateWayView extends StatelessWidget { ) : Expanded( child: GridView.builder( - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 10, mainAxisSpacing: 10, @@ -141,8 +141,7 @@ class GateWayView extends StatelessWidget { ], ), ), - ) - )); + ))); })); } } diff --git a/lib/features/devices/view/widgets/lights/lights_view_list.dart b/lib/features/devices/view/widgets/lights/lights_view_list.dart index 98e9757..576a103 100644 --- a/lib/features/devices/view/widgets/lights/lights_view_list.dart +++ b/lib/features/devices/view/widgets/lights/lights_view_list.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -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/lights/lights_list.dart'; import 'package:syncrow_app/features/devices/view/widgets/universal_switch.dart'; diff --git a/lib/features/devices/view/widgets/offline_one_time_password_page.dart b/lib/features/devices/view/widgets/offline_one_time_password_page.dart index 6c560cd..baadcc8 100644 --- a/lib/features/devices/view/widgets/offline_one_time_password_page.dart +++ b/lib/features/devices/view/widgets/offline_one_time_password_page.dart @@ -1,5 +1,3 @@ - -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -7,7 +5,6 @@ import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_blo import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_event.dart'; import 'package:syncrow_app/features/devices/bloc/smart_door_bloc/smart_door_state.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/repeat_widget.dart'; -import 'package:syncrow_app/features/shared_widgets/default_button.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/door_lock_button.dart'; @@ -29,14 +26,12 @@ class OfflineOneTimePasswordPage extends StatelessWidget { create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!), child: BlocConsumer(listener: (context, state) { if (state is FailedState) { - CustomSnackBar.displaySnackBar( - state.errorMessage - ); + CustomSnackBar.displaySnackBar(state.errorMessage); } - if (state is IsRepeatState){ + if (state is IsRepeatState) { isRepeat = state.repeat; } - if (state is GeneratePasswordOneTimestate ){ + if (state is GeneratePasswordOneTimestate) { generated = state.generated; } }, builder: (context, state) { @@ -54,170 +49,173 @@ class OfflineOneTimePasswordPage extends StatelessWidget { onPressed: () { Navigator.of(context).pop(true); }, - icon: const Icon(Icons.arrow_back) - ), + icon: const Icon(Icons.arrow_back)), ), child: state is LoadingInitialState ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const BodyMedium( - text: 'Save the password immediately. The password is not displayed in the app.', - fontWeight: FontWeight.normal, - fontColor: ColorsManager.grayColor, - ), - const SizedBox( - height: 20, - ), - const BodyMedium( - text: '7-Digit Password', - fontWeight: FontWeight.normal, - fontColor: ColorsManager.grayColor, - ), - DefaultContainer( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children:smartDoorBloc.passwordController.text.isEmpty? - List.generate(10, (index) { - return const Padding( - padding: EdgeInsets.symmetric(horizontal: 4.0,vertical: 15), - child: Icon( - Icons.circle, - size: 20.0, - color: Colors.black, - ), - ); - }) :[ - Expanded( - child: Row( - children: [ - - Expanded( - child: BodyLarge( - style: const TextStyle( - color: ColorsManager.primaryColor, - fontWeight: FontWeight.bold, - letterSpacing: 8.0 , - fontSize: 25, - wordSpacing: 2), - textAlign: TextAlign.center, - text: smartDoorBloc.passwordController.text, - fontSize: 23, - ),), - - IconButton( - onPressed: () async { - await Clipboard.setData(ClipboardData( - text: smartDoorBloc.passwordController.text)); - }, - icon: const Icon(Icons.copy) - ), - ], - ), - ), - ], - )), - const SizedBox( - width: 10, - ), - - ], + const BodyMedium( + text: + 'Save the password immediately. The password is not displayed in the app.', + fontWeight: FontWeight.normal, + fontColor: ColorsManager.grayColor, ), - if(smartDoorBloc.passwordController.text.isNotEmpty) - Column( + const SizedBox( + height: 20, + ), + const BodyMedium( + text: '7-Digit Password', + fontWeight: FontWeight.normal, + fontColor: ColorsManager.grayColor, + ), + DefaultContainer( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), + child: Column( children: [ - const Divider( - color: ColorsManager.graysColor, - ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, children: [ - Expanded( - child: Container( - padding: const EdgeInsets.all(10.0), - child: const BodyMedium( - text: 'Password Name', - fontWeight: FontWeight.normal, - ), - ), + Flexible( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: smartDoorBloc.passwordController.text.isEmpty + ? List.generate(10, (index) { + return const Padding( + padding: EdgeInsets.symmetric( + horizontal: 4.0, vertical: 15), + child: Icon( + Icons.circle, + size: 20.0, + color: Colors.black, + ), + ); + }) + : [ + Expanded( + child: Row( + children: [ + Expanded( + child: BodyLarge( + style: const TextStyle( + color: ColorsManager.primaryColor, + fontWeight: FontWeight.bold, + letterSpacing: 8.0, + fontSize: 25, + wordSpacing: 2), + textAlign: TextAlign.center, + text: smartDoorBloc.passwordController.text, + fontSize: 23, + ), + ), + IconButton( + onPressed: () async { + await Clipboard.setData(ClipboardData( + text: smartDoorBloc + .passwordController.text)); + }, + icon: const Icon(Icons.copy)), + ], + ), + ), + ], + )), + const SizedBox( + width: 10, ), - SizedBox( - width: MediaQuery.of(context).size.width / 2.6, - child: TextFormField( - controller: BlocProvider.of(context).passwordNameController, - decoration: const InputDecoration( - hintText: 'Enter The Name', - hintStyle: TextStyle( - fontSize: 14, color: ColorsManager.textGray)), - )), ], ), - + if (smartDoorBloc.passwordController.text.isNotEmpty) + Column( + children: [ + const Divider( + color: ColorsManager.graysColor, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Container( + padding: const EdgeInsets.all(10.0), + child: const BodyMedium( + text: 'Password Name', + fontWeight: FontWeight.normal, + ), + ), + ), + SizedBox( + width: MediaQuery.of(context).size.width / 2.6, + child: TextFormField( + controller: BlocProvider.of(context) + .passwordNameController, + decoration: const InputDecoration( + hintText: 'Enter The Name', + hintStyle: TextStyle( + fontSize: 14, color: ColorsManager.textGray)), + )), + ], + ), + ], + ), ], ), + ), + const SizedBox( + height: 20, + ), + const BodyMedium( + textAlign: TextAlign.center, + text: + 'Save the password immediately. The password is not displayed in the app.', + fontWeight: FontWeight.normal, + fontColor: ColorsManager.grayColor, + ), + + // NameTimeWidget(type:type!), + const SizedBox( + height: 20, + ), + Center( + child: SizedBox( + width: MediaQuery.of(context).size.width / 1.5, + child: DoorLockButton( + isDone: generated, + isLoading: smartDoorBloc.isSavingPassword, + borderRadius: 30, + backgroundColor: ColorsManager.primaryColor, + onPressed: () async { + if (generated == false) { + smartDoorBloc + .add(GenerateAndSavePasswordOneTimeEvent(context: context)); + } else { + if (smartDoorBloc.passwordNameController.text.isNotEmpty) { + smartDoorBloc.add(RenamePasswordEvent()); + } + Navigator.of(context).pop(true); + } + }, + child: const BodyMedium( + text: 'Obtain Password', + fontWeight: FontWeight.bold, + fontColor: Colors.white, + ), + ), + ), + ), + const SizedBox( + height: 20, + ), + isRepeat ? const RepeatWidget() : const SizedBox(), + const SizedBox( + height: 40, + ) ], ), ), - const SizedBox( - height: 20, - ), - const BodyMedium( - textAlign: TextAlign.center, - text: 'Save the password immediately. The password is not displayed in the app.', - fontWeight: FontWeight.normal, - fontColor: ColorsManager.grayColor, - ), - - // NameTimeWidget(type:type!), - const SizedBox( - height: 20, - ), - Center( - child: SizedBox( - width: MediaQuery.of(context).size.width/1.5, - child: DoorLockButton( - isDone: generated, - isLoading: smartDoorBloc.isSavingPassword , - borderRadius: 30, - backgroundColor:ColorsManager.primaryColor , - onPressed: () async { - if(generated==false){ - smartDoorBloc.add(GenerateAndSavePasswordOneTimeEvent(context: context)); - }else{ - if(smartDoorBloc.passwordNameController.text.isNotEmpty){ - smartDoorBloc.add(RenamePasswordEvent()); - } - Navigator.of(context).pop(true); - } - }, - child: const BodyMedium( - text: 'Obtain Password', - fontWeight: FontWeight.bold, - fontColor: Colors.white, - ),), - ), - ), - const SizedBox( - height: 20, - ), - isRepeat? const RepeatWidget():const SizedBox(), - const SizedBox( - height: 40, - ) - ], - ), - ), ); })); } diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_Interface.dart b/lib/features/devices/view/widgets/one_gang/one_gang_Interface.dart index 636a730..28f2728 100644 --- a/lib/features/devices/view/widgets/one_gang/one_gang_Interface.dart +++ b/lib/features/devices/view/widgets/one_gang/one_gang_Interface.dart @@ -3,7 +3,6 @@ import 'package:flutter/services.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/device_appbar.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_screen.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_list.dart b/lib/features/devices/view/widgets/one_gang/one_gang_list.dart new file mode 100644 index 0000000..ba03339 --- /dev/null +++ b/lib/features/devices/view/widgets/one_gang/one_gang_list.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_event.dart'; +import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart'; +import 'package:syncrow_app/features/devices/model/group_one_gang_model.dart'; +import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; + +class OneGangList extends StatelessWidget { + const OneGangList({super.key, required this.oneGangList, required this.allSwitches}); + + final List oneGangList; + final bool allSwitches; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox(height: 10), + const BodySmall(text: 'All Lights'), + const SizedBox(height: 5), + DevicesDefaultSwitch( + switchValue: allSwitches, + action: () { + BlocProvider.of(context).add(GroupAllOnEvent()); + }, + secondAction: () { + BlocProvider.of(context).add(GroupAllOffEvent()); + }, + ), + ListView.builder( + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + padding: const EdgeInsets.all(0), + itemCount: oneGangList.length, + itemBuilder: (context, index) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + BodySmall(text: oneGangList[index].deviceName), + const SizedBox(height: 5), + DevicesDefaultSwitch( + switchValue: oneGangList[index].firstSwitch, + action: () { + BlocProvider.of(context).add(ChangeFirstSwitchStatusEvent( + value: oneGangList[index].firstSwitch, + deviceId: oneGangList[index].deviceId)); + }, + ), + ], + ); + }, + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart b/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart index 21aee6d..59ffb34 100644 --- a/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart +++ b/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart @@ -3,7 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart'; import 'package:syncrow_app/features/devices/bloc/one_gang_bloc/one_gang_state.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; +import 'package:syncrow_app/features/devices/model/group_one_gang_model.dart'; import 'package:syncrow_app/features/devices/model/one_gang_model.dart'; +import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_list.dart'; import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; @@ -20,10 +22,8 @@ class OneGangScreen extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => OneGangBloc( - switchCode: 'switch_1', - oneGangId : device?.uuid ?? '') - ..add(const InitialEvent(groupScreen:false)), + create: (context) => OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '') + ..add(const InitialEvent(groupScreen: false)), child: BlocBuilder( builder: (context, state) { OneGangModel oneGangModel = OneGangModel( @@ -31,141 +31,149 @@ class OneGangScreen extends StatelessWidget { firstCountDown: 0, ); + List groupOneGangModel = []; + bool allSwitchesOn = false; + if (state is LoadingNewSate) { oneGangModel = state.oneGangModel; } else if (state is UpdateState) { oneGangModel = state.oneGangModel; + } else if (state is UpdateGroupState) { + groupOneGangModel = state.oneGangList; + allSwitchesOn = state.allSwitches; } - return state is LoadingInitialState ? - const Center( - child: - DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), - ): - RefreshIndicator( - onRefresh: () async { - BlocProvider.of(context) - .add(InitialEvent(groupScreen: device != null ? false : true)); - }, - child: ListView( - children: [ - SizedBox( - height: MediaQuery.of(context).size.height, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - const Expanded(child: SizedBox.shrink()), - Expanded( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Column( + return state is LoadingInitialState + ? const Center( + child: + DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), + ) + : device == null + ? OneGangList(oneGangList: groupOneGangModel, allSwitches: allSwitchesOn) + : RefreshIndicator( + onRefresh: () async { + BlocProvider.of(context) + .add(InitialEvent(groupScreen: device != null ? false : true)); + }, + child: ListView( + children: [ + SizedBox( + height: MediaQuery.of(context).size.height, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - GangSwitch( - threeGangSwitch: device!, - value: oneGangModel.firstSwitch, - action: () { - BlocProvider.of(context).add( - ChangeFirstSwitchStatusEvent( - value: oneGangModel.firstSwitch)); - }, - ), - const SizedBox(height: 20), - const SizedBox( - width: 70, - child: BodySmall( - text:" Entrance Light", - fontColor: ColorsManager.textPrimaryColor, - textAlign: TextAlign.center, - ), - ), - ], - ), - ], - ), - ), - Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox( - width: 20, - ), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Card( - elevation: 3, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), - ), - child: GestureDetector( - onTap: () { - Navigator.push( - context, - PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => TimerScheduleScreen( - switchCode:'switch_1' , - device: device!, - deviceCode: 'countdown_1', - ))); - }, - child: Stack( - alignment: Alignment.center, - children: [ - Container( - width: 60, - height: 60, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), + const Expanded(child: SizedBox.shrink()), + Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Column( + children: [ + GangSwitch( + threeGangSwitch: device!, + value: oneGangModel.firstSwitch, + action: () { + BlocProvider.of(context).add( + ChangeFirstSwitchStatusEvent( + value: oneGangModel.firstSwitch)); + }, ), - ), - Container( - width: 40, - height: 40, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - child: Center( - child: Icon( - Icons.access_time, - color: - ColorsManager.primaryColorWithOpacity, - size: 25, + const SizedBox(height: 20), + const SizedBox( + width: 70, + child: BodySmall( + text: " Entrance Light", + fontColor: ColorsManager.textPrimaryColor, + textAlign: TextAlign.center, ), ), - ), - ], - ), + ], + ), + ], ), ), - const SizedBox(height: 10), - BodySmall( - text: "Timer", - style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox( + width: 20, + ), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(100), + ), + child: GestureDetector( + onTap: () { + Navigator.push( + context, + PageRouteBuilder( + pageBuilder: + (context, animation1, animation2) => + TimerScheduleScreen( + switchCode: 'switch_1', + device: device!, + deviceCode: 'countdown_1', + ))); + }, + child: Stack( + alignment: Alignment.center, + children: [ + Container( + width: 60, + height: 60, + decoration: BoxDecoration( + color: Colors.grey[300], + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + child: Center( + child: Icon( + Icons.access_time, + color: + ColorsManager.primaryColorWithOpacity, + size: 25, + ), + ), + ), + ], + ), + ), + ), + const SizedBox(height: 10), + BodySmall( + text: "Timer", + style: context.bodyMedium.copyWith( + color: ColorsManager.textPrimaryColor, + ), + ), + ], + ), + ], ), ), + Expanded(child: SizedBox()) ], ), - - ], - ), + ), + ], ), - Expanded(child: SizedBox()) - ], - ), - ), - ], - ), - ); + ); }, ), ); - } } diff --git a/lib/features/devices/view/widgets/room_page.dart b/lib/features/devices/view/widgets/room_page.dart index 68b2ac1..ce2028a 100644 --- a/lib/features/devices/view/widgets/room_page.dart +++ b/lib/features/devices/view/widgets/room_page.dart @@ -1,6 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/features/devices/model/room_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/room_page_switch.dart'; diff --git a/lib/features/devices/view/widgets/smart_door/create_temporary_password.dart b/lib/features/devices/view/widgets/smart_door/create_temporary_password.dart index 7d2b807..efeeda3 100644 --- a/lib/features/devices/view/widgets/smart_door/create_temporary_password.dart +++ b/lib/features/devices/view/widgets/smart_door/create_temporary_password.dart @@ -23,7 +23,7 @@ class CreateTemporaryPassword extends StatelessWidget { @override Widget build(BuildContext context) { bool isRepeat = false; - bool generated = false; + // bool generated = false; return BlocProvider( create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!), child: BlocConsumer(listener: (context, state) { @@ -35,11 +35,11 @@ class CreateTemporaryPassword extends StatelessWidget { ), ); } - if (state is IsRepeatState){ + if (state is IsRepeatState) { isRepeat = state.repeat; } - if (state is GeneratePasswordOneTimestate ){ - generated = state.generated; + if (state is GeneratePasswordOneTimestate) { + // generated = state.generated; } }, builder: (context, state) { final smartDoorBloc = BlocProvider.of(context); @@ -56,141 +56,142 @@ class CreateTemporaryPassword extends StatelessWidget { onPressed: () { Navigator.of(context).pop(true); }, - icon: const Icon(Icons.arrow_back) - ), - actions: - type == 'Online Password'?[ - TextButton( - onPressed: () { - smartDoorBloc.add(SavePasswordEvent(context: context)); - }, - child: const Text('Save') - ) - ]:null, + icon: const Icon(Icons.arrow_back)), + actions: type == 'Online Password' + ? [ + TextButton( + onPressed: () { + smartDoorBloc.add(SavePasswordEvent(context: context)); + }, + child: const Text('Save')) + ] + : null, ), child: state is LoadingInitialState ? const Center(child: CircularProgressIndicator()) : SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const BodyMedium( - text: 'Save the password immediately. The password is not displayed in the app.', - fontWeight: FontWeight.normal, - fontColor: ColorsManager.grayColor, - ), - const SizedBox( - height: 20, - ), - const BodyMedium( - text: '7-Digit Password', - fontWeight: FontWeight.normal, - fontColor: ColorsManager.grayColor, - ), - DefaultContainer( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: type == 'Online Password'?0:25), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.max, - children: [ - Flexible( - flex: 2, - child: PinCodeTextField( - onCompleted: (value) { - if (value.split('').every((char) => char == '1')) { - smartDoorBloc.passwordController.clear(); - CustomSnackBar.displaySnackBar('All characters cannot be 1.'); - } - }, - autoDisposeControllers: false, - keyboardType: TextInputType.phone, - length: 7, - // enabled:type == 'Online Password'? true:false, - obscureText: false, - animationType: AnimationType.fade, - pinTheme: PinTheme( - shape: PinCodeFieldShape.underline, - fieldHeight: 45, - fieldWidth: 20, - activeFillColor: Colors.white, - disabledColor: Colors.grey, - activeColor: Colors.grey, - errorBorderColor: Colors.grey, - inactiveColor: Colors.grey, - inactiveFillColor: Colors.grey, - selectedColor: Colors.grey), - animationDuration: const Duration(milliseconds: 300), - backgroundColor: Colors.white, - enableActiveFill: false, - controller: smartDoorBloc.passwordController, - appContext: context, - )), - const SizedBox( - width: 10, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const BodyMedium( + text: + 'Save the password immediately. The password is not displayed in the app.', + fontWeight: FontWeight.normal, + fontColor: ColorsManager.grayColor, + ), + const SizedBox( + height: 20, + ), + const BodyMedium( + text: '7-Digit Password', + fontWeight: FontWeight.normal, + fontColor: ColorsManager.grayColor, + ), + DefaultContainer( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: type == 'Online Password' ? 0 : 25), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + flex: 2, + child: PinCodeTextField( + onCompleted: (value) { + if (value.split('').every((char) => char == '1')) { + smartDoorBloc.passwordController.clear(); + CustomSnackBar.displaySnackBar( + 'All characters cannot be 1.'); + } + }, + autoDisposeControllers: false, + keyboardType: TextInputType.phone, + length: 7, + // enabled:type == 'Online Password'? true:false, + obscureText: false, + animationType: AnimationType.fade, + pinTheme: PinTheme( + shape: PinCodeFieldShape.underline, + fieldHeight: 45, + fieldWidth: 20, + activeFillColor: Colors.white, + disabledColor: Colors.grey, + activeColor: Colors.grey, + errorBorderColor: Colors.grey, + inactiveColor: Colors.grey, + inactiveFillColor: Colors.grey, + selectedColor: Colors.grey), + animationDuration: const Duration(milliseconds: 300), + backgroundColor: Colors.white, + enableActiveFill: false, + controller: smartDoorBloc.passwordController, + appContext: context, + )), + const SizedBox( + width: 10, + ), + if (type == 'Online Password') + Flexible( + child: InkWell( + onTap: () { + smartDoorBloc.add(GeneratePasswordEvent()); + }, + child: const BodyMedium( + text: 'Generate Randomly', + fontWeight: FontWeight.bold, + fontColor: ColorsManager.primaryColor, + )), + ) + ], + ), ), - if(type == 'Online Password') - Flexible( - child: InkWell( - onTap: () { - smartDoorBloc.add(GeneratePasswordEvent()); + ), + if (smartDoorBloc.passwordController.text.isNotEmpty) + TextButton( + onPressed: () async { + await Clipboard.setData( + ClipboardData(text: smartDoorBloc.passwordController.text)); + }, + child: const Text('Copy')), + const SizedBox( + height: 20, + ), + NameTimeWidget(), + const SizedBox( + height: 20, + ), + DefaultContainer( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const BodyMedium( + text: 'Repeat', + fontWeight: FontWeight.normal, + ), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: smartDoorBloc.repeat, + onChanged: (value) { + smartDoorBloc.add(ToggleRepeatEvent()); }, - child: const BodyMedium( - text: 'Generate Randomly', - fontWeight: FontWeight.bold, - fontColor: ColorsManager.primaryColor, - )), - ) - ], - ), + applyTheme: true, + )), + ), + ), + const SizedBox( + height: 20, + ), + isRepeat ? const RepeatWidget() : const SizedBox(), + const SizedBox( + height: 40, + ) + ], ), ), - if(smartDoorBloc.passwordController.text.isNotEmpty) - TextButton( - onPressed: () async { - await Clipboard.setData(ClipboardData( - text: smartDoorBloc.passwordController.text)); - }, - child: const Text('Copy') - ), - const SizedBox( - height: 20, - ), - NameTimeWidget(), - const SizedBox( - height: 20, - ), - DefaultContainer( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: const BodyMedium( - text: 'Repeat', - fontWeight: FontWeight.normal, - ), - trailing: Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: smartDoorBloc.repeat, - onChanged: (value) { - smartDoorBloc.add(ToggleRepeatEvent()); - }, - applyTheme: true, - )), - ), - ) , - const SizedBox( - height: 20, - ), - isRepeat? const RepeatWidget():const SizedBox(), - const SizedBox( - height: 40, - ) - ], - ), - ), ); })); } diff --git a/lib/features/devices/view/widgets/smart_door/door_dialog.dart b/lib/features/devices/view/widgets/smart_door/door_dialog.dart index b1a672d..db95566 100644 --- a/lib/features/devices/view/widgets/smart_door/door_dialog.dart +++ b/lib/features/devices/view/widgets/smart_door/door_dialog.dart @@ -31,16 +31,18 @@ class DoorDialogState extends State { @override Widget build(BuildContext context) { - final effectiveTime = widget.temporaryPassword?.effectiveTime ??int.parse( widget.offline?.gmtStart); - final invalidTime = widget.temporaryPassword?.invalidTime ?? int.parse(widget.offline?.gmtExpired); + final effectiveTime = + widget.temporaryPassword?.effectiveTime ?? int.parse(widget.offline?.gmtStart); + final invalidTime = + widget.temporaryPassword?.invalidTime ?? int.parse(widget.offline?.gmtExpired); final DateTime effectiveDateTime = - DateTime.fromMillisecondsSinceEpoch(effectiveTime! * 1000, isUtc: false); + DateTime.fromMillisecondsSinceEpoch(effectiveTime * 1000, isUtc: false); String formattedDateEffectiveTime = DateFormat('yyyy-MM-dd').format(effectiveDateTime); String formattedTimeEffectiveTime = DateFormat('hh:mm a').format(effectiveDateTime); final DateTime expiredDateTime = - DateTime.fromMillisecondsSinceEpoch(invalidTime! * 1000, isUtc: false); + DateTime.fromMillisecondsSinceEpoch(invalidTime * 1000, isUtc: false); String formattedDateExpiredDateTime = DateFormat('yyyy-MM-dd').format(expiredDateTime); String formattedTimeExpiredDateTime = DateFormat('hh:mm a').format(expiredDateTime); return Dialog( @@ -116,60 +118,59 @@ class DoorDialogState extends State { width: double.infinity, color: ColorsManager.greyColor, ), - widget.temporaryPassword?.effectiveTime!=null? - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - InkWell( - onTap: () { - Navigator.pop(context); - }, - child: Center( - child: BodyMedium( - text: 'Cancel', - style: context.bodyMedium.copyWith(color: ColorsManager.greyColor), - ), - ), - ), - Container( - height: 50, - width: 1, - color: ColorsManager.greyColor, - ), - InkWell( - onTap: () { - Navigator.pop(context, 'delete'); - }, - child: Center( - child: BodyMedium( - text: 'Delete Password', - style: context.bodyMedium.copyWith(color: ColorsManager.primaryColorWithOpacity), - ), - ), - ), - ], - ): - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Container( - height: 50, - child: InkWell( - onTap: () { - Navigator.pop(context); - }, - child: Center( - child: BodyMedium( - text: 'Cancel', - style: context.bodyMedium.copyWith(color: ColorsManager.greyColor), + widget.temporaryPassword?.effectiveTime != null + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Center( + child: BodyMedium( + text: 'Cancel', + style: context.bodyMedium.copyWith(color: ColorsManager.greyColor), + ), + ), ), - ), - ), - - ), - - ], - ) + Container( + height: 50, + width: 1, + color: ColorsManager.greyColor, + ), + InkWell( + onTap: () { + Navigator.pop(context, 'delete'); + }, + child: Center( + child: BodyMedium( + text: 'Delete Password', + style: context.bodyMedium + .copyWith(color: ColorsManager.primaryColorWithOpacity), + ), + ), + ), + ], + ) + : Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + height: 50, + child: InkWell( + onTap: () { + Navigator.pop(context); + }, + child: Center( + child: BodyMedium( + text: 'Cancel', + style: context.bodyMedium.copyWith(color: ColorsManager.greyColor), + ), + ), + ), + ), + ], + ) ], ), ), diff --git a/lib/features/devices/view/widgets/smart_door/door_grid.dart b/lib/features/devices/view/widgets/smart_door/door_grid.dart index fc5c290..a37be12 100644 --- a/lib/features/devices/view/widgets/smart_door/door_grid.dart +++ b/lib/features/devices/view/widgets/smart_door/door_grid.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/members_management_view.dart'; import 'package:syncrow_app/features/devices/view/widgets/smart_door/smart_linkage_view.dart'; @@ -10,9 +9,8 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart import 'package:syncrow_app/generated/assets.dart'; class DoorLockGrid extends StatelessWidget { - String uuid; - DoorLockGrid({ - super.key,required this.uuid}); + final String uuid; + const DoorLockGrid({super.key, required this.uuid}); @override Widget build(BuildContext context) { @@ -67,24 +65,24 @@ class DoorLockGrid extends StatelessWidget { } List> doorLockButtons({val}) => [ - { - 'title': 'Unlocking Records', - 'image': Assets.assetsIconsDoorlockAssetsUnlockingRecords, - 'page': const UnlockingRecordsView(), - }, - { - 'title': 'Members Management', - 'image': Assets.assetsIconsDoorlockAssetsMembersManagement, - 'page': const MembersManagementView(), - }, - { - 'title': 'Temporary Password', - 'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword, - 'page': TemporaryPasswordPage(deviceId:val) , - }, - { - 'title': 'Smart Linkage', - 'image': Assets.assetsIconsDoorlockAssetsSmartLinkage, - 'page': const SmartLinkgeView() - }, -]; + { + 'title': 'Unlocking Records', + 'image': Assets.assetsIconsDoorlockAssetsUnlockingRecords, + 'page': const UnlockingRecordsView(), + }, + { + 'title': 'Members Management', + 'image': Assets.assetsIconsDoorlockAssetsMembersManagement, + 'page': const MembersManagementView(), + }, + { + 'title': 'Temporary Password', + 'image': Assets.assetsIconsDoorlockAssetsTemporaryPassword, + 'page': TemporaryPasswordPage(deviceId: val), + }, + { + 'title': 'Smart Linkage', + 'image': Assets.assetsIconsDoorlockAssetsSmartLinkage, + 'page': const SmartLinkgeView() + }, + ]; diff --git a/lib/features/devices/view/widgets/smart_door/onetime_password_page.dart b/lib/features/devices/view/widgets/smart_door/onetime_password_page.dart index ba54fc5..a5f1d62 100644 --- a/lib/features/devices/view/widgets/smart_door/onetime_password_page.dart +++ b/lib/features/devices/view/widgets/smart_door/onetime_password_page.dart @@ -14,98 +14,103 @@ import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; class OnetimePasswordPage extends StatelessWidget { final String? deviceId; - const OnetimePasswordPage({super.key, this.deviceId,}); + const OnetimePasswordPage({ + super.key, + this.deviceId, + }); @override Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialOneTimePassword( )), - child: BlocConsumer( - listener: (context, state) { - if (state is FailedState) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(state.errorMessage), - backgroundColor: Colors.red, - ), - ); - } - }, - builder: (context, state) { - final smartDoorBloc = BlocProvider.of(context); - return DefaultScaffold( - title: 'Passwords', - actions: [ - IconButton( - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => OfflineOneTimePasswordPage(deviceId: deviceId, ) - )).then((result) { - if(result!=null){ - smartDoorBloc.add(InitialOneTimePassword()); - smartDoorBloc.add(InitialOneTimePassword()); - } - }); - }, - icon: const Icon(Icons.add) - ) - ], - child: Builder( - builder: (context) { - return state is LoadingInitialState - ? const Center(child: CircularProgressIndicator()) - : Center( - child: smartDoorBloc.oneTimePasswords!.isNotEmpty - ? ListView.builder( - itemCount: smartDoorBloc.oneTimePasswords!.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.all(5.0), - child: DefaultContainer( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon), - title: BodyMedium( - text: 'Password Name: ${smartDoorBloc.oneTimePasswords![index].pwdName}', - fontWeight: FontWeight.normal, - ), - onTap: () async { - final result = await showDialog( - context: context, - builder: (context) { - return DoorDialog( - title: 'Password Information', - offline: smartDoorBloc.oneTimePasswords![index], - ); - }, - ); - - }, - trailing: const Icon( - Icons.arrow_forward_ios, - color: ColorsManager.greyColor, - size: 15, - ), - ), - ), - ); - }, - ) : Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset(Assets.noValidPasswords), - const SizedBox( - height: 10, - ), - const BodyMedium(text: 'No Valid Passwords') - ], - ), - ); + create: (BuildContext context) => + SmartDoorBloc(deviceId: deviceId!)..add(InitialOneTimePassword()), + child: BlocConsumer(listener: (context, state) { + if (state is FailedState) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(state.errorMessage), + backgroundColor: Colors.red, + ), + ); + } + }, builder: (context, state) { + final smartDoorBloc = BlocProvider.of(context); + return DefaultScaffold( + title: 'Passwords', + actions: [ + IconButton( + onPressed: () { + Navigator.of(context) + .push(MaterialPageRoute( + builder: (context) => OfflineOneTimePasswordPage( + deviceId: deviceId, + ))) + .then((result) { + if (result != null) { + smartDoorBloc.add(InitialOneTimePassword()); + smartDoorBloc.add(InitialOneTimePassword()); + } + }); }, - )); - }) - ); + icon: const Icon(Icons.add)) + ], + child: Builder( + builder: (context) { + return state is LoadingInitialState + ? const Center(child: CircularProgressIndicator()) + : Center( + child: smartDoorBloc.oneTimePasswords!.isNotEmpty + ? ListView.builder( + itemCount: smartDoorBloc.oneTimePasswords!.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.all(5.0), + child: DefaultContainer( + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 10), + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon), + title: BodyMedium( + text: + 'Password Name: ${smartDoorBloc.oneTimePasswords![index].pwdName}', + fontWeight: FontWeight.normal, + ), + onTap: () async { + await showDialog( + context: context, + builder: (context) { + return DoorDialog( + title: 'Password Information', + offline: smartDoorBloc.oneTimePasswords![index], + ); + }, + ); + }, + trailing: const Icon( + Icons.arrow_forward_ios, + color: ColorsManager.greyColor, + size: 15, + ), + ), + ), + ); + }, + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset(Assets.noValidPasswords), + const SizedBox( + height: 10, + ), + const BodyMedium(text: 'No Valid Passwords') + ], + ), + ); + }, + )); + })); } } diff --git a/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart b/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart index fce92b9..b07c192 100644 --- a/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart +++ b/lib/features/devices/view/widgets/smart_door/timelimited_password_page.dart @@ -19,87 +19,88 @@ class TimeLimitedPasswordPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (BuildContext context) => SmartDoorBloc(deviceId: deviceId!)..add(InitialTimeLimitPassword()), - child: BlocConsumer( - listener: (context, state) { - if (state is FailedState) { - CustomSnackBar.displaySnackBar( - state.errorMessage - ); - } - }, - builder: (context, state) { - final smartDoorBloc = BlocProvider.of(context); - return DefaultScaffold( - title: 'Passwords', - actions: [ - IconButton( - onPressed: () { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => CreateOfflineTimeLimitPasswordPage(deviceId: deviceId,) - )).then((result) { - smartDoorBloc.add(InitialTimeLimitPassword()); - smartDoorBloc.add(InitialTimeLimitPassword()); - }); - }, - icon: const Icon(Icons.add) - ) - ], - child: Builder( - builder: (context) { - return state is LoadingInitialState - ? const Center(child: CircularProgressIndicator()) - : Center( - child: smartDoorBloc.timeLimitPasswords!.isNotEmpty - ? ListView.builder( - itemCount: smartDoorBloc.timeLimitPasswords!.length, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.all(5.0), - child: DefaultContainer( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10), - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon), - title: BodyMedium( - text: 'Password Name: ${smartDoorBloc.timeLimitPasswords![index].pwdName}', - fontWeight: FontWeight.normal, - ), - onTap: () async { - final result = await showDialog( - context: context, - builder: (context) { - return DoorDialog( - title: 'Password Information', - offline: smartDoorBloc.timeLimitPasswords![index], - ); - }, + create: (BuildContext context) => + SmartDoorBloc(deviceId: deviceId!)..add(InitialTimeLimitPassword()), + child: BlocConsumer(listener: (context, state) { + if (state is FailedState) { + CustomSnackBar.displaySnackBar(state.errorMessage); + } + }, builder: (context, state) { + final smartDoorBloc = BlocProvider.of(context); + return DefaultScaffold( + title: 'Passwords', + actions: [ + IconButton( + onPressed: () { + Navigator.of(context) + .push(MaterialPageRoute( + builder: (context) => CreateOfflineTimeLimitPasswordPage( + deviceId: deviceId, + ))) + .then((result) { + smartDoorBloc.add(InitialTimeLimitPassword()); + smartDoorBloc.add(InitialTimeLimitPassword()); + }); + }, + icon: const Icon(Icons.add)) + ], + child: Builder( + builder: (context) { + return state is LoadingInitialState + ? const Center(child: CircularProgressIndicator()) + : Center( + child: smartDoorBloc.timeLimitPasswords!.isNotEmpty + ? ListView.builder( + itemCount: smartDoorBloc.timeLimitPasswords!.length, + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.all(5.0), + child: DefaultContainer( + padding: const EdgeInsets.symmetric( + horizontal: 15, vertical: 10), + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: SvgPicture.asset(Assets.timeLimitedPasswordIcon), + title: BodyMedium( + text: + 'Password Name: ${smartDoorBloc.timeLimitPasswords![index].pwdName}', + fontWeight: FontWeight.normal, + ), + onTap: () async { + await showDialog( + context: context, + builder: (context) { + return DoorDialog( + title: 'Password Information', + offline: smartDoorBloc.timeLimitPasswords![index], + ); + }, + ); + }, + trailing: const Icon( + Icons.arrow_forward_ios, + color: ColorsManager.greyColor, + size: 15, + ), + ), + ), ); }, - trailing: const Icon( - Icons.arrow_forward_ios, - color: ColorsManager.greyColor, - size: 15, - ), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SvgPicture.asset(Assets.noValidPasswords), + const SizedBox( + height: 10, + ), + const BodyMedium(text: 'No Valid Passwords') + ], ), - ), - ); - }, - ) : Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset(Assets.noValidPasswords), - const SizedBox( - height: 10, - ), - const BodyMedium(text: 'No Valid Passwords') - ], - ), - ); - }, - )); - }) - ); + ); + }, + )); + })); } } diff --git a/lib/features/devices/view/widgets/three_gang/gang_switch.dart b/lib/features/devices/view/widgets/three_gang/gang_switch.dart index 8b5dc55..61afbc0 100644 --- a/lib/features/devices/view/widgets/three_gang/gang_switch.dart +++ b/lib/features/devices/view/widgets/three_gang/gang_switch.dart @@ -18,7 +18,7 @@ class GangSwitch extends StatelessWidget { @override Widget build(BuildContext context) { return InkWell( - overlayColor: MaterialStateProperty.all(Colors.transparent), + overlayColor: WidgetStateProperty.all(Colors.transparent), onTap: () { action(); // var tempControl = DeviceControlModel( diff --git a/lib/features/devices/view/widgets/three_gang/timer_screen.dart b/lib/features/devices/view/widgets/three_gang/timer_screen.dart index d15d4b1..23dcdf5 100644 --- a/lib/features/devices/view/widgets/three_gang/timer_screen.dart +++ b/lib/features/devices/view/widgets/three_gang/timer_screen.dart @@ -8,7 +8,6 @@ import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_eve import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_state.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; import 'package:syncrow_app/features/shared_widgets/create_schedule.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/schedule_list.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; @@ -18,17 +17,12 @@ import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; - - class TimerScheduleScreen extends StatelessWidget { final DeviceModel device; final String deviceCode; final String switchCode; const TimerScheduleScreen( - {required this.device, - required this.deviceCode, - required this.switchCode, - super.key}); + {required this.device, required this.deviceCode, required this.switchCode, super.key}); @override Widget build(BuildContext context) { @@ -38,8 +32,7 @@ class TimerScheduleScreen extends StatelessWidget { statusBarIconBrightness: Brightness.light, ), child: BlocProvider( - create: (context) => - ThreeGangBloc(switchCode: switchCode, threeGangId: device.uuid ?? '') + create: (context) => ThreeGangBloc(switchCode: switchCode, threeGangId: device.uuid ?? '') ..add(GetCounterEvent(deviceCode: deviceCode)) ..add(GetScheduleEvent()), child: BlocBuilder( @@ -66,7 +59,7 @@ class TimerScheduleScreen extends StatelessWidget { }, child: DefaultTabController( length: 2, - child: DefaultScaffold( + child: DefaultScaffold( appBar: AppBar( backgroundColor: Colors.transparent, centerTitle: true, @@ -76,177 +69,175 @@ class TimerScheduleScreen extends StatelessWidget { fontWeight: FontsManager.bold, ), actions: [ - threeGangBloc.createSchedule == true ? - TextButton( - onPressed: () { - threeGangBloc.add(ThreeGangSave()); - }, - child: const Text('Save') - ) : - threeGangBloc.selectedTabIndex==1? IconButton( - onPressed: () { - threeGangBloc.toggleCreateSchedule(); - }, - icon: const Icon(Icons.add), - ):SizedBox(), + threeGangBloc.createSchedule == true + ? TextButton( + onPressed: () { + threeGangBloc.add(ThreeGangSave()); + }, + child: const Text('Save')) + : threeGangBloc.selectedTabIndex == 1 + ? IconButton( + onPressed: () { + threeGangBloc.toggleCreateSchedule(); + }, + icon: const Icon(Icons.add), + ) + : SizedBox(), ], ), - child: - state is LoadingInitialState? - const Center(child: CircularProgressIndicator()): - Column( - children: [ - Container( - width: MediaQuery.of(context).size.width, - decoration: const ShapeDecoration( - color: ColorsManager.onPrimaryColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(30)), - ), - ), - child: TabBar( - onTap: (value) { - if(value==0){ - if(threeGangBloc.createSchedule == true){ - threeGangBloc.toggleCreateSchedule(); - } - threeGangBloc.toggleSelectedIndex(0); - - }else{ - threeGangBloc.toggleSelectedIndex(1); - } - }, - indicatorColor: Colors.white, // Customize the indicator - dividerHeight: 0, - indicatorSize: TabBarIndicatorSize.tab, - indicator: const ShapeDecoration( - color: ColorsManager.slidingBlueColor, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.all(Radius.circular(20)), - ), - ), - tabs: [ - Tab( - child: Container( - padding: const EdgeInsets.symmetric( - vertical: 10), - child: BodySmall( - text: 'Countdown', - style: context.bodySmall.copyWith( - color: ColorsManager.blackColor, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - Tab( - child: Container( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - 'Schedule', - style: context.bodySmall.copyWith( - color: ColorsManager.blackColor, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - ], - ), - - ), - Expanded( - child: TabBarView( + child: state is LoadingInitialState + ? const Center(child: CircularProgressIndicator()) + : Column( children: [ - Center( - child: Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - countNum > 0 - ? BodyLarge( - text: _formatDuration(countNum), - fontColor: - ColorsManager.slidingBlueColor, - fontSize: 40, - ) - : CupertinoTimerPicker( - mode: CupertinoTimerPickerMode.hm, - onTimerDurationChanged: - (Duration newDuration) { - duration = newDuration; - }, - ), - GestureDetector( - onTap: () { - if (state is LoadingNewSate) { - return; - } - if (countNum > 0) { - threeGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: Duration.zero)); - } else if (duration != Duration.zero) { - threeGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: duration)); - } - }, - child: SvgPicture.asset(countNum > 0 - ? Assets.pauseIcon - : Assets.playIcon)), - ], + Container( + width: MediaQuery.of(context).size.width, + decoration: const ShapeDecoration( + color: ColorsManager.onPrimaryColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(30)), ), ), - ), - Column( - mainAxisAlignment:threeGangBloc.listSchedule.isNotEmpty? - MainAxisAlignment.start:MainAxisAlignment.center, - children: [ - SizedBox( - child: threeGangBloc.createSchedule == true ? - CreateSchedule( - onToggleChanged: (bool isOn) { - threeGangBloc.toggleSchedule = isOn; - }, - onDateTimeChanged: (DateTime dateTime) { - threeGangBloc.selectedTime=dateTime; - }, - days: threeGangBloc.days, - selectDays: (List selectedDays) { - threeGangBloc.selectedDays = selectedDays; - }, - ) - : - Padding( - padding: const EdgeInsets.only(top: 10), - child: ScheduleListView( - listSchedule: threeGangBloc.listSchedule, // Pass the schedule list here - onDismissed: (scheduleId) { - threeGangBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId); - threeGangBloc.add(DeleteScheduleEvent(id: scheduleId)); - }, - onToggleSchedule: (scheduleId, isEnabled) { - threeGangBloc.add(ToggleScheduleEvent( - id: scheduleId, - toggle: isEnabled, - )); - }, - ), + child: TabBar( + onTap: (value) { + if (value == 0) { + if (threeGangBloc.createSchedule == true) { + threeGangBloc.toggleCreateSchedule(); + } + threeGangBloc.toggleSelectedIndex(0); + } else { + threeGangBloc.toggleSelectedIndex(1); + } + }, + indicatorColor: Colors.white, // Customize the indicator + dividerHeight: 0, + indicatorSize: TabBarIndicatorSize.tab, + indicator: const ShapeDecoration( + color: ColorsManager.slidingBlueColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), ), ), - ], + tabs: [ + Tab( + child: Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: BodySmall( + text: 'Countdown', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + Tab( + child: Container( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + 'Schedule', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ), + Expanded( + child: TabBarView( + children: [ + Center( + child: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + countNum > 0 + ? BodyLarge( + text: _formatDuration(countNum), + fontColor: ColorsManager.slidingBlueColor, + fontSize: 40, + ) + : CupertinoTimerPicker( + mode: CupertinoTimerPickerMode.hm, + onTimerDurationChanged: + (Duration newDuration) { + duration = newDuration; + }, + ), + GestureDetector( + onTap: () { + if (state is LoadingNewSate) { + return; + } + if (countNum > 0) { + threeGangBloc.add(SetCounterValue( + deviceCode: deviceCode, + duration: Duration.zero)); + } else if (duration != Duration.zero) { + threeGangBloc.add(SetCounterValue( + deviceCode: deviceCode, + duration: duration)); + } + }, + child: SvgPicture.asset(countNum > 0 + ? Assets.pauseIcon + : Assets.playIcon)), + ], + ), + ), + ), + Column( + mainAxisAlignment: threeGangBloc.listSchedule.isNotEmpty + ? MainAxisAlignment.start + : MainAxisAlignment.center, + children: [ + SizedBox( + child: threeGangBloc.createSchedule == true + ? CreateSchedule( + onToggleChanged: (bool isOn) { + threeGangBloc.toggleSchedule = isOn; + }, + onDateTimeChanged: (DateTime dateTime) { + threeGangBloc.selectedTime = dateTime; + }, + days: threeGangBloc.days, + selectDays: (List selectedDays) { + threeGangBloc.selectedDays = selectedDays; + }, + ) + : Padding( + padding: const EdgeInsets.only(top: 10), + child: ScheduleListView( + listSchedule: threeGangBloc + .listSchedule, // Pass the schedule list here + onDismissed: (scheduleId) { + threeGangBloc.listSchedule.removeWhere( + (schedule) => + schedule.scheduleId == scheduleId); + threeGangBloc.add( + DeleteScheduleEvent(id: scheduleId)); + }, + onToggleSchedule: (scheduleId, isEnabled) { + threeGangBloc.add(ToggleScheduleEvent( + id: scheduleId, + toggle: isEnabled, + )); + }, + ), + ), + ), + ], + ), + ], + ), ), ], ), - ), - ], - ), - )) - ); + ))); }, ), ), diff --git a/lib/features/devices/view/widgets/two_gang/two_gang_list.dart b/lib/features/devices/view/widgets/two_gang/two_gang_list.dart index 065dd62..a36de97 100644 --- a/lib/features/devices/view/widgets/two_gang/two_gang_list.dart +++ b/lib/features/devices/view/widgets/two_gang/two_gang_list.dart @@ -1,10 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart'; -import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_event.dart'; -import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/three_gang_state.dart'; -import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; -import 'package:syncrow_app/features/devices/model/group_three_gang_model.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_event.dart'; +import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_state.dart'; +import 'package:syncrow_app/features/devices/model/group_two_gang_model.dart'; import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart'; @@ -16,7 +15,7 @@ class TwoGangList extends StatelessWidget { @override Widget build(BuildContext context) { - return BlocBuilder( + return BlocBuilder( builder: (context, state) { return SingleChildScrollView( child: Column( @@ -28,10 +27,10 @@ class TwoGangList extends StatelessWidget { DevicesDefaultSwitch( switchValue: allSwitches, action: () { - BlocProvider.of(context).add(GroupAllOnEvent()); + BlocProvider.of(context).add(GroupAllOnEvent()); }, secondAction: () { - BlocProvider.of(context).add(GroupAllOffEvent()); + BlocProvider.of(context).add(GroupAllOffEvent()); }, ), ListView.builder( @@ -44,30 +43,27 @@ class TwoGangList extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 10), - BodySmall(text: '${twoGangList[index].deviceName} beside light'), + BodySmall(text: twoGangList[index].deviceName), const SizedBox(height: 5), DevicesDefaultSwitch( switchValue: twoGangList[index].firstSwitch, action: () { - BlocProvider.of(context).add(ChangeFirstSwitchStatusEvent( + BlocProvider.of(context).add(ChangeFirstSwitchStatusEvent( value: twoGangList[index].firstSwitch, deviceId: twoGangList[index].deviceId)); }, ), const SizedBox(height: 10), - BodySmall(text: '${twoGangList[index].deviceName} ceiling light'), + BodySmall(text: twoGangList[index].deviceName), const SizedBox(height: 5), DevicesDefaultSwitch( switchValue: twoGangList[index].secondSwitch, action: () { - BlocProvider.of(context).add(ChangeSecondSwitchStatusEvent( + BlocProvider.of(context).add(ChangeSecondSwitchStatusEvent( value: twoGangList[index].secondSwitch, deviceId: twoGangList[index].deviceId)); }, ), - const SizedBox(height: 10), - BodySmall(text: '${twoGangList[index].deviceName} spotlight'), - const SizedBox(height: 5), ], ); }, diff --git a/lib/features/devices/view/widgets/two_gang/two_gang_screen.dart b/lib/features/devices/view/widgets/two_gang/two_gang_screen.dart index d332386..240a5ff 100644 --- a/lib/features/devices/view/widgets/two_gang/two_gang_screen.dart +++ b/lib/features/devices/view/widgets/two_gang/two_gang_screen.dart @@ -4,7 +4,7 @@ import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_bloc.da import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_event.dart'; import 'package:syncrow_app/features/devices/bloc/two_gang_bloc/two_gang_state.dart'; import 'package:syncrow_app/features/devices/model/device_model.dart'; -import 'package:syncrow_app/features/devices/model/groupTwoGangModel.dart'; +import 'package:syncrow_app/features/devices/model/group_two_gang_model.dart'; import 'package:syncrow_app/features/devices/model/two_gang_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart'; import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_list.dart'; @@ -22,18 +22,16 @@ class TwoGangScreen extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => TwoGangBloc( - switchCode: switchCode??'', - twoGangId: device?.uuid ?? '') + create: (context) => TwoGangBloc(switchCode: switchCode ?? '', twoGangId: device?.uuid ?? '') ..add(InitialEvent(groupScreen: device != null ? false : true)), child: BlocBuilder( builder: (context, state) { TwoGangModel twoGangModel = TwoGangModel( - firstSwitch: false, - secondSwitch: false, - firstCountDown: 0, - secondCountDown: 0, - ); + firstSwitch: false, + secondSwitch: false, + firstCountDown: 0, + secondCountDown: 0, + ); List groupTwoGangModel = []; bool allSwitchesOn = false; @@ -47,7 +45,9 @@ class TwoGangScreen extends StatelessWidget { } return state is LoadingInitialState ? const Center( - child: DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),) + child: + DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), + ) : device == null ? TwoGangList( twoGangList: groupTwoGangModel, @@ -116,7 +116,6 @@ class TwoGangScreen extends StatelessWidget { ), ], ), - ], ), ), diff --git a/lib/features/devices/view/widgets/wizard_page.dart b/lib/features/devices/view/widgets/wizard_page.dart index 6639321..fdddf05 100644 --- a/lib/features/devices/view/widgets/wizard_page.dart +++ b/lib/features/devices/view/widgets/wizard_page.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_app/features/devices/model/device_category_model.dart'; import 'package:syncrow_app/features/devices/view/widgets/ACs/acs_view.dart'; +import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart'; import 'package:syncrow_app/features/devices/view/widgets/three_gang/three_gang_interface.dart'; +import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/context_extension.dart'; @@ -39,6 +41,18 @@ class WizardPage extends StatelessWidget { pageBuilder: (context, animation1, animation2) => const ThreeGangInterface())); } + if (groupsList[index].name == '2G') { + Navigator.push( + context, + PageRouteBuilder( + pageBuilder: (context, animation1, animation2) => const TwoGangInterface())); + } + if (groupsList[index].name == '1G') { + Navigator.push( + context, + PageRouteBuilder( + pageBuilder: (context, animation1, animation2) => const OneGangInterface())); + } }, child: DefaultContainer( padding: const EdgeInsets.all(15), diff --git a/lib/features/shared_widgets/schedule_list.dart b/lib/features/shared_widgets/schedule_list.dart index 0b48f86..15e2b6e 100644 --- a/lib/features/shared_widgets/schedule_list.dart +++ b/lib/features/shared_widgets/schedule_list.dart @@ -1,16 +1,13 @@ - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/features/devices/model/schedule_model.dart'; -import 'package:syncrow_app/features/shared_widgets/default_button.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'empty_schedule.dart'; // for SVG icons - class ScheduleListView extends StatelessWidget { final List listSchedule; final Function(String) onDismissed; @@ -25,96 +22,93 @@ class ScheduleListView extends StatelessWidget { @override Widget build(BuildContext context) { return Center( - child: listSchedule.isNotEmpty - ? SizedBox( - child: ListView.builder( - shrinkWrap: true, - itemCount: listSchedule.length, - itemBuilder: (context, index) { - return Dismissible( - key: Key(listSchedule[index].scheduleId), - background: Container( - padding: const EdgeInsets.only(right: 10), - alignment: AlignmentDirectional.centerEnd, - decoration: const ShapeDecoration( - color: Color(0xFFFF0000), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), - ), - ), - child: Padding( - padding: const EdgeInsets.only(bottom: 10, right: 10), - child: SvgPicture.asset( - Assets.assetsDeleteIcon, - width: 20, - height: 22, - ), - ), - ), - direction: DismissDirection.endToStart, - onDismissed: (direction) { - - onDismissed(listSchedule[index].scheduleId); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Schedule removed')), - ); - }, - child: InkWell( - onTap: () { - - }, - child: DefaultContainer( - padding: const EdgeInsets.all(20), - height: MediaQuery.of(context).size.height / 6.4, - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BodyLarge( - text: listSchedule[index].time, - fontWeight: FontWeight.w500, - fontColor: Colors.black, - fontSize: 22, - ), - Text(listSchedule[index].days.join(' ')), - Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'), - ], - ), - ), - Expanded( - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: const BodyMedium( - text: '', - fontWeight: FontWeight.normal, + child: listSchedule.isNotEmpty + ? SizedBox( + child: ListView.builder( + shrinkWrap: true, + itemCount: listSchedule.length, + itemBuilder: (context, index) { + return Dismissible( + key: Key(listSchedule[index].scheduleId), + background: Container( + padding: const EdgeInsets.only(right: 10), + alignment: AlignmentDirectional.centerEnd, + decoration: const ShapeDecoration( + color: Color(0xFFFF0000), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), ), - trailing: Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: listSchedule[index].enable, - onChanged: (value) { - onToggleSchedule( - listSchedule[index].scheduleId, - value, - ); - }, - applyTheme: true, - ), + ), + child: Padding( + padding: const EdgeInsets.only(bottom: 10, right: 10), + child: SvgPicture.asset( + Assets.assetsDeleteIcon, + width: 20, + height: 22, ), ), ), - ], - ), + direction: DismissDirection.endToStart, + onDismissed: (direction) { + onDismissed(listSchedule[index].scheduleId); + + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Schedule removed')), + ); + }, + child: InkWell( + onTap: () {}, + child: DefaultContainer( + padding: const EdgeInsets.all(20), + height: MediaQuery.of(context).size.height / 6.4, + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BodyLarge( + text: listSchedule[index].time, + fontWeight: FontWeight.w500, + fontColor: Colors.black, + fontSize: 22, + ), + Text(listSchedule[index].days.join(' ')), + Text( + 'Function ${listSchedule[index].function.value ? "ON" : "OFF"}'), + ], + ), + ), + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const BodyMedium( + text: '', + fontWeight: FontWeight.normal, + ), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: listSchedule[index].enable, + onChanged: (value) { + onToggleSchedule( + listSchedule[index].scheduleId, + value, + ); + }, + applyTheme: true, + ), + ), + ), + ), + ], + ), + ), + ), + ); + }, ), - ), - ); - }, - ), - ) - : const EmptySchedule() - ); + ) + : const EmptySchedule()); } } diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index f8a8101..1d38fd0 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -72,8 +72,7 @@ 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; @@ -83,9 +82,7 @@ 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) @@ -110,8 +107,7 @@ 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) @@ -150,8 +146,7 @@ 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, @@ -173,8 +168,7 @@ 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; @@ -185,8 +179,7 @@ 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; @@ -197,8 +190,7 @@ 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; @@ -223,12 +215,10 @@ 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, @@ -239,8 +229,7 @@ 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; @@ -252,12 +241,10 @@ 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) { @@ -366,7 +353,7 @@ class DevicesAPI { required String endTime, }) async { // print( - // '---------${ApiEndpoints.reportLogs.replaceAll('{deviceUuid}', deviceUuid).replaceAll('{code}', code).replaceAll('{startTime}', startTime).replaceAll('{endTime}', endTime)}'); + // '---------${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) @@ -375,7 +362,6 @@ class DevicesAPI { .replaceAll('{endTime}', endTime), expectedResponseModel: (json) { return DeviceReport.fromJson(json); - return json; }, ); From 429009aefa19f35e3a6032b13cf256f22d01046c Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 23 Sep 2024 14:37:07 +0300 Subject: [PATCH 4/9] bug fixes 2 --- lib/features/auth/bloc/auth_cubit.dart | 1 - .../door_sensor_bloc/door_sensor_bloc.dart | 33 +- .../devices/model/device_report_model.dart | 6 +- .../door_sensor/door_records_screen.dart | 134 +++--- .../widgets/three_gang/schedule_screen.dart | 57 +-- .../view/widgets/three_gang/timer_screen.dart | 171 +++++--- .../widgets/two_gang/two_timer_screen.dart | 351 ++++++++-------- .../water_heater/circulate_list_view.dart | 176 ++++---- .../wh_timer_schedule_screen.dart | 383 +++++++++++------- .../shared_widgets/schedule_list.dart | 174 ++++---- lib/services/api/devices_api.dart | 38 +- 11 files changed, 863 insertions(+), 661 deletions(-) diff --git a/lib/features/auth/bloc/auth_cubit.dart b/lib/features/auth/bloc/auth_cubit.dart index 2952e70..276bfd8 100644 --- a/lib/features/auth/bloc/auth_cubit.dart +++ b/lib/features/auth/bloc/auth_cubit.dart @@ -8,7 +8,6 @@ import 'package:syncrow_app/features/auth/model/user_model.dart'; import 'package:syncrow_app/navigation/navigation_service.dart'; import 'package:syncrow_app/navigation/routing_constants.dart'; import 'package:syncrow_app/services/api/authentication_api.dart'; -import 'package:syncrow_app/services/api/profile_api.dart'; import 'package:syncrow_app/utils/helpers/shared_preferences_helper.dart'; import 'package:syncrow_app/utils/helpers/snack_bar.dart'; import 'package:syncrow_app/utils/resource_manager/strings_manager.dart'; 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 636edc7..213dbeb 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 @@ -16,7 +16,7 @@ class DoorSensorBloc extends Bloc { DoorSensorBloc({ required this.DSId, }) : super(const DoorSensorState()) { - on(_fetchWaterHeaterStatus); + on(_fetchStatus); on(fetchLogsForLastMonth); on(_toggleLowBattery); on(_toggleClosingReminder); @@ -26,9 +26,11 @@ class DoorSensorBloc extends Bloc { bool lowBattery = false; bool closingReminder = false; bool doorAlarm = false; - DoorSensorModel deviceStatus = DoorSensorModel(doorContactState: false, batteryPercentage: 0); + DoorSensorModel deviceStatus = + DoorSensorModel(doorContactState: false, batteryPercentage: 0); - void _fetchWaterHeaterStatus(DoorSensorInitial event, Emitter emit) async { + void _fetchStatus( + DoorSensorInitial event, Emitter emit) async { emit(DoorSensorLoadingState()); try { var response = await DevicesAPI.getDeviceStatus(DSId); @@ -49,7 +51,8 @@ class DoorSensorBloc extends Bloc { } // Toggle functions for each switch - void _toggleLowBattery(ToggleLowBatteryEvent event, Emitter emit) async { + void _toggleLowBattery( + ToggleLowBatteryEvent event, Emitter emit) async { emit(LoadingNewSate(doorSensor: deviceStatus)); try { lowBattery = event.isLowBatteryEnabled; @@ -90,7 +93,8 @@ class DoorSensorBloc extends Bloc { } } - void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter emit) async { + void _toggleDoorAlarm( + ToggleDoorAlarmEvent event, Emitter emit) async { emit(LoadingNewSate(doorSensor: deviceStatus)); try { doorAlarm = event.isDoorAlarmEnabled; @@ -110,9 +114,11 @@ class DoorSensorBloc extends Bloc { } } - DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []); + DeviceReport recordGroups = + DeviceReport(startTime: '0', endTime: '0', data: []); - Future fetchLogsForLastMonth(ReportLogsInitial event, Emitter emit) async { + Future fetchLogsForLastMonth( + ReportLogsInitial event, Emitter emit) async { // Get the current date and time DateTime now = DateTime.now(); @@ -123,15 +129,18 @@ class DoorSensorBloc extends Bloc { int startTime = lastMonth.millisecondsSinceEpoch; int endTime = now.millisecondsSinceEpoch; try { + emit(DoorSensorLoadingState()); 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', ); + print('response======${response}'); recordGroups = response; // Process response here - print(response); + emit(UpdateState(doorSensor: deviceStatus)); } on DioException catch (e) { final errorData = e.response!.data; String errorMessage = errorData['message']; @@ -142,14 +151,16 @@ class DoorSensorBloc extends Bloc { _listenToChanges() { try { - DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$DSId'); + 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; + Map usersMap = + event.snapshot.value as Map; List statusList = []; usersMap['status'].forEach((element) { diff --git a/lib/features/devices/model/device_report_model.dart b/lib/features/devices/model/device_report_model.dart index b73dc77..c640d81 100644 --- a/lib/features/devices/model/device_report_model.dart +++ b/lib/features/devices/model/device_report_model.dart @@ -1,7 +1,7 @@ class DeviceReport { - final String? deviceUuid; - final String? startTime; - final String? endTime; + final dynamic deviceUuid; + final dynamic startTime; + final dynamic endTime; final List? data; DeviceReport({ 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 11b5d34..9b4b961 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 @@ -4,27 +4,10 @@ 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/devices/model/device_report_model.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(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]; +import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; class DoorRecordsScreen extends StatelessWidget { final String DSId; @@ -35,36 +18,43 @@ class DoorRecordsScreen extends StatelessWidget { return DefaultScaffold( title: 'Records', child: BlocProvider( - create: (context) => DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()), + create: (context) => + DoorSensorBloc(DSId: DSId)..add(const ReportLogsInitial()), child: BlocBuilder( builder: (context, state) { + final doorSensorBloc = BlocProvider.of(context); + if (state is DoorSensorLoadingState) { - return const Center(child: CircularProgressIndicator()); - } - - if (state is DoorSensorFailedState) { - return Center( - child: Text('Failed to load data: ${state.errorMessage}'), + return const Center( + child: DefaultContainer( + width: 50, height: 50, child: CircularProgressIndicator()), ); - } + } else if (state is UpdateState) { + // Group records by formatted date + final Map> groupedRecords = {}; - if (state is UpdateState) { - final recordGroups = context.read().recordGroups; + // Iterate over the data list in DeviceReport + for (var record in doorSensorBloc.recordGroups.data!) { + final DateTime eventDateTime = + DateTime.fromMillisecondsSinceEpoch(record.eventTime!); + final String formattedDate = + DateFormat('EEEE, dd/MM/yyyy').format(eventDateTime); - if (recordGroups.data == null || recordGroups.data!.isEmpty) { - return const Center(child: Text('No records available.')); + // Group by formatted date + if (groupedRecords.containsKey(formattedDate)) { + groupedRecords[formattedDate]!.add(record); + } else { + groupedRecords[formattedDate] = [record]; + } } + // Build the ListView with grouped data return ListView.builder( - itemCount: recordGroups.data!.length, + itemCount: groupedRecords.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); + final String date = groupedRecords.keys.elementAt(index); + final List recordsForDate = + groupedRecords[date]!; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -73,30 +63,57 @@ class DoorRecordsScreen extends StatelessWidget { Padding( padding: const EdgeInsets.all(16.0), child: Text( - formattedDate, + date, style: const TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, + color: ColorsManager.grayColor, + fontSize: 13, + fontWeight: FontWeight.w700, ), ), ), - // Display the event details in DefaultContainer + // List of records for the specific date + 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( - fontWeight: FontWeight.bold, - fontSize: 18, - ), - ), - subtitle: Text('Time: $formattedTime'), + child: Column( + children: [ + ...recordsForDate.map((record) { + final DateTime eventDateTime = + DateTime.fromMillisecondsSinceEpoch( + record.eventTime!); + final String formattedTime = + DateFormat('HH:mm:ss').format(eventDateTime); + + return Column( + children: [ + Container( + 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( + record.value == 'true' + ? "Opened" + : "Closed", + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + subtitle: Text('$formattedTime'), + ), + ), + const Divider( + color: ColorsManager.graysColor, + ) + ], + ); + }).toList(), + ], ), ), ], @@ -104,7 +121,6 @@ class DoorRecordsScreen extends StatelessWidget { }, ); } - return const Center(child: Text('No data available.')); }, ), diff --git a/lib/features/devices/view/widgets/three_gang/schedule_screen.dart b/lib/features/devices/view/widgets/three_gang/schedule_screen.dart index 8e1388a..03232c5 100644 --- a/lib/features/devices/view/widgets/three_gang/schedule_screen.dart +++ b/lib/features/devices/view/widgets/three_gang/schedule_screen.dart @@ -63,17 +63,20 @@ class ScheduleScreen extends StatelessWidget { Navigator.push( context, PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => TimerScheduleScreen( - switchCode :"switch_1", - device: device, - deviceCode: 'countdown_1', - ))); + pageBuilder: + (context, animation1, animation2) => + TimerScheduleScreen( + switchCode: "switch_1", + device: device, + deviceCode: 'countdown_1', + ))); }, child: Container( - padding: - const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20), + padding: const EdgeInsets.only( + left: 25, right: 15, top: 20, bottom: 20), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ BodySmall( text: "Bedside Light", @@ -100,17 +103,20 @@ class ScheduleScreen extends StatelessWidget { Navigator.push( context, PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => TimerScheduleScreen( - switchCode :"switch_2", - device: device, - deviceCode: 'countdown_2', - ))); + pageBuilder: + (context, animation1, animation2) => + TimerScheduleScreen( + switchCode: "switch_2", + device: device, + deviceCode: 'countdown_2', + ))); }, child: Container( - padding: - const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20), + padding: const EdgeInsets.only( + left: 25, right: 15, top: 20, bottom: 20), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ BodySmall( text: "Ceiling Light", @@ -137,17 +143,20 @@ class ScheduleScreen extends StatelessWidget { Navigator.push( context, PageRouteBuilder( - pageBuilder: (context, animation1, animation2) => TimerScheduleScreen( - switchCode :"switch_3", - device: device, - deviceCode: 'countdown_3', - ))); + pageBuilder: + (context, animation1, animation2) => + TimerScheduleScreen( + switchCode: "switch_3", + device: device, + deviceCode: 'countdown_3', + ))); }, child: Container( - padding: - const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20), + padding: const EdgeInsets.only( + left: 25, right: 15, top: 20, bottom: 20), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ BodySmall( text: "Spotlight", diff --git a/lib/features/devices/view/widgets/three_gang/timer_screen.dart b/lib/features/devices/view/widgets/three_gang/timer_screen.dart index 23dcdf5..eb486f4 100644 --- a/lib/features/devices/view/widgets/three_gang/timer_screen.dart +++ b/lib/features/devices/view/widgets/three_gang/timer_screen.dart @@ -22,7 +22,10 @@ class TimerScheduleScreen extends StatelessWidget { final String deviceCode; final String switchCode; const TimerScheduleScreen( - {required this.device, required this.deviceCode, required this.switchCode, super.key}); + {required this.device, + required this.deviceCode, + required this.switchCode, + super.key}); @override Widget build(BuildContext context) { @@ -32,7 +35,8 @@ class TimerScheduleScreen extends StatelessWidget { statusBarIconBrightness: Brightness.light, ), child: BlocProvider( - create: (context) => ThreeGangBloc(switchCode: switchCode, threeGangId: device.uuid ?? '') + create: (context) => ThreeGangBloc( + switchCode: switchCode, threeGangId: device.uuid ?? '') ..add(GetCounterEvent(deviceCode: deviceCode)) ..add(GetScheduleEvent()), child: BlocBuilder( @@ -94,13 +98,15 @@ class TimerScheduleScreen extends StatelessWidget { decoration: const ShapeDecoration( color: ColorsManager.onPrimaryColor, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(30)), + borderRadius: + BorderRadius.all(Radius.circular(30)), ), ), child: TabBar( onTap: (value) { if (value == 0) { - if (threeGangBloc.createSchedule == true) { + if (threeGangBloc.createSchedule == + true) { threeGangBloc.toggleCreateSchedule(); } threeGangBloc.toggleSelectedIndex(0); @@ -108,19 +114,21 @@ class TimerScheduleScreen extends StatelessWidget { threeGangBloc.toggleSelectedIndex(1); } }, - indicatorColor: Colors.white, // Customize the indicator + indicatorColor: Colors.white, dividerHeight: 0, indicatorSize: TabBarIndicatorSize.tab, indicator: const ShapeDecoration( color: ColorsManager.slidingBlueColor, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), + borderRadius: BorderRadius.all( + Radius.circular(20)), ), ), tabs: [ Tab( child: Container( - padding: const EdgeInsets.symmetric(vertical: 10), + padding: const EdgeInsets.symmetric( + vertical: 10), child: BodySmall( text: 'Countdown', style: context.bodySmall.copyWith( @@ -133,7 +141,8 @@ class TimerScheduleScreen extends StatelessWidget { ), Tab( child: Container( - padding: const EdgeInsets.symmetric(vertical: 10), + padding: const EdgeInsets.symmetric( + vertical: 10), child: Text( 'Schedule', style: context.bodySmall.copyWith( @@ -153,84 +162,118 @@ class TimerScheduleScreen extends StatelessWidget { Center( child: Container( child: Column( - mainAxisAlignment: MainAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, children: [ countNum > 0 ? BodyLarge( - text: _formatDuration(countNum), - fontColor: ColorsManager.slidingBlueColor, + text: _formatDuration( + countNum), + fontColor: ColorsManager + .slidingBlueColor, fontSize: 40, ) : CupertinoTimerPicker( - mode: CupertinoTimerPickerMode.hm, + mode: + CupertinoTimerPickerMode + .hm, onTimerDurationChanged: - (Duration newDuration) { + (Duration + newDuration) { duration = newDuration; }, ), GestureDetector( onTap: () { - if (state is LoadingNewSate) { + if (state + is LoadingNewSate) { return; } if (countNum > 0) { - threeGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: Duration.zero)); - } else if (duration != Duration.zero) { - threeGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: duration)); + threeGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: Duration + .zero)); + } else if (duration != + Duration.zero) { + threeGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: + duration)); } }, - child: SvgPicture.asset(countNum > 0 - ? Assets.pauseIcon - : Assets.playIcon)), + child: SvgPicture.asset( + countNum > 0 + ? Assets.pauseIcon + : Assets.playIcon)), ], ), ), ), - Column( - mainAxisAlignment: threeGangBloc.listSchedule.isNotEmpty - ? MainAxisAlignment.start - : MainAxisAlignment.center, - children: [ - SizedBox( - child: threeGangBloc.createSchedule == true - ? CreateSchedule( - onToggleChanged: (bool isOn) { - threeGangBloc.toggleSchedule = isOn; - }, - onDateTimeChanged: (DateTime dateTime) { - threeGangBloc.selectedTime = dateTime; - }, - days: threeGangBloc.days, - selectDays: (List selectedDays) { - threeGangBloc.selectedDays = selectedDays; - }, - ) - : Padding( - padding: const EdgeInsets.only(top: 10), - child: ScheduleListView( - listSchedule: threeGangBloc - .listSchedule, // Pass the schedule list here - onDismissed: (scheduleId) { - threeGangBloc.listSchedule.removeWhere( - (schedule) => - schedule.scheduleId == scheduleId); - threeGangBloc.add( - DeleteScheduleEvent(id: scheduleId)); - }, - onToggleSchedule: (scheduleId, isEnabled) { - threeGangBloc.add(ToggleScheduleEvent( - id: scheduleId, - toggle: isEnabled, - )); - }, + SizedBox( + child: threeGangBloc.createSchedule == + true + ? CreateSchedule( + onToggleChanged: (bool isOn) { + threeGangBloc.toggleSchedule = + isOn; + }, + onDateTimeChanged: + (DateTime dateTime) { + threeGangBloc.selectedTime = + dateTime; + }, + days: threeGangBloc.days, + selectDays: (List + selectedDays) { + threeGangBloc.selectedDays = + selectedDays; + }, + ) + : Padding( + padding: const EdgeInsets.only( + top: 10), + child: Column( + mainAxisAlignment: + MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Expanded( + child: ScheduleListView( + listSchedule: threeGangBloc + .listSchedule, // Pass the schedule list here + onDismissed: + (scheduleId) { + threeGangBloc + .listSchedule + .removeWhere( + (schedule) => + schedule + .scheduleId == + scheduleId); + threeGangBloc.add( + DeleteScheduleEvent( + id: scheduleId)); + }, + onToggleSchedule: + (scheduleId, + isEnabled) { + threeGangBloc.add( + ToggleScheduleEvent( + id: scheduleId, + toggle: isEnabled, + )); + }, + ), ), - ), - ), - ], + ], + ), + ), ), ], ), diff --git a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart index a86ae8c..fcdf71c 100644 --- a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart +++ b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart @@ -63,7 +63,7 @@ class TimerScheduleScreen extends StatelessWidget { }, child: DefaultTabController( length: 2, - child: DefaultScaffold( + child: DefaultScaffold( appBar: AppBar( backgroundColor: Colors.transparent, centerTitle: true, @@ -73,177 +73,204 @@ class TimerScheduleScreen extends StatelessWidget { fontWeight: FontsManager.bold, ), actions: [ - twoGangBloc.createSchedule == true ? - TextButton( - onPressed: () { - twoGangBloc.add(TwoGangSave()); - }, - child: const Text('Save') - ) : - twoGangBloc.selectedTabIndex==1? IconButton( - onPressed: () { - twoGangBloc.toggleCreateSchedule(); - }, - icon: const Icon(Icons.add), - ):SizedBox(), + twoGangBloc.createSchedule == true + ? TextButton( + onPressed: () { + twoGangBloc.add(TwoGangSave()); + }, + child: const Text('Save')) + : twoGangBloc.selectedTabIndex == 1 + ? IconButton( + onPressed: () { + twoGangBloc.toggleCreateSchedule(); + }, + icon: const Icon(Icons.add), + ) + : SizedBox(), ], ), - child: - state is LoadingInitialState? - const Center(child: CircularProgressIndicator()): - Column( - children: [ - Container( - width: MediaQuery.of(context).size.width, - decoration: const ShapeDecoration( - color: ColorsManager.onPrimaryColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(30)), - ), - ), - child: TabBar( - onTap: (value) { - print(value); - if(value==0){ - if(twoGangBloc.createSchedule == true){ - twoGangBloc.toggleCreateSchedule(); - } - twoGangBloc.toggleSelectedIndex(0); - - }else{ - twoGangBloc.toggleSelectedIndex(1); - } - }, - indicatorColor: Colors.white, // Customize the indicator - dividerHeight: 0, - indicatorSize: TabBarIndicatorSize.tab, - indicator: const ShapeDecoration( - color: ColorsManager.slidingBlueColor, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.all(Radius.circular(20)), - ), - ), - tabs: [ - Tab( - child: Container( - padding: const EdgeInsets.symmetric( - vertical: 10), - child: BodySmall( - text: 'Countdown', - style: context.bodySmall.copyWith( - color: ColorsManager.blackColor, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - Tab( - child: Container( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - 'Schedule', - style: context.bodySmall.copyWith( - color: ColorsManager.blackColor, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - ], - ), - ), - Expanded( - child: TabBarView( + child: state is LoadingInitialState + ? const Center(child: CircularProgressIndicator()) + : Column( children: [ - Center( - child: Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - countNum > 0 - ? BodyLarge( - text: _formatDuration(countNum), - fontColor: - ColorsManager.slidingBlueColor, - fontSize: 40, - ) - : CupertinoTimerPicker( - mode: CupertinoTimerPickerMode.hm, - onTimerDurationChanged: - (Duration newDuration) { - duration = newDuration; - }, - ), - GestureDetector( - onTap: () { - if (state is LoadingNewSate) { - return; - } - if (countNum > 0) { - twoGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: Duration.zero)); - } else if (duration != Duration.zero) { - twoGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: duration)); - } - }, - child: SvgPicture.asset(countNum > 0 - ? Assets.pauseIcon - : Assets.playIcon)), - ], + Container( + width: MediaQuery.of(context).size.width, + decoration: const ShapeDecoration( + color: ColorsManager.onPrimaryColor, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.all(Radius.circular(30)), ), ), - ), - Column( - mainAxisAlignment:twoGangBloc.listSchedule.isNotEmpty? - MainAxisAlignment.start:MainAxisAlignment.center, - children: [ - SizedBox( - child: twoGangBloc.createSchedule == true ? - CreateSchedule( - onToggleChanged: (bool isOn) { - twoGangBloc.toggleSchedule = isOn; - }, - onDateTimeChanged: (DateTime dateTime) { - twoGangBloc.selectedTime=dateTime; - }, - days: twoGangBloc.days, - selectDays: (List selectedDays) { - twoGangBloc.selectedDays = selectedDays; - }, - ) - : - Padding( - padding: const EdgeInsets.only(top: 10), - child: ScheduleListView( - listSchedule: twoGangBloc.listSchedule, // Pass the schedule list here - onDismissed: (scheduleId) { - twoGangBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId); - twoGangBloc.add(DeleteScheduleEvent(id: scheduleId)); - }, - onToggleSchedule: (scheduleId, isEnabled) { - twoGangBloc.add(ToggleScheduleEvent( - id: scheduleId, - toggle: isEnabled, - )); - }, - ), + child: TabBar( + onTap: (value) { + print(value); + if (value == 0) { + if (twoGangBloc.createSchedule == + true) { + twoGangBloc.toggleCreateSchedule(); + } + twoGangBloc.toggleSelectedIndex(0); + } else { + twoGangBloc.toggleSelectedIndex(1); + } + }, + indicatorColor: + Colors.white, // Customize the indicator + dividerHeight: 0, + indicatorSize: TabBarIndicatorSize.tab, + indicator: const ShapeDecoration( + color: ColorsManager.slidingBlueColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(20)), ), ), - ], + tabs: [ + Tab( + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 10), + child: BodySmall( + text: 'Countdown', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + Tab( + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 10), + child: Text( + 'Schedule', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ), + Expanded( + child: TabBarView( + children: [ + Center( + child: Container( + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + countNum > 0 + ? BodyLarge( + text: _formatDuration( + countNum), + fontColor: ColorsManager + .slidingBlueColor, + fontSize: 40, + ) + : CupertinoTimerPicker( + mode: + CupertinoTimerPickerMode + .hm, + onTimerDurationChanged: + (Duration + newDuration) { + duration = newDuration; + }, + ), + GestureDetector( + onTap: () { + if (state + is LoadingNewSate) { + return; + } + if (countNum > 0) { + twoGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: Duration + .zero)); + } else if (duration != + Duration.zero) { + twoGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: + duration)); + } + }, + child: SvgPicture.asset( + countNum > 0 + ? Assets.pauseIcon + : Assets.playIcon)), + ], + ), + ), + ), + SizedBox( + child: twoGangBloc.createSchedule == + true + ? CreateSchedule( + onToggleChanged: (bool isOn) { + twoGangBloc.toggleSchedule = + isOn; + }, + onDateTimeChanged: + (DateTime dateTime) { + twoGangBloc.selectedTime = + dateTime; + }, + days: twoGangBloc.days, + selectDays: (List + selectedDays) { + twoGangBloc.selectedDays = + selectedDays; + }, + ) + : Padding( + padding: const EdgeInsets.only( + top: 10), + child: Column( + children: [ + Expanded( + child: ScheduleListView( + listSchedule: twoGangBloc.listSchedule, // Pass the schedule list here + onDismissed:(scheduleId) { + twoGangBloc .listSchedule + .removeWhere( (schedule) => schedule .scheduleId == scheduleId); + twoGangBloc.add( + DeleteScheduleEvent( id: scheduleId)); + }, + onToggleSchedule: + (scheduleId, + isEnabled) { + twoGangBloc.add( + ToggleScheduleEvent( + id: scheduleId, + toggle: isEnabled, + )); + }, + ), + ), + ], + ), + ), + ), + ], + ), ), ], ), - ), - ], - ), - )) - ); + ))); }, ), ), diff --git a/lib/features/devices/view/widgets/water_heater/circulate_list_view.dart b/lib/features/devices/view/widgets/water_heater/circulate_list_view.dart index cdc2b9a..a6792f9 100644 --- a/lib/features/devices/view/widgets/water_heater/circulate_list_view.dart +++ b/lib/features/devices/view/widgets/water_heater/circulate_list_view.dart @@ -1,8 +1,3 @@ - - - - - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -13,7 +8,6 @@ import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart'; import 'package:syncrow_app/generated/assets.dart'; - class CirculateListView extends StatelessWidget { final List listSchedule; final Function(String) onDismissed; @@ -30,96 +24,98 @@ class CirculateListView extends StatelessWidget { return Center( child: listSchedule.isNotEmpty ? SizedBox( - child: ListView.builder( - shrinkWrap: true, - itemCount: listSchedule.length, - itemBuilder: (context, index) { - return Dismissible( - key: Key(listSchedule[index].scheduleId), - background: Container( - padding: const EdgeInsets.only(right: 10), - alignment: AlignmentDirectional.centerEnd, - decoration: const ShapeDecoration( - color: Color(0xFFFF0000), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), - ), - ), - child: Padding( - padding: const EdgeInsets.only(bottom: 10, right: 10), - child: SvgPicture.asset( - Assets.assetsDeleteIcon, - width: 20, - height: 22, - ), - ), - ), - direction: DismissDirection.endToStart, - onDismissed: (direction) { + child: ListView.builder( + shrinkWrap: true, + itemCount: listSchedule.length, + itemBuilder: (context, index) { + return Dismissible( + key: Key(listSchedule[index].scheduleId), + background: Container( + padding: const EdgeInsets.only(right: 10), + alignment: AlignmentDirectional.centerEnd, + decoration: const ShapeDecoration( + color: Color(0xFFFF0000), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), + ), + ), + child: Padding( + padding: const EdgeInsets.only(bottom: 10, right: 10), + child: SvgPicture.asset( + Assets.assetsDeleteIcon, + width: 20, + height: 22, + ), + ), + ), + direction: DismissDirection.endToStart, + onDismissed: (direction) { + onDismissed(listSchedule[index].scheduleId); - onDismissed(listSchedule[index].scheduleId); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Schedule removed')), - ); - }, - child: InkWell( - onTap: () { - - }, - child: DefaultContainer( - padding: const EdgeInsets.all(20), - height: MediaQuery.of(context).size.height / 6.4, - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Schedule removed')), + ); + }, + child: InkWell( + onTap: () {}, + child: DefaultContainer( + padding: const EdgeInsets.all(20), + height: MediaQuery.of(context).size.height / 6.5, + child: Row( children: [ - BodyLarge( - text: '12:30 AM - 01:30 PM', - // text: listSchedule[index].time, - fontWeight: FontWeight.w500, - fontColor: Colors.black, - fontSize: 22, + Expanded( + flex: 2, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + BodyLarge( + text: '12:30 AM - 01:30 PM', + // text: listSchedule[index].time, + fontWeight: FontWeight.w500, + fontColor: Colors.black, + fontSize: 18, + ), + ], + ), + Text(listSchedule[index].days.join(' ')), + // Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'), + Text( + 'Start Duration: 0h 10m End Duration: 0h 15m'), + ], + ), + ), + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const BodyMedium( + text: '', + fontWeight: FontWeight.normal, + ), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: listSchedule[index].enable, + onChanged: (value) { + onToggleSchedule( + listSchedule[index].scheduleId, + value, + ); + }, + applyTheme: true, + ), + ), + ), ), - Text(listSchedule[index].days.join(' ')), - // Text('Function ${listSchedule[index].function.value ? "ON" : "OFF"}'), - Text('Start Duration: 0h 10m End Duration: 0h 15m'), ], ), ), - Expanded( - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: const BodyMedium( - text: '', - fontWeight: FontWeight.normal, - ), - trailing: Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: listSchedule[index].enable, - onChanged: (value) { - onToggleSchedule( - listSchedule[index].scheduleId, - value, - ); - }, - applyTheme: true, - ), - ), - ), - ), - ], - ), - ), + ), + ); + }, ), - ); - }, - ), - ) - : const EmptySchedule() - ); + ) + : const EmptySchedule()); } } diff --git a/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart b/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart index f1325ba..5787f9c 100644 --- a/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart +++ b/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart @@ -76,33 +76,36 @@ class WHTimerScheduleScreen extends StatelessWidget { fontWeight: FontsManager.bold, ), actions: [ - waterHeaterBloc.createSchedule == true && waterHeaterBloc.selectedTabIndex == 1 ? - TextButton( - onPressed: () { - waterHeaterBloc.add(ScheduleSave()); - }, - child: const Text('Save')) : waterHeaterBloc.selectedTabIndex == 1 - ? IconButton( - onPressed: () { - waterHeaterBloc.toggleCreateSchedule(); - }, - icon: const Icon(Icons.add), - ) - : const SizedBox(), - waterHeaterBloc.createCirculate == true &&waterHeaterBloc.selectedTabIndex==2 ? - TextButton( - onPressed: () { - waterHeaterBloc.add(ScheduleSave()); - }, - child: const Text('Save')) - : waterHeaterBloc.selectedTabIndex == 2 - ? IconButton( - onPressed: () { - waterHeaterBloc.toggleCreateCirculate(); + waterHeaterBloc.createSchedule == true && + waterHeaterBloc.selectedTabIndex == 1 + ? TextButton( + onPressed: () { + waterHeaterBloc.add(ScheduleSave()); }, - icon: const Icon(Icons.add), - ) - : const SizedBox(), + child: const Text('Save')) + : waterHeaterBloc.selectedTabIndex == 1 + ? IconButton( + onPressed: () { + waterHeaterBloc.toggleCreateSchedule(); + }, + icon: const Icon(Icons.add), + ) + : const SizedBox(), + waterHeaterBloc.createCirculate == true && + waterHeaterBloc.selectedTabIndex == 2 + ? TextButton( + onPressed: () { + waterHeaterBloc.add(ScheduleSave()); + }, + child: const Text('Save')) + : waterHeaterBloc.selectedTabIndex == 2 + ? IconButton( + onPressed: () { + waterHeaterBloc.toggleCreateCirculate(); + }, + icon: const Icon(Icons.add), + ) + : const SizedBox(), ], ), child: state is WHLoadingState @@ -124,20 +127,29 @@ class WHTimerScheduleScreen extends StatelessWidget { labelPadding: EdgeInsets.zero, onTap: (value) { if (value == 0) { - if (waterHeaterBloc.createSchedule == true) { - waterHeaterBloc.toggleCreateSchedule(); + if (waterHeaterBloc.createSchedule == + true) { + waterHeaterBloc + .toggleCreateSchedule(); } - waterHeaterBloc.toggleSelectedIndex(value); - } else if (value == 2) { - if (waterHeaterBloc.createCirculate == true) { - waterHeaterBloc.toggleCreateCirculate(); + waterHeaterBloc + .toggleSelectedIndex(value); + } else if (value == 2) { + if (waterHeaterBloc.createCirculate == + true) { + waterHeaterBloc + .toggleCreateCirculate(); } - waterHeaterBloc.toggleSelectedIndex(value); + waterHeaterBloc + .toggleSelectedIndex(value); } else { - if (waterHeaterBloc.createSchedule == true) { - waterHeaterBloc.toggleCreateSchedule(); + if (waterHeaterBloc.createSchedule == + true) { + waterHeaterBloc + .toggleCreateSchedule(); } - waterHeaterBloc.toggleSelectedIndex(value); + waterHeaterBloc + .toggleSelectedIndex(value); } }, indicatorColor: Colors.white, @@ -151,96 +163,128 @@ class WHTimerScheduleScreen extends StatelessWidget { ), ), isScrollable: false, - labelColor: Colors.white, // Text color when selected - unselectedLabelColor: ColorsManager.blackColor, // Text color when not selected + labelColor: Colors + .white, // Text color when selected + unselectedLabelColor: ColorsManager + .blackColor, // Text color when not selected tabs: [ Tab( - icon: SvgPicture.asset( - Assets.scheduleTimeIcon, - color: waterHeaterBloc.selectedTabIndex == 0 - ? Colors.white - : ColorsManager.blackColor, // Change icon color based on selectedIndex + icon: Padding( + padding: const EdgeInsets.only( + top: 10.0), + child: SvgPicture.asset( + Assets.scheduleTimeIcon, + color: waterHeaterBloc + .selectedTabIndex == + 0 + ? Colors.white + : ColorsManager + .blackColor, // Change icon color based on selectedIndex + ), ), child: Container( padding: const EdgeInsets.symmetric( - vertical: 10), + vertical: 5), child: BodySmall( text: 'Countdown', style: context.bodySmall.copyWith( - color: waterHeaterBloc.selectedTabIndex == 0 + color: waterHeaterBloc + .selectedTabIndex == + 0 ? Colors.white : ColorsManager .blackColor, // Text color based on selectedTabIndex - fontSize: 8, + fontSize: 10, fontWeight: FontWeight.w400, ), ), ), ), Tab( - icon: SvgPicture.asset( - Assets.scheduleCelenderIcon, - color: waterHeaterBloc.selectedTabIndex == 1 - ? Colors.white - : ColorsManager.blackColor, + icon: Padding( + padding: + const EdgeInsets.only(top: 10), + child: SvgPicture.asset( + Assets.scheduleCelenderIcon, + color: waterHeaterBloc + .selectedTabIndex == + 1 + ? Colors.white + : ColorsManager.blackColor, + ), ), child: Container( padding: const EdgeInsets.symmetric( - vertical: 10), + vertical: 5), child: Text( 'Schedule', style: context.bodySmall.copyWith( - color: waterHeaterBloc.selectedTabIndex == 1 + color: waterHeaterBloc + .selectedTabIndex == + 1 ? Colors.white : ColorsManager.blackColor, - fontSize: 8, + fontSize: 12, fontWeight: FontWeight.w400, ), ), ), ), Tab( - icon: SvgPicture.asset( - Assets.scheduleCirculateIcon, - color: waterHeaterBloc.selectedTabIndex == 2 - ? Colors.white - : ColorsManager.blackColor, + icon: Padding( + padding: + const EdgeInsets.only(top: 10), + child: SvgPicture.asset( + Assets.scheduleCirculateIcon, + color: waterHeaterBloc + .selectedTabIndex == + 2 + ? Colors.white + : ColorsManager.blackColor, + ), ), child: Container( padding: const EdgeInsets.symmetric( - vertical: 10), + vertical: 5), child: Text( 'Circulate', style: context.bodySmall.copyWith( color: waterHeaterBloc - .selectedTabIndex == 2 + .selectedTabIndex == + 2 ? Colors.white : ColorsManager.blackColor, - fontSize: 8, + fontSize: 12, fontWeight: FontWeight.w400, ), ), ), ), Tab( - icon: SvgPicture.asset( - Assets.scheduleInchingIcon, - color: waterHeaterBloc - .selectedTabIndex == 3 - ? Colors.white - : ColorsManager.blackColor, + icon: Padding( + padding: + const EdgeInsets.only(top: 10), + child: SvgPicture.asset( + Assets.scheduleInchingIcon, + color: waterHeaterBloc + .selectedTabIndex == + 3 + ? Colors.white + : ColorsManager.blackColor, + ), ), child: Container( padding: const EdgeInsets.symmetric( - vertical: 10), + vertical: 5), child: Text( 'Inching', style: context.bodySmall.copyWith( color: waterHeaterBloc - .selectedTabIndex == 3 + .selectedTabIndex == + 3 ? Colors.white : ColorsManager.blackColor, - fontSize: 8, + fontSize: 12, fontWeight: FontWeight.w400, ), ), @@ -308,93 +352,132 @@ class WHTimerScheduleScreen extends StatelessWidget { ), ), ), - Column( - mainAxisAlignment: waterHeaterBloc - .listSchedule.isNotEmpty - ? MainAxisAlignment.start - : MainAxisAlignment.center, - children: [ - SizedBox( - child: waterHeaterBloc.createSchedule == true - ? CreateSchedule( - onToggleChanged: (bool isOn) { - waterHeaterBloc.toggleSchedule = isOn; - }, - onDateTimeChanged: (DateTime dateTime) { - waterHeaterBloc.selectedTime = dateTime; - }, - days: waterHeaterBloc.days, - selectDays: (List - selectedDays) { - waterHeaterBloc - .selectedDays = - selectedDays; - }, - ) - : Padding( - padding: const EdgeInsets.only(top: 10), - child: ScheduleListView( - listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here - onDismissed: - (scheduleId) { - waterHeaterBloc.listSchedule.removeWhere( - (schedule) => schedule.scheduleId == scheduleId); - waterHeaterBloc.add( - DeleteScheduleEvent(id: scheduleId)); - }, - onToggleSchedule: (scheduleId, isEnabled) { - - waterHeaterBloc.add(ToggleScheduleEvent( - id: scheduleId, toggle: isEnabled, - )); - }, + SizedBox( + child: waterHeaterBloc.createSchedule == + true + ? CreateSchedule( + onToggleChanged: (bool isOn) { + waterHeaterBloc + .toggleSchedule = isOn; + }, + onDateTimeChanged: + (DateTime dateTime) { + waterHeaterBloc.selectedTime = + dateTime; + }, + days: waterHeaterBloc.days, + selectDays: (List + selectedDays) { + waterHeaterBloc.selectedDays = + selectedDays; + }, + ) + : Padding( + padding: const EdgeInsets.only( + top: 10), + child: Column( + children: [ + Expanded( + child: ScheduleListView( + listSchedule: + waterHeaterBloc + .listSchedule, // Pass the schedule list here + onDismissed: + (scheduleId) { + waterHeaterBloc + .listSchedule + .removeWhere( + (schedule) => + schedule + .scheduleId == + scheduleId); + waterHeaterBloc.add( + DeleteScheduleEvent( + id: scheduleId)); + }, + onToggleSchedule: + (scheduleId, + isEnabled) { + waterHeaterBloc.add( + ToggleScheduleEvent( + id: scheduleId, + toggle: isEnabled, + )); + }, + ), ), - ), - ), - ], + ], + ), + ), ), Center( child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, children: [ - waterHeaterBloc.createCirculate == true - ? - CirculateWidget( - endDuration: () { - waterHeaterBloc.add(SelectTimeEvent(context: context, isEffective: false)); - }, - startDuration: () { - waterHeaterBloc.add(SelectTimeEvent(context: context, isEffective: false)); - - }, - isStartEndTime: true, - startTime: DateTime.now(), - endTime: DateTime.now(), - days: waterHeaterBloc.days, - selectedDays: [], - onToggleStartEndTime: (c) {}, - onTimeChanged: (x, f) { - }, - onDaySelected: (p0) {}, - ):CirculateListView( - listSchedule: waterHeaterBloc.listSchedule, // Pass the schedule list here - onDismissed: (scheduleId) { - waterHeaterBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId); - waterHeaterBloc.add(DeleteScheduleEvent(id: scheduleId)); - }, - onToggleSchedule: (scheduleId, isEnabled) { - waterHeaterBloc.add(ToggleScheduleEvent( - id: scheduleId, toggle: isEnabled, - )); - }, - ) + waterHeaterBloc.createCirculate == + true + ? CirculateWidget( + endDuration: () { + waterHeaterBloc.add( + SelectTimeEvent( + context: context, + isEffective: + false)); + }, + startDuration: () { + waterHeaterBloc.add( + SelectTimeEvent( + context: context, + isEffective: + false)); + }, + isStartEndTime: true, + startTime: DateTime.now(), + endTime: DateTime.now(), + days: waterHeaterBloc.days, + selectedDays: [], + onToggleStartEndTime: + (c) {}, + onTimeChanged: (x, f) {}, + onDaySelected: (p0) {}, + ) + : CirculateListView( + listSchedule: [], // Pass the schedule list here + onDismissed: (scheduleId) { + waterHeaterBloc + .listSchedule + .removeWhere((schedule) => + schedule + .scheduleId == + scheduleId); + waterHeaterBloc.add( + DeleteScheduleEvent( + id: scheduleId)); + }, + onToggleSchedule: + (scheduleId, + isEnabled) { + waterHeaterBloc.add( + ToggleScheduleEvent( + id: scheduleId, + toggle: isEnabled, + )); + }, + ) ], ), ), - Column(children: [ - SizedBox(height: 20), - Container(child: InchingWidget(),),],) + Column( + children: [ + SizedBox(height: 20), + Container( + child: InchingWidget(), + ), + ], + ) ], ), ), diff --git a/lib/features/shared_widgets/schedule_list.dart b/lib/features/shared_widgets/schedule_list.dart index 15e2b6e..9292fcb 100644 --- a/lib/features/shared_widgets/schedule_list.dart +++ b/lib/features/shared_widgets/schedule_list.dart @@ -21,94 +21,98 @@ class ScheduleListView extends StatelessWidget { @override Widget build(BuildContext context) { - return Center( - child: listSchedule.isNotEmpty - ? SizedBox( - child: ListView.builder( - shrinkWrap: true, - itemCount: listSchedule.length, - itemBuilder: (context, index) { - return Dismissible( - key: Key(listSchedule[index].scheduleId), - background: Container( - padding: const EdgeInsets.only(right: 10), - alignment: AlignmentDirectional.centerEnd, - decoration: const ShapeDecoration( - color: Color(0xFFFF0000), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(20)), - ), - ), - child: Padding( - padding: const EdgeInsets.only(bottom: 10, right: 10), - child: SvgPicture.asset( - Assets.assetsDeleteIcon, - width: 20, - height: 22, - ), - ), + return listSchedule.isNotEmpty + ? SizedBox( + child: ListView.builder( + shrinkWrap: true, + itemCount: listSchedule.length, + itemBuilder: (context, index) { + return Dismissible( + key: Key(listSchedule[index].scheduleId), + background: Container( + padding: const EdgeInsets.only(right: 10), + alignment: AlignmentDirectional.centerEnd, + decoration: const ShapeDecoration( + color: Color(0xFFFF0000), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(20)), ), - direction: DismissDirection.endToStart, - onDismissed: (direction) { - onDismissed(listSchedule[index].scheduleId); + ), + child: Padding( + padding: const EdgeInsets.only(bottom: 10, right: 10), + child: SvgPicture.asset( + Assets.assetsDeleteIcon, + width: 20, + height: 22, + ), + ), + ), + direction: DismissDirection.endToStart, + onDismissed: (direction) { + onDismissed(listSchedule[index].scheduleId); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Schedule removed')), - ); - }, - child: InkWell( - onTap: () {}, - child: DefaultContainer( - padding: const EdgeInsets.all(20), - height: MediaQuery.of(context).size.height / 6.4, - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - BodyLarge( - text: listSchedule[index].time, - fontWeight: FontWeight.w500, - fontColor: Colors.black, - fontSize: 22, - ), - Text(listSchedule[index].days.join(' ')), - Text( - 'Function ${listSchedule[index].function.value ? "ON" : "OFF"}'), - ], - ), - ), - Expanded( - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: const BodyMedium( - text: '', - fontWeight: FontWeight.normal, - ), - trailing: Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: listSchedule[index].enable, - onChanged: (value) { - onToggleSchedule( - listSchedule[index].scheduleId, - value, - ); - }, - applyTheme: true, - ), - ), - ), - ), - ], - ), - ), - ), + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Schedule removed')), ); }, - ), - ) - : const EmptySchedule()); + child: InkWell( + onTap: () {}, + child: DefaultContainer( + padding: const EdgeInsets.all(20), + height: MediaQuery.of(context).size.height / 6.4, + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BodyLarge( + text: listSchedule[index].time, + fontWeight: FontWeight.w500, + fontColor: Colors.black, + fontSize: 22, + ), + Text(listSchedule[index].days.join(' ')), + Text( + 'Function ${listSchedule[index].function.value ? "ON" : "OFF"}'), + ], + ), + ), + Expanded( + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const BodyMedium( + text: '', + fontWeight: FontWeight.normal, + ), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: listSchedule[index].enable, + onChanged: (value) { + onToggleSchedule( + listSchedule[index].scheduleId, + value, + ); + }, + applyTheme: true, + ), + ), + ), + ), + ], + ), + ), + ), + ); + }, + ), + ) + : const Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Center(child: EmptySchedule()), + ], + ); } } diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index 1d38fd0..f7e6b14 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -72,7 +72,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 +83,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 +110,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 +150,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 +173,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 +185,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 +197,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 +223,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 +239,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 +252,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) { @@ -361,6 +374,7 @@ class DevicesAPI { .replaceAll('{startTime}', startTime) .replaceAll('{endTime}', endTime), expectedResponseModel: (json) { + print('json-=-=-=-=-=-=-=${json}'); return DeviceReport.fromJson(json); }, ); From dfae04076f7a82a37cd5fb528ab965b8fdb9fff5 Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 23 Sep 2024 16:33:02 +0300 Subject: [PATCH 5/9] Bug fixes 3 --- .../bloc/one_gang_bloc/one_gang_bloc.dart | 40 +- .../bloc/one_gang_bloc/one_gang_event.dart | 18 +- .../bloc/one_gang_bloc/one_gang_state.dart | 2 +- .../bloc/three_gang_bloc/three_gang_bloc.dart | 44 ++- .../three_gang_bloc/three_gang_event.dart | 17 + .../bloc/two_gang_bloc/two_gang_bloc.dart | 125 ++++-- .../bloc/two_gang_bloc/two_gang_event.dart | 16 +- .../water_heater_bloc/water_heater_bloc.dart | 47 ++- .../water_heater_bloc/water_heater_event.dart | 26 +- .../widgets/one_gang/one_gang_screen.dart | 78 ++-- .../one_gang/one_gang_timer_screen.dart | 369 ++++++++++-------- .../view/widgets/three_gang/timer_screen.dart | 32 +- .../widgets/two_gang/two_timer_screen.dart | 39 +- .../wh_timer_schedule_screen.dart | 47 ++- 14 files changed, 593 insertions(+), 307 deletions(-) diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart index 061dbca..db30079 100644 --- a/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_bloc.dart @@ -35,10 +35,12 @@ class OneGangBloc extends Bloc { on(_onClose); on(toggleDaySelection); - on(saveSchedule); + on(saveSchedule); on(getSchedule); on(toggleChange); on(deleteSchedule); + on(toggleSelectedIndex); + on(toggleCreateSchedule); } void _fetchOneGangStatus(InitialEvent event, Emitter emit) async { @@ -196,7 +198,7 @@ class OneGangBloc extends Bloc { ]; Future saveSchedule( - ThreeGangSave event, + ScheduleSave event, Emitter emit, ) async { try { @@ -211,8 +213,9 @@ class OneGangBloc extends Bloc { days: selectedDays); CustomSnackBar.displaySnackBar('Save Successfully'); add(GetScheduleEvent()); - emit(ThreeGangSaveSchedule()); - toggleCreateSchedule(); + emit(SaveSchedule()); + + add(const ToggleCreateScheduleEvent(index:1 )); } else { CustomSnackBar.displaySnackBar('Please select days'); } @@ -287,14 +290,23 @@ class OneGangBloc extends Bloc { } } - void toggleCreateSchedule() { - emit(LoadingInitialState()); - createSchedule = !createSchedule; - selectedDays.clear(); - selectedTime = DateTime.now(); - emit(UpdateCreateScheduleState(createSchedule)); - emit(ChangeSlidingSegmentState(value: 1)); - } + // void toggleCreateSchedule() { + // emit(LoadingInitialState()); + // createSchedule = !createSchedule; + // selectedDays.clear(); + // selectedTime = DateTime.now(); + // emit(UpdateCreateScheduleState(createSchedule)); + // emit(ChangeSlidingSegmentState(value: 1)); + // } + + + void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter emit) { + emit(LoadingInitialState()); + createSchedule = !createSchedule; + selectedDays.clear(); + selectedTime = DateTime.now(); + emit(UpdateCreateScheduleState(createSchedule)); +} bool toggleSchedule = true; List selectedDays = []; @@ -317,9 +329,9 @@ class OneGangBloc extends Bloc { int selectedTabIndex = 0; - void toggleSelectedIndex(index) { + void toggleSelectedIndex( ToggleSelectedEvent event, Emitter emit) { emit(LoadingInitialState()); - selectedTabIndex = index; + selectedTabIndex =event.index; emit(ChangeSlidingSegmentState(value: selectedTabIndex)); } } diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart index af6dee2..a59f653 100644 --- a/lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_event.dart @@ -92,7 +92,7 @@ class OnClose extends OneGangEvent {} //------------------- Schedule ----------=--------- class GetScheduleEvent extends OneGangEvent {} -class ThreeGangSave extends OneGangEvent {} +class ScheduleSave extends OneGangEvent {} class ToggleScheduleEvent extends OneGangEvent { final String id; final bool toggle; @@ -114,3 +114,19 @@ class DeleteScheduleEvent extends OneGangEvent { @override List get props => [id]; } + + +class ToggleSelectedEvent extends OneGangEvent { + final int index; + const ToggleSelectedEvent({required this.index}); + @override + List get props => [index]; +} + + +class ToggleCreateScheduleEvent extends OneGangEvent { + final int index; + const ToggleCreateScheduleEvent({required this.index}); + @override + List get props => [index]; +} diff --git a/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart b/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart index 4078ccf..693851d 100644 --- a/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart +++ b/lib/features/devices/bloc/one_gang_bloc/one_gang_state.dart @@ -77,7 +77,7 @@ class TimerRunInProgress extends OneGangState { class TimerRunComplete extends OneGangState {} -class ThreeGangSaveSchedule extends OneGangState {} +class SaveSchedule extends OneGangState {} class IsToggleState extends OneGangState { final bool? onOff; diff --git a/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart b/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart index 2822b1b..1985acd 100644 --- a/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart +++ b/lib/features/devices/bloc/three_gang_bloc/three_gang_bloc.dart @@ -55,6 +55,9 @@ class ThreeGangBloc extends Bloc { on(getSchedule); on(toggleChange); on(deleteSchedule); + + on(toggleSelectedIndex); + on(toggleCreateSchedule); } void _fetchThreeGangStatus(InitialEvent event, Emitter emit) async { @@ -528,7 +531,7 @@ class ThreeGangBloc extends Bloc { CustomSnackBar.displaySnackBar('Save Successfully'); add(GetScheduleEvent()); emit(ThreeGangSaveSchedule()); - toggleCreateSchedule(); + add(const ToggleCreateScheduleEvent(index:1 )); } else { CustomSnackBar.displaySnackBar('Please select days'); } @@ -603,23 +606,40 @@ class ThreeGangBloc extends Bloc { } } - void toggleCreateSchedule() { - emit(LoadingInitialState()); - createSchedule = !createSchedule; - selectedDays.clear(); - selectedTime = DateTime.now(); - emit(UpdateCreateScheduleState(createSchedule)); - emit(ChangeSlidingSegmentState(value: 1)); - } + // void toggleCreateSchedule() { + // emit(LoadingInitialState()); + // createSchedule = !createSchedule; + // selectedDays.clear(); + // selectedTime = DateTime.now(); + // emit(UpdateCreateScheduleState(createSchedule)); + // emit(ChangeSlidingSegmentState(value: 1)); + // } - int selectedTabIndex = 0; - void toggleSelectedIndex(index) { + + // void toggleSelectedIndex(index) { + // emit(LoadingInitialState()); + // selectedTabIndex = index; + // emit(ChangeSlidingSegmentState(value: selectedTabIndex)); + // } + + + void toggleSelectedIndex( ToggleSelectedEvent event, Emitter emit) { emit(LoadingInitialState()); - selectedTabIndex = index; + selectedTabIndex =event.index; emit(ChangeSlidingSegmentState(value: selectedTabIndex)); } + void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter emit) { + emit(LoadingInitialState()); + createSchedule = !createSchedule; + selectedDays.clear(); + selectedTime = DateTime.now(); + emit(UpdateCreateScheduleState(createSchedule)); +} + + + int selectedTabIndex = 0; bool toggleSchedule = true; List selectedDays = []; bool createSchedule = false; diff --git a/lib/features/devices/bloc/three_gang_bloc/three_gang_event.dart b/lib/features/devices/bloc/three_gang_bloc/three_gang_event.dart index 89ad267..12e727b 100644 --- a/lib/features/devices/bloc/three_gang_bloc/three_gang_event.dart +++ b/lib/features/devices/bloc/three_gang_bloc/three_gang_event.dart @@ -119,3 +119,20 @@ class DeleteScheduleEvent extends ThreeGangEvent { @override List get props => [id]; } + + + +class ToggleSelectedEvent extends ThreeGangEvent { + final int index; + const ToggleSelectedEvent({required this.index}); + @override + List get props => [index]; +} + + +class ToggleCreateScheduleEvent extends ThreeGangEvent { + final int index; + const ToggleCreateScheduleEvent({required this.index}); + @override + List get props => [index]; +} \ No newline at end of file diff --git a/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart b/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart index bb1c329..0891db2 100644 --- a/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_bloc.dart @@ -35,7 +35,8 @@ class TwoGangBloc extends Bloc { bool createSchedule = false; List listSchedule = []; - TwoGangBloc({required this.twoGangId, required this.switchCode}) : super(InitialState()) { + TwoGangBloc({required this.twoGangId, required this.switchCode}) + : super(InitialState()) { on(_fetchTwoGangStatus); on(_twoGangUpdated); on(_changeFirstSwitch); @@ -54,28 +55,47 @@ class TwoGangBloc extends Bloc { on(getSchedule); on(toggleRepeat); on(deleteSchedule); + on(toggleSelectedIndex); + on(toggleCreateSchedule); } DateTime? selectedTime = DateTime.now(); - void toggleCreateSchedule() { + // void toggleCreateSchedule() { + // emit(LoadingInitialState()); + // createSchedule = !createSchedule; + // selectedDays.clear(); + // selectedTime = DateTime.now(); + // emit(UpdateCreateScheduleState(createSchedule)); + // emit(ChangeSlidingSegmentState(value: 1)); + // } + + int selectedTabIndex = 0; + + // void toggleSelectedIndex(index) { + // emit(LoadingInitialState()); + // selectedTabIndex = index; + // emit(ChangeSlidingSegmentState(value: selectedTabIndex)); + // } + + void toggleSelectedIndex( + ToggleSelectedEvent event, Emitter emit) { + emit(LoadingInitialState()); + selectedTabIndex = event.index; + emit(ChangeSlidingSegmentState(value: selectedTabIndex)); + } + + void toggleCreateSchedule( + ToggleCreateScheduleEvent event, Emitter emit) { emit(LoadingInitialState()); createSchedule = !createSchedule; selectedDays.clear(); selectedTime = DateTime.now(); emit(UpdateCreateScheduleState(createSchedule)); - emit(ChangeSlidingSegmentState(value: 1)); } - int selectedTabIndex = 0; - - void toggleSelectedIndex(index) { - emit(LoadingInitialState()); - selectedTabIndex = index; - emit(ChangeSlidingSegmentState(value: selectedTabIndex)); - } - - void _fetchTwoGangStatus(InitialEvent event, Emitter emit) async { + void _fetchTwoGangStatus( + InitialEvent event, Emitter emit) async { emit(LoadingInitialState()); try { twoGangGroup = event.groupScreen; @@ -87,7 +107,8 @@ class TwoGangBloc extends Bloc { HomeCubit.getInstance().selectedSpace?.id ?? '', '2G'); for (int i = 0; i < devicesList.length; i++) { - var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); + var response = + await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? ''); List statusModelList = []; for (var status in response['status']) { statusModelList.add(StatusModel.fromJson(status)); @@ -110,7 +131,8 @@ class TwoGangBloc extends Bloc { return true; }); } - emit(UpdateGroupState(twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); + emit(UpdateGroupState( + twoGangList: groupTwoGangList, allSwitches: allSwitchesOn)); } else { var response = await DevicesAPI.getDeviceStatus(twoGangId); List statusModelList = []; @@ -129,18 +151,21 @@ class TwoGangBloc extends Bloc { _listenToChanges() { try { - DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$twoGangId'); + DatabaseReference ref = + FirebaseDatabase.instance.ref('device-status/$twoGangId'); 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; + Map usersMap = + event.snapshot.value as Map; List statusList = []; usersMap['status'].forEach((element) { - statusList.add(StatusModel(code: element['code'], value: element['value'])); + statusList + .add(StatusModel(code: element['code'], value: element['value'])); }); deviceStatus = TwoGangModel.fromJson(statusList); @@ -155,7 +180,8 @@ class TwoGangBloc extends Bloc { emit(UpdateState(twoGangModel: deviceStatus)); } - void _changeFirstSwitch(ChangeFirstSwitchStatusEvent event, Emitter emit) async { + void _changeFirstSwitch( + ChangeFirstSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { deviceStatus.firstSwitch = !event.value; @@ -181,7 +207,8 @@ class TwoGangBloc extends Bloc { } } - void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event, Emitter emit) async { + void _changeSecondSwitch( + ChangeSecondSwitchStatusEvent event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); try { deviceStatus.secondSwitch = !event.value; @@ -217,11 +244,15 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), + deviceId: twoGangId, + code: 'switch_1', + value: deviceStatus.firstSwitch), twoGangId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), + deviceId: twoGangId, + code: 'switch_2', + value: deviceStatus.secondSwitch), twoGangId), ]); @@ -244,11 +275,15 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_1', value: deviceStatus.firstSwitch), + deviceId: twoGangId, + code: 'switch_1', + value: deviceStatus.firstSwitch), twoGangId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: twoGangId, code: 'switch_2', value: deviceStatus.secondSwitch), + deviceId: twoGangId, + code: 'switch_2', + value: deviceStatus.secondSwitch), twoGangId), ]); if (response.every((element) => !element['success'])) { @@ -274,11 +309,15 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, code: 'switch_1', value: true), + deviceId: groupTwoGangList[i].deviceId, + code: 'switch_1', + value: true), groupTwoGangList[i].deviceId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, code: 'switch_2', value: true), + deviceId: groupTwoGangList[i].deviceId, + code: 'switch_2', + value: true), groupTwoGangList[i].deviceId), ]); @@ -307,11 +346,15 @@ class TwoGangBloc extends Bloc { final response = await Future.wait([ DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, code: 'switch_1', value: false), + deviceId: groupTwoGangList[i].deviceId, + code: 'switch_1', + value: false), groupTwoGangList[i].deviceId), DevicesAPI.controlDevice( DeviceControlModel( - deviceId: groupTwoGangList[i].deviceId, code: 'switch_2', value: false), + deviceId: groupTwoGangList[i].deviceId, + code: 'switch_2', + value: false), groupTwoGangList[i].deviceId), ]); @@ -327,17 +370,20 @@ class TwoGangBloc extends Bloc { } } - void _changeSliding(ChangeSlidingSegment event, Emitter emit) async { + void _changeSliding( + ChangeSlidingSegment event, Emitter emit) async { emit(ChangeSlidingSegmentState(value: event.value)); } - void _setCounterValue(SetCounterValue event, Emitter emit) async { + void _setCounterValue( + SetCounterValue event, Emitter emit) async { emit(LoadingNewSate(twoGangModel: deviceStatus)); int seconds = 0; try { seconds = event.duration.inSeconds; final response = await DevicesAPI.controlDevice( - DeviceControlModel(deviceId: twoGangId, code: event.deviceCode, value: seconds), + DeviceControlModel( + deviceId: twoGangId, code: event.deviceCode, value: seconds), twoGangId); if (response['success'] ?? false) { @@ -362,7 +408,8 @@ class TwoGangBloc extends Bloc { } } - void _getCounterValue(GetCounterEvent event, Emitter emit) async { + void _getCounterValue( + GetCounterEvent event, Emitter emit) async { emit(LoadingInitialState()); try { add(GetScheduleEvent()); @@ -449,7 +496,8 @@ class TwoGangBloc extends Bloc { CustomSnackBar.displaySnackBar('Save Successfully'); add(GetScheduleEvent()); emit(TwoGangSaveSchedule()); - toggleCreateSchedule(); + add(const ToggleCreateScheduleEvent(index: 1)); + // toggleCreateSchedule(); } else { CustomSnackBar.displaySnackBar('Please select days'); } @@ -469,7 +517,8 @@ class TwoGangBloc extends Bloc { deviceId: twoGangId, ); List jsonData = response; - listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); + listSchedule = + jsonData.map((item) => ScheduleModel.fromJson(item)).toList(); emit(InitialState()); } on DioException catch (e) { final errorData = e.response!.data; @@ -480,12 +529,13 @@ class TwoGangBloc extends Bloc { int? getTimeStampWithoutSeconds(DateTime? dateTime) { if (dateTime == null) return null; - DateTime dateTimeWithoutSeconds = - DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute); + DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month, + dateTime.day, dateTime.hour, dateTime.minute); return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000; } - Future toggleRepeat(ToggleScheduleEvent event, Emitter emit) async { + Future toggleRepeat( + ToggleScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.changeSchedule( @@ -504,7 +554,8 @@ class TwoGangBloc extends Bloc { } } - Future deleteSchedule(DeleteScheduleEvent event, Emitter emit) async { + Future deleteSchedule( + DeleteScheduleEvent event, Emitter emit) async { try { emit(LoadingInitialState()); final response = await DevicesAPI.deleteSchedule( diff --git a/lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart b/lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart index 9fd4737..db8bd96 100644 --- a/lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart +++ b/lib/features/devices/bloc/two_gang_bloc/two_gang_event.dart @@ -62,7 +62,7 @@ class GroupAllOffEvent extends TwoGangEvent {} // two_gang_event.dart -class ToggleCreateScheduleEvent extends TwoGangEvent {} +// class ToggleCreateScheduleEvent extends TwoGangEvent {} @@ -125,6 +125,20 @@ class TabChangedEvent extends TwoGangEvent { } +class ToggleSelectedEvent extends TwoGangEvent { + final int index; + const ToggleSelectedEvent({required this.index}); + @override + List get props => [index]; +} + + +class ToggleCreateScheduleEvent extends TwoGangEvent { + final int index; + const ToggleCreateScheduleEvent({required this.index}); + @override + List get props => [index]; +} diff --git a/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart b/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart index 3a397c0..78e25ec 100644 --- a/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart +++ b/lib/features/devices/bloc/water_heater_bloc/water_heater_bloc.dart @@ -48,6 +48,9 @@ class WaterHeaterBloc extends Bloc { on(_onTickTimer); on(_onClose); on(showTime); + + on(toggleSelectedIndex); + on(toggleCreateSchedule); } void _fetchWaterHeaterStatus(WaterHeaterInitial event, Emitter emit) async { @@ -201,7 +204,7 @@ class WaterHeaterBloc extends Bloc { CustomSnackBar.displaySnackBar('Save Successfully'); add(GetScheduleEvent()); emit(SaveSchedule()); - toggleCreateSchedule(); + add(const ToggleCreateScheduleEvent(index:1 )); }else{ CustomSnackBar.displaySnackBar('Please select days'); } @@ -272,22 +275,43 @@ class WaterHeaterBloc extends Bloc { } } - void toggleCreateSchedule() { - emit(WHLoadingState()); - createSchedule = !createSchedule; - selectedDays.clear(); - selectedTime=DateTime.now(); - emit(UpdateCreateScheduleState(createSchedule)); - } + // void toggleCreateSchedule() { + // emit(WHLoadingState()); + // createSchedule = !createSchedule; + // selectedDays.clear(); + // selectedTime=DateTime.now(); + // emit(UpdateCreateScheduleState(createSchedule)); + // } void toggleCreateCirculate() { - emit(WHLoadingState()); + emit(WHLoadingState()); createCirculate = !createCirculate; selectedDays.clear(); selectedTime=DateTime.now(); emit(UpdateCreateScheduleState(createCirculate)); } + + // void toggleSelectedIndex(index) { + // emit(WHLoadingState()); + // selectedTabIndex = index; + // emit(ChangeSlidingSegmentState(value: selectedTabIndex)); + // } + void toggleSelectedIndex( ToggleSelectedEvent event, Emitter emit) { + emit(WHLoadingState()); + selectedTabIndex =event.index; + emit(ChangeSlidingSegmentState(value: selectedTabIndex)); + } + + + void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter emit) { + emit(WHLoadingState()); + createSchedule = !createSchedule; + selectedDays.clear(); + selectedTime = DateTime.now(); + emit(UpdateCreateScheduleState(createSchedule)); +} + Future toggleDaySelection( ToggleDaySelectionEvent event, Emitter emit, @@ -303,11 +327,6 @@ class WaterHeaterBloc extends Bloc { int selectedTabIndex = 0; - void toggleSelectedIndex(index) { - emit(WHLoadingState()); - selectedTabIndex = index; - emit(ChangeSlidingSegmentState(value: selectedTabIndex)); - } showTime(SelectTimeEvent event, Emitter emit) async { final TimeOfDay? timePicked = await showTimePicker( diff --git a/lib/features/devices/bloc/water_heater_bloc/water_heater_event.dart b/lib/features/devices/bloc/water_heater_bloc/water_heater_event.dart index a0f8ef9..d39efa9 100644 --- a/lib/features/devices/bloc/water_heater_bloc/water_heater_event.dart +++ b/lib/features/devices/bloc/water_heater_bloc/water_heater_event.dart @@ -98,4 +98,28 @@ class SelectTimeEvent extends WaterHeaterEvent { const SelectTimeEvent({required this.context, required this.isEffective}); @override List get props => [context, isEffective]; -} \ No newline at end of file +} + + +class ToggleSelectedEvent extends WaterHeaterEvent { + final int index; + const ToggleSelectedEvent({required this.index}); + @override + List get props => [index]; +} + + +class ToggleCreateScheduleEvent extends WaterHeaterEvent { + final int index; + const ToggleCreateScheduleEvent({required this.index}); + @override + List get props => [index]; +} + + +class ToggleCreateCirculateEvent extends WaterHeaterEvent { + final int index; + const ToggleCreateCirculateEvent({required this.index}); + @override + List get props => [index]; +} diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart b/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart index 59ffb34..2bc3353 100644 --- a/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart +++ b/lib/features/devices/view/widgets/one_gang/one_gang_screen.dart @@ -22,8 +22,9 @@ class OneGangScreen extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '') - ..add(const InitialEvent(groupScreen: false)), + create: (context) => + OneGangBloc(switchCode: 'switch_1', oneGangId: device?.uuid ?? '') + ..add(const InitialEvent(groupScreen: false)), child: BlocBuilder( builder: (context, state) { OneGangModel oneGangModel = OneGangModel( @@ -44,15 +45,19 @@ class OneGangScreen extends StatelessWidget { } return state is LoadingInitialState ? const Center( - child: - DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), + child: DefaultContainer( + width: 50, + height: 50, + child: CircularProgressIndicator()), ) : device == null - ? OneGangList(oneGangList: groupOneGangModel, allSwitches: allSwitchesOn) + ? OneGangList( + oneGangList: groupOneGangModel, + allSwitches: allSwitchesOn) : RefreshIndicator( onRefresh: () async { - BlocProvider.of(context) - .add(InitialEvent(groupScreen: device != null ? false : true)); + BlocProvider.of(context).add(InitialEvent( + groupScreen: device != null ? false : true)); }, child: ListView( children: [ @@ -65,8 +70,10 @@ class OneGangScreen extends StatelessWidget { const Expanded(child: SizedBox.shrink()), Expanded( child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.spaceAround, + crossAxisAlignment: + CrossAxisAlignment.center, children: [ Column( children: [ @@ -74,9 +81,12 @@ class OneGangScreen extends StatelessWidget { threeGangSwitch: device!, value: oneGangModel.firstSwitch, action: () { - BlocProvider.of(context).add( - ChangeFirstSwitchStatusEvent( - value: oneGangModel.firstSwitch)); + BlocProvider.of( + context) + .add( + ChangeFirstSwitchStatusEvent( + value: oneGangModel + .firstSwitch)); }, ), const SizedBox(height: 20), @@ -84,7 +94,8 @@ class OneGangScreen extends StatelessWidget { width: 70, child: BodySmall( text: " Entrance Light", - fontColor: ColorsManager.textPrimaryColor, + fontColor: ColorsManager + .textPrimaryColor, textAlign: TextAlign.center, ), ), @@ -96,31 +107,33 @@ class OneGangScreen extends StatelessWidget { Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, children: [ - const SizedBox( - width: 20, - ), Column( mainAxisSize: MainAxisSize.min, children: [ Card( elevation: 3, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(100), + borderRadius: + BorderRadius.circular(100), ), child: GestureDetector( onTap: () { Navigator.push( context, PageRouteBuilder( - pageBuilder: - (context, animation1, animation2) => - TimerScheduleScreen( - switchCode: 'switch_1', - device: device!, - deviceCode: 'countdown_1', - ))); + pageBuilder: (context, + animation1, + animation2) => + TimerScheduleScreen( + switchCode: + 'switch_1', + device: device!, + deviceCode: + 'countdown_1', + ))); }, child: Stack( alignment: Alignment.center, @@ -130,7 +143,9 @@ class OneGangScreen extends StatelessWidget { height: 60, decoration: BoxDecoration( color: Colors.grey[300], - borderRadius: BorderRadius.circular(100), + borderRadius: + BorderRadius.circular( + 100), ), ), Container( @@ -138,13 +153,15 @@ class OneGangScreen extends StatelessWidget { height: 40, decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(100), + borderRadius: + BorderRadius.circular( + 100), ), child: Center( child: Icon( Icons.access_time, - color: - ColorsManager.primaryColorWithOpacity, + color: ColorsManager + .primaryColorWithOpacity, size: 25, ), ), @@ -157,7 +174,8 @@ class OneGangScreen extends StatelessWidget { BodySmall( text: "Timer", style: context.bodyMedium.copyWith( - color: ColorsManager.textPrimaryColor, + color: ColorsManager + .textPrimaryColor, ), ), ], diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart b/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart index 605d5d5..37676a0 100644 --- a/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart +++ b/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart @@ -17,16 +17,15 @@ import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/font_manager.dart'; - class TimerScheduleScreen extends StatelessWidget { final DeviceModel device; final String deviceCode; final String switchCode; const TimerScheduleScreen( {required this.device, - required this.deviceCode, - required this.switchCode, - super.key}); + required this.deviceCode, + required this.switchCode, + super.key}); @override Widget build(BuildContext context) { @@ -37,9 +36,9 @@ class TimerScheduleScreen extends StatelessWidget { ), child: BlocProvider( create: (context) => - OneGangBloc(switchCode: switchCode, oneGangId: device.uuid ?? '') - ..add(GetCounterEvent(deviceCode: deviceCode)) - ..add(GetScheduleEvent()), + OneGangBloc(switchCode: switchCode, oneGangId: device.uuid ?? '') + ..add(GetCounterEvent(deviceCode: deviceCode)) + ..add(GetScheduleEvent()), child: BlocBuilder( builder: (context, state) { final oneGangBloc = BlocProvider.of(context); @@ -64,7 +63,7 @@ class TimerScheduleScreen extends StatelessWidget { }, child: DefaultTabController( length: 2, - child: DefaultScaffold( + child: DefaultScaffold( appBar: AppBar( backgroundColor: Colors.transparent, centerTitle: true, @@ -74,175 +73,211 @@ class TimerScheduleScreen extends StatelessWidget { fontWeight: FontsManager.bold, ), actions: [ - oneGangBloc.createSchedule == true ? - TextButton( - onPressed: () { - oneGangBloc.add(ThreeGangSave()); - }, - child: const Text('Save') - ) : - oneGangBloc.selectedTabIndex==1? IconButton( - onPressed: () { - oneGangBloc.toggleCreateSchedule(); - }, - icon: const Icon(Icons.add), - ):SizedBox(), + oneGangBloc.createSchedule == true + ? TextButton( + onPressed: () { + oneGangBloc.add(ScheduleSave()); + }, + child: const Text('Save')) + : oneGangBloc.selectedTabIndex == 1 + ? IconButton( + onPressed: () { + // oneGangBloc.toggleCreateSchedule(); + oneGangBloc.add( + const ToggleCreateScheduleEvent( + index: 1)); + }, + icon: const Icon(Icons.add), + ) + : const SizedBox(), ], ), - child: - state is LoadingInitialState? - const Center(child: CircularProgressIndicator()): - Column( - children: [ - Container( - width: MediaQuery.of(context).size.width, - decoration: const ShapeDecoration( - color: ColorsManager.onPrimaryColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(30)), - ), - ), - child: TabBar( - onTap: (value) { - if(value==0){ - if(oneGangBloc.createSchedule == true){ - oneGangBloc.toggleCreateSchedule(); - } - oneGangBloc.toggleSelectedIndex(0); - }else{ - oneGangBloc.toggleSelectedIndex(1); - } - }, - indicatorColor: Colors.white, // Customize the indicator - dividerHeight: 0, - indicatorSize: TabBarIndicatorSize.tab, - indicator: const ShapeDecoration( - color: ColorsManager.slidingBlueColor, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.all(Radius.circular(20)), - ), - ), - tabs: [ - Tab( - child: Container( - padding: const EdgeInsets.symmetric( - vertical: 10), - child: BodySmall( - text: 'Countdown', - style: context.bodySmall.copyWith( - color: ColorsManager.blackColor, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - Tab( - child: Container( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - 'Schedule', - style: context.bodySmall.copyWith( - color: ColorsManager.blackColor, - fontSize: 12, - fontWeight: FontWeight.w400, - ), - ), - ), - ), - ], - ), - ), - Expanded( - child: TabBarView( + child: state is LoadingInitialState + ? const Center(child: CircularProgressIndicator()) + : Column( children: [ - Center( - child: Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - countNum > 0 - ? BodyLarge( - text: _formatDuration(countNum), - fontColor: - ColorsManager.slidingBlueColor, - fontSize: 40, - ) - : CupertinoTimerPicker( - mode: CupertinoTimerPickerMode.hm, - onTimerDurationChanged: - (Duration newDuration) { - duration = newDuration; - }, - ), - GestureDetector( - onTap: () { - if (state is LoadingNewSate) { - return; - } - if (countNum > 0) { - oneGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: Duration.zero)); - } else if (duration != Duration.zero) { - oneGangBloc.add(SetCounterValue( - deviceCode: deviceCode, - duration: duration)); - } - }, - child: SvgPicture.asset(countNum > 0 - ? Assets.pauseIcon - : Assets.playIcon)), - ], + Container( + width: MediaQuery.of(context).size.width, + decoration: const ShapeDecoration( + color: ColorsManager.onPrimaryColor, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.all(Radius.circular(30)), ), ), - ), - Column( - mainAxisAlignment:oneGangBloc.listSchedule.isNotEmpty? - MainAxisAlignment.start:MainAxisAlignment.center, - children: [ - SizedBox( - child: oneGangBloc.createSchedule == true ? - CreateSchedule( - onToggleChanged: (bool isOn) { - oneGangBloc.toggleSchedule = isOn; - }, - onDateTimeChanged: (DateTime dateTime) { - oneGangBloc.selectedTime=dateTime; - }, - days: oneGangBloc.days, - selectDays: (List selectedDays) { - oneGangBloc.selectedDays = selectedDays; - }, - ) - : - Padding( - padding: const EdgeInsets.only(top: 10), - child: ScheduleListView( - listSchedule: oneGangBloc.listSchedule, // Pass the schedule list here - onDismissed: (scheduleId) { - oneGangBloc.listSchedule.removeWhere((schedule) => schedule.scheduleId == scheduleId); - oneGangBloc.add(DeleteScheduleEvent(id: scheduleId)); - }, - onToggleSchedule: (scheduleId, isEnabled) { - oneGangBloc.add(ToggleScheduleEvent( - id: scheduleId, - toggle: isEnabled, - )); - }, - ), + child: TabBar( + onTap: (value) { + if (value == 0) { + if (oneGangBloc.createSchedule == + true) { + // oneGangBloc.toggleCreateSchedule(); + oneGangBloc.add( + const ToggleCreateScheduleEvent( + index: 0)); + } + oneGangBloc.add( + const ToggleSelectedEvent( + index: 0)); + } else { + oneGangBloc.add( + const ToggleSelectedEvent( + index: 1)); + } + }, + indicatorColor: + Colors.white, // Customize the indicator + dividerHeight: 0, + indicatorSize: TabBarIndicatorSize.tab, + indicator: const ShapeDecoration( + color: ColorsManager.slidingBlueColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(20)), ), ), - ], + tabs: [ + Tab( + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 10), + child: BodySmall( + text: 'Countdown', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + Tab( + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 10), + child: Text( + 'Schedule', + style: context.bodySmall.copyWith( + color: ColorsManager.blackColor, + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ), + Expanded( + child: TabBarView( + children: [ + Center( + child: Container( + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + countNum > 0 + ? BodyLarge( + text: _formatDuration( + countNum), + fontColor: ColorsManager + .slidingBlueColor, + fontSize: 40, + ) + : CupertinoTimerPicker( + mode: + CupertinoTimerPickerMode + .hm, + onTimerDurationChanged: + (Duration + newDuration) { + duration = newDuration; + }, + ), + GestureDetector( + onTap: () { + if (state + is LoadingNewSate) { + return; + } + if (countNum > 0) { + oneGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: Duration + .zero)); + } else if (duration != + Duration.zero) { + oneGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: + duration)); + } + }, + child: SvgPicture.asset( + countNum > 0 + ? Assets.pauseIcon + : Assets.playIcon)), + ], + ), + ), + ), + SizedBox( + child: oneGangBloc.createSchedule == + true + ? CreateSchedule( + onToggleChanged: (bool isOn) { + oneGangBloc.toggleSchedule = + isOn; + }, + onDateTimeChanged: + (DateTime dateTime) { + oneGangBloc.selectedTime = + dateTime; + }, + days: oneGangBloc.days, + selectDays: (List + selectedDays) { + oneGangBloc.selectedDays = + selectedDays; + }, + ) + : Padding( + padding: const EdgeInsets.only( + top: 10), + child: ScheduleListView( + listSchedule: oneGangBloc + .listSchedule, // Pass the schedule list here + onDismissed: (scheduleId) { + oneGangBloc.listSchedule + .removeWhere((schedule) => + schedule + .scheduleId == + scheduleId); + oneGangBloc.add( + DeleteScheduleEvent( + id: scheduleId)); + }, + onToggleSchedule: + (scheduleId, isEnabled) { + oneGangBloc.add( + ToggleScheduleEvent( + id: scheduleId, + toggle: isEnabled, + )); + }, + ), + ), + ), + ], + ), ), ], ), - ), - ], - ), - )) - ); + ))); }, ), ), diff --git a/lib/features/devices/view/widgets/three_gang/timer_screen.dart b/lib/features/devices/view/widgets/three_gang/timer_screen.dart index eb486f4..453c0e6 100644 --- a/lib/features/devices/view/widgets/three_gang/timer_screen.dart +++ b/lib/features/devices/view/widgets/three_gang/timer_screen.dart @@ -82,11 +82,14 @@ class TimerScheduleScreen extends StatelessWidget { : threeGangBloc.selectedTabIndex == 1 ? IconButton( onPressed: () { - threeGangBloc.toggleCreateSchedule(); + // oneGangBloc.toggleCreateSchedule(); + threeGangBloc.add( + const ToggleCreateScheduleEvent( + index: 1)); }, icon: const Icon(Icons.add), ) - : SizedBox(), + : const SizedBox(), ], ), child: state is LoadingInitialState @@ -103,15 +106,34 @@ class TimerScheduleScreen extends StatelessWidget { ), ), child: TabBar( + // onTap: (value) { + // if (value == 0) { + // if (threeGangBloc.createSchedule == + // true) { + // threeGangBloc.toggleCreateSchedule(); + // } + // threeGangBloc.toggleSelectedIndex(0); + // } else { + // threeGangBloc.toggleSelectedIndex(1); + // } + // }, + onTap: (value) { if (value == 0) { if (threeGangBloc.createSchedule == true) { - threeGangBloc.toggleCreateSchedule(); + // oneGangBloc.toggleCreateSchedule(); + threeGangBloc.add( + const ToggleCreateScheduleEvent( + index: 0)); } - threeGangBloc.toggleSelectedIndex(0); + threeGangBloc.add( + const ToggleSelectedEvent( + index: 0)); } else { - threeGangBloc.toggleSelectedIndex(1); + threeGangBloc.add( + const ToggleSelectedEvent( + index: 1)); } }, indicatorColor: Colors.white, diff --git a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart index fcdf71c..9aa7abc 100644 --- a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart +++ b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart @@ -82,11 +82,14 @@ class TimerScheduleScreen extends StatelessWidget { : twoGangBloc.selectedTabIndex == 1 ? IconButton( onPressed: () { - twoGangBloc.toggleCreateSchedule(); + // oneGangBloc.toggleCreateSchedule(); + twoGangBloc.add( + const ToggleCreateScheduleEvent( + index: 1)); }, icon: const Icon(Icons.add), ) - : SizedBox(), + : const SizedBox(), ], ), child: state is LoadingInitialState @@ -104,15 +107,21 @@ class TimerScheduleScreen extends StatelessWidget { ), child: TabBar( onTap: (value) { - print(value); if (value == 0) { if (twoGangBloc.createSchedule == true) { - twoGangBloc.toggleCreateSchedule(); + // oneGangBloc.toggleCreateSchedule(); + twoGangBloc.add( + const ToggleCreateScheduleEvent( + index: 0)); } - twoGangBloc.toggleSelectedIndex(0); + twoGangBloc.add( + const ToggleSelectedEvent( + index: 0)); } else { - twoGangBloc.toggleSelectedIndex(1); + twoGangBloc.add( + const ToggleSelectedEvent( + index: 1)); } }, indicatorColor: @@ -243,12 +252,20 @@ class TimerScheduleScreen extends StatelessWidget { children: [ Expanded( child: ScheduleListView( - listSchedule: twoGangBloc.listSchedule, // Pass the schedule list here - onDismissed:(scheduleId) { - twoGangBloc .listSchedule - .removeWhere( (schedule) => schedule .scheduleId == scheduleId); + listSchedule: twoGangBloc + .listSchedule, // Pass the schedule list here + onDismissed: + (scheduleId) { + twoGangBloc + .listSchedule + .removeWhere( + (schedule) => + schedule + .scheduleId == + scheduleId); twoGangBloc.add( - DeleteScheduleEvent( id: scheduleId)); + DeleteScheduleEvent( + id: scheduleId)); }, onToggleSchedule: (scheduleId, diff --git a/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart b/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart index 5787f9c..de027a9 100644 --- a/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart +++ b/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart @@ -86,7 +86,10 @@ class WHTimerScheduleScreen extends StatelessWidget { : waterHeaterBloc.selectedTabIndex == 1 ? IconButton( onPressed: () { - waterHeaterBloc.toggleCreateSchedule(); + // waterHeaterBloc.toggleCreateSchedule(); + waterHeaterBloc.add( + const ToggleCreateScheduleEvent( + index: 1)); }, icon: const Icon(Icons.add), ) @@ -129,27 +132,45 @@ class WHTimerScheduleScreen extends StatelessWidget { if (value == 0) { if (waterHeaterBloc.createSchedule == true) { - waterHeaterBloc - .toggleCreateSchedule(); + // waterHeaterBloc + // .toggleCreateSchedule(); + waterHeaterBloc.add( + const ToggleCreateScheduleEvent( + index: 1)); } - waterHeaterBloc - .toggleSelectedIndex(value); + waterHeaterBloc.add( + ToggleSelectedEvent( + index: value)); + // waterHeaterBloc + // .toggleSelectedIndex(value); } else if (value == 2) { if (waterHeaterBloc.createCirculate == true) { - waterHeaterBloc - .toggleCreateCirculate(); + waterHeaterBloc.add( + ToggleCreateCirculateEvent( + index: value)); + // waterHeaterBloc + // .toggleCreateCirculate(); } - waterHeaterBloc - .toggleSelectedIndex(value); + waterHeaterBloc.add( + ToggleSelectedEvent( + index: value)); + // waterHeaterBloc + // .toggleSelectedIndex(value); } else { if (waterHeaterBloc.createSchedule == true) { - waterHeaterBloc - .toggleCreateSchedule(); + waterHeaterBloc.add( + ToggleSelectedEvent( + index: value)); + // waterHeaterBloc + // .toggleCreateSchedule(); } - waterHeaterBloc - .toggleSelectedIndex(value); + waterHeaterBloc.add( + ToggleSelectedEvent( + index: value)); + // waterHeaterBloc + // .toggleSelectedIndex(value); } }, indicatorColor: Colors.white, From 04e8131fb2524a53ac9776e06a954c700be23abb Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 23 Sep 2024 16:33:39 +0300 Subject: [PATCH 6/9] Bug fixes 3 --- lib/services/api/devices_api.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/services/api/devices_api.dart b/lib/services/api/devices_api.dart index f7e6b14..d0c068c 100644 --- a/lib/services/api/devices_api.dart +++ b/lib/services/api/devices_api.dart @@ -365,8 +365,6 @@ class DevicesAPI { 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) @@ -374,7 +372,6 @@ class DevicesAPI { .replaceAll('{startTime}', startTime) .replaceAll('{endTime}', endTime), expectedResponseModel: (json) { - print('json-=-=-=-=-=-=-=${json}'); return DeviceReport.fromJson(json); }, ); From a811baca70322981c1a215e07885d488fbb07b76 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 24 Sep 2024 00:28:46 +0300 Subject: [PATCH 7/9] Fixed design issues --- .../door_sensor/door_sensor_screen.dart | 274 ++++++++---------- .../widgets/water_heater/Inching_widget.dart | 37 ++- .../water_heater/water_heater_page.dart | 50 ++-- .../shared_widgets/schedule_list.dart | 1 - 4 files changed, 165 insertions(+), 197 deletions(-) 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 51c70be..1ae3961 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,13 +25,11 @@ class DoorSensorScreen extends StatelessWidget { title: 'Door Sensor', child: BlocProvider( create: (context) => - DoorSensorBloc( DSId: device?.uuid ?? '') - ..add(const DoorSensorInitial()), + DoorSensorBloc(DSId: device?.uuid ?? '')..add(const DoorSensorInitial()), child: BlocBuilder( builder: (context, state) { final doorSensorBloc = BlocProvider.of(context); - DoorSensorModel model = - DoorSensorModel(batteryPercentage: 0, doorContactState: false); + DoorSensorModel model = DoorSensorModel(batteryPercentage: 0, doorContactState: false); if (state is LoadingNewSate) { model = state.doorSensor; } else if (state is UpdateState) { @@ -39,164 +37,148 @@ class DoorSensorScreen extends StatelessWidget { } return state is DoorSensorLoadingState ? const Center( - child: DefaultContainer( - width: 50, - height: 50, - child: CircularProgressIndicator()), + 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, + child: ListView( + children: [ + SizedBox( + height: MediaQuery.sizeOf(context).height * 0.8, + child: Column( 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, - ), - ], + Expanded( + flex: 4, + child: 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, + ), ), - child: SvgPicture.asset( - model.doorContactState - ? Assets.doorOpen - : Assets.doorClose, - fit: BoxFit.fill, + ], + ), + ), + ), + Flexible( + 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, + ), + ), + ), + ], + ), ), ), ], ), - ), - 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/water_heater/Inching_widget.dart b/lib/features/devices/view/widgets/water_heater/Inching_widget.dart index 948d95c..bd99153 100644 --- a/lib/features/devices/view/widgets/water_heater/Inching_widget.dart +++ b/lib/features/devices/view/widgets/water_heater/Inching_widget.dart @@ -1,13 +1,11 @@ - import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:syncrow_app/features/shared_widgets/default_container.dart'; import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; - class InchingWidget extends StatefulWidget { - const InchingWidget({super.key,this.onDateTimeChanged}); + const InchingWidget({super.key, this.onDateTimeChanged}); final Function(DateTime)? onDateTimeChanged; @override @@ -22,7 +20,7 @@ class _InchingWidgetState extends State { children: [ DefaultContainer( child: Container( - padding: EdgeInsets.all(10), + padding: const EdgeInsets.all(10), child: Column( children: [ Row( @@ -46,26 +44,29 @@ class _InchingWidgetState extends State { ), ], ), - const SizedBox(height: 10,), - const Text('Once enabled this feature, each time the device is turned on, it will automatically turn of after a period time as pre-set.'), + const SizedBox( + height: 10, + ), + const Text( + 'Once enabled this feature, each time the device is turned on, it will automatically turn of after a period time as pre-set.'), ], ), ), ), const Padding( - padding: EdgeInsets.only(right: 30,left: 30), + padding: EdgeInsets.only(right: 30, left: 30), child: Divider(), ), - Container( - child: MinuteSecondPicker()), + Container(child: MinuteSecondPicker()), const Padding( - padding: EdgeInsets.only(right: 30,left: 30), + padding: EdgeInsets.only(right: 30, left: 30), child: Divider(), ), ], ); } } + class MinuteSecondPicker extends StatefulWidget { const MinuteSecondPicker({super.key}); @@ -79,7 +80,7 @@ class _MinuteSecondPickerState extends State { @override Widget build(BuildContext context) { - return Center( + return Center( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -98,10 +99,9 @@ class _MinuteSecondPickerState extends State { children: List.generate(61, (int index) { return Center( child: BodyLarge( - text: index.toString().padLeft(2, '0'), + text: index.toString().padLeft(2, '0'), style: const TextStyle( - fontWeight: FontWeight.w400, - fontSize: 30,color: Colors.blue), + fontWeight: FontWeight.w400, fontSize: 30, color: Colors.blue), ), ); }), @@ -124,20 +124,17 @@ class _MinuteSecondPickerState extends State { children: List.generate(60, (int index) { return Center( child: BodyLarge( - text: index.toString().padLeft(2, '0'), + text: index.toString().padLeft(2, '0'), style: const TextStyle( - fontWeight: FontWeight.w400, - fontSize: 30,color: Colors.blue), + fontWeight: FontWeight.w400, fontSize: 30, color: Colors.blue), ), ); }), ), ), const Text('S'), - ], ), - ); } -} \ No newline at end of file +} diff --git a/lib/features/devices/view/widgets/water_heater/water_heater_page.dart b/lib/features/devices/view/widgets/water_heater/water_heater_page.dart index 9678cba..3f3c168 100644 --- a/lib/features/devices/view/widgets/water_heater/water_heater_page.dart +++ b/lib/features/devices/view/widgets/water_heater/water_heater_page.dart @@ -21,10 +21,10 @@ class WaterHeaterPage extends StatelessWidget { @override Widget build(BuildContext context) { return DefaultScaffold( + title: 'Water heater', child: BlocProvider( - create: (context) => - WaterHeaterBloc(switchCode: 'switch_1', whId: device?.uuid ?? '') - ..add(const WaterHeaterInitial()), + create: (context) => WaterHeaterBloc(switchCode: 'switch_1', whId: device?.uuid ?? '') + ..add(const WaterHeaterInitial()), child: BlocBuilder( builder: (context, state) { final waterHeaterBloc = BlocProvider.of(context); @@ -36,10 +36,8 @@ class WaterHeaterPage extends StatelessWidget { } return state is WHLoadingState ? const Center( - child: DefaultContainer( - width: 50, - height: 50, - child: CircularProgressIndicator()), + child: + DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()), ) : RefreshIndicator( onRefresh: () async { @@ -53,13 +51,11 @@ class WaterHeaterPage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ InkWell( - overlayColor: MaterialStateProperty.all( - Colors.transparent), + overlayColor: MaterialStateProperty.all(Colors.transparent), onTap: () { waterHeaterBloc.add( - WaterHeaterSwitch( - whSwitch:whModel.firstSwitch - ),); + WaterHeaterSwitch(whSwitch: whModel.firstSwitch), + ); }, child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -68,26 +64,22 @@ class WaterHeaterPage extends StatelessWidget { Container( decoration: BoxDecoration( // color: Colors.white.withOpacity(0.1), - borderRadius: - BorderRadius.circular(890), + borderRadius: BorderRadius.circular(890), boxShadow: [ BoxShadow( - color: - Colors.white.withOpacity(0.1), + color: Colors.white.withOpacity(0.1), blurRadius: 24, offset: const Offset(-5, -5), blurStyle: BlurStyle.outer, ), BoxShadow( - color: - Colors.black.withOpacity(0.11), + color: Colors.black.withOpacity(0.11), blurRadius: 25, offset: const Offset(5, 5), blurStyle: BlurStyle.outer, ), BoxShadow( - color: - Colors.black.withOpacity(0.13), + color: Colors.black.withOpacity(0.13), blurRadius: 30, offset: const Offset(5, 5), blurStyle: BlurStyle.inner, @@ -111,8 +103,7 @@ class WaterHeaterPage extends StatelessWidget { Card( elevation: 3, shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(100), + borderRadius: BorderRadius.circular(100), ), child: GestureDetector( onTap: () { @@ -121,8 +112,10 @@ class WaterHeaterPage extends StatelessWidget { PageRouteBuilder( pageBuilder: (context, animation1, animation2) => WHTimerScheduleScreen( - switchCode: 'switch_1', device: device!, deviceCode: 'countdown_1', - ))); + switchCode: 'switch_1', + device: device!, + deviceCode: 'countdown_1', + ))); }, child: Stack( alignment: Alignment.center, @@ -132,8 +125,7 @@ class WaterHeaterPage extends StatelessWidget { height: 60, decoration: BoxDecoration( color: Colors.grey[300], - borderRadius: - BorderRadius.circular(100), + borderRadius: BorderRadius.circular(100), ), ), Container( @@ -141,14 +133,12 @@ class WaterHeaterPage extends StatelessWidget { height: 40, decoration: BoxDecoration( color: Colors.white, - borderRadius: - BorderRadius.circular(100), + borderRadius: BorderRadius.circular(100), ), child: Center( child: Icon( Icons.access_time, - color: ColorsManager - .primaryColorWithOpacity, + color: ColorsManager.primaryColorWithOpacity, size: 25, ), ), diff --git a/lib/features/shared_widgets/schedule_list.dart b/lib/features/shared_widgets/schedule_list.dart index 9292fcb..11248fa 100644 --- a/lib/features/shared_widgets/schedule_list.dart +++ b/lib/features/shared_widgets/schedule_list.dart @@ -59,7 +59,6 @@ class ScheduleListView extends StatelessWidget { onTap: () {}, child: DefaultContainer( padding: const EdgeInsets.all(20), - height: MediaQuery.of(context).size.height / 6.4, child: Row( children: [ Expanded( From 9d8c40e44eb34e80f87b45e37265335bb1b268c9 Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 24 Sep 2024 10:35:56 +0300 Subject: [PATCH 8/9] bugs fixes 4 --- .../devices/view/widgets/one_gang/one_gang_timer_screen.dart | 2 ++ .../devices/view/widgets/three_gang/timer_screen.dart | 2 ++ .../devices/view/widgets/two_gang/two_timer_screen.dart | 2 ++ .../view/widgets/water_heater/wh_timer_schedule_screen.dart | 4 ++++ 4 files changed, 10 insertions(+) diff --git a/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart b/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart index 37676a0..2d766c1 100644 --- a/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart +++ b/lib/features/devices/view/widgets/one_gang/one_gang_timer_screen.dart @@ -169,6 +169,8 @@ class TimerScheduleScreen extends StatelessWidget { ), Expanded( child: TabBarView( + physics: const NeverScrollableScrollPhysics(), // Disable swiping + children: [ Center( child: Container( diff --git a/lib/features/devices/view/widgets/three_gang/timer_screen.dart b/lib/features/devices/view/widgets/three_gang/timer_screen.dart index 453c0e6..8f49fea 100644 --- a/lib/features/devices/view/widgets/three_gang/timer_screen.dart +++ b/lib/features/devices/view/widgets/three_gang/timer_screen.dart @@ -180,6 +180,8 @@ class TimerScheduleScreen extends StatelessWidget { ), Expanded( child: TabBarView( + physics: const NeverScrollableScrollPhysics(), // Disable swiping + children: [ Center( child: Container( diff --git a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart index 9aa7abc..eb1fab5 100644 --- a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart +++ b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart @@ -169,6 +169,8 @@ class TimerScheduleScreen extends StatelessWidget { ), Expanded( child: TabBarView( + physics: const NeverScrollableScrollPhysics(), // Disable swiping + children: [ Center( child: Container( diff --git a/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart b/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart index de027a9..1bafc83 100644 --- a/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart +++ b/lib/features/devices/view/widgets/water_heater/wh_timer_schedule_screen.dart @@ -166,6 +166,10 @@ class WHTimerScheduleScreen extends StatelessWidget { // waterHeaterBloc // .toggleCreateSchedule(); } + waterHeaterBloc.createCirculate = + false; + waterHeaterBloc.createSchedule = + false; waterHeaterBloc.add( ToggleSelectedEvent( index: value)); From e3a6579819035e65f8df5845a83d1f2072267b2e Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 24 Sep 2024 11:15:29 +0300 Subject: [PATCH 9/9] fixes bugs 5 --- .../door_sensor/door_records_screen.dart | 13 ++- .../widgets/two_gang/two_timer_screen.dart | 102 +++++++++--------- 2 files changed, 58 insertions(+), 57 deletions(-) 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 9b4b961..556a983 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 @@ -72,11 +72,12 @@ class DoorRecordsScreen extends StatelessWidget { ), ), // List of records for the specific date - DefaultContainer( child: Column( children: [ - ...recordsForDate.map((record) { + ...recordsForDate.asMap().entries.map((entry) { + final int idx = entry.key; + final DeviceEvent record = entry.value; final DateTime eventDateTime = DateTime.fromMillisecondsSinceEpoch( record.eventTime!); @@ -107,9 +108,11 @@ class DoorRecordsScreen extends StatelessWidget { subtitle: Text('$formattedTime'), ), ), - const Divider( - color: ColorsManager.graysColor, - ) + // Only add Divider if it's not the last item + if (idx != recordsForDate.length - 1) + const Divider( + color: ColorsManager.graysColor, + ), ], ); }).toList(), diff --git a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart index eb1fab5..c06c4c8 100644 --- a/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart +++ b/lib/features/devices/view/widgets/two_gang/two_timer_screen.dart @@ -173,58 +173,56 @@ class TimerScheduleScreen extends StatelessWidget { children: [ Center( - child: Container( - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - countNum > 0 - ? BodyLarge( - text: _formatDuration( - countNum), - fontColor: ColorsManager - .slidingBlueColor, - fontSize: 40, - ) - : CupertinoTimerPicker( - mode: - CupertinoTimerPickerMode - .hm, - onTimerDurationChanged: - (Duration - newDuration) { - duration = newDuration; - }, - ), - GestureDetector( - onTap: () { - if (state - is LoadingNewSate) { - return; - } - if (countNum > 0) { - twoGangBloc.add( - SetCounterValue( - deviceCode: - deviceCode, - duration: Duration - .zero)); - } else if (duration != - Duration.zero) { - twoGangBloc.add( - SetCounterValue( - deviceCode: - deviceCode, - duration: - duration)); - } - }, - child: SvgPicture.asset( - countNum > 0 - ? Assets.pauseIcon - : Assets.playIcon)), - ], - ), + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + countNum > 0 + ? BodyLarge( + text: _formatDuration( + countNum), + fontColor: ColorsManager + .slidingBlueColor, + fontSize: 40, + ) + : CupertinoTimerPicker( + mode: + CupertinoTimerPickerMode + .hm, + onTimerDurationChanged: + (Duration + newDuration) { + duration = newDuration; + }, + ), + GestureDetector( + onTap: () { + if (state + is LoadingNewSate) { + return; + } + if (countNum > 0) { + twoGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: Duration + .zero)); + } else if (duration != + Duration.zero) { + twoGangBloc.add( + SetCounterValue( + deviceCode: + deviceCode, + duration: + duration)); + } + }, + child: SvgPicture.asset( + countNum > 0 + ? Assets.pauseIcon + : Assets.playIcon)), + ], ), ), SizedBox(