fix oct/8 issues

This commit is contained in:
ashrafzarkanisala
2024-10-08 20:15:52 +03:00
parent 66f6b1cba9
commit 79ec890244
19 changed files with 406 additions and 335 deletions

View File

@ -15,6 +15,9 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
List<AllDevicesModel> _selectedDevices = []; List<AllDevicesModel> _selectedDevices = [];
List<AllDevicesModel> _filteredDevices = []; List<AllDevicesModel> _filteredDevices = [];
String productName = ''; String productName = '';
String? currentCommunity;
String? currentUnitName;
String? currentProductName;
DeviceManagementBloc() : super(DeviceManagementInitial()) { DeviceManagementBloc() : super(DeviceManagementInitial()) {
on<FetchDevices>(_onFetchDevices); on<FetchDevices>(_onFetchDevices);
@ -234,6 +237,16 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
} }
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) { void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
if (event.productName == currentProductName &&
event.community == currentCommunity &&
event.unitName == currentUnitName) {
return;
}
currentProductName = event.productName;
currentCommunity = event.community;
currentUnitName = event.unitName;
if ((event.community == null || event.community!.isEmpty) && if ((event.community == null || event.community!.isEmpty) &&
(event.unitName == null || event.unitName!.isEmpty) && (event.unitName == null || event.unitName!.isEmpty) &&
(event.productName == null || event.productName!.isEmpty)) { (event.productName == null || event.productName!.isEmpty)) {

View File

@ -38,14 +38,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
on<GarageDoorBatchControlEvent>(_onBatchControl); on<GarageDoorBatchControlEvent>(_onBatchControl);
on<GarageDoorFetchBatchStatusEvent>(_onFetchBatchStatus); on<GarageDoorFetchBatchStatusEvent>(_onFetchBatchStatus);
on<GarageDoorFactoryResetEvent>(_onFactoryReset); on<GarageDoorFactoryResetEvent>(_onFactoryReset);
on<EditGarageDoorScheduleEvent>(_onEditSchedule);
} }
void _fetchGarageDoorStatus( void _fetchGarageDoorStatus(GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorInitialEvent event, Emitter<GarageDoorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
var response = var response = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId);
deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status); deviceStatus = GarageDoorStatusModel.fromJson(deviceId, response.status);
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} catch (e) { } catch (e) {
@ -53,22 +52,18 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, Future<void> _onFetchBatchStatus(GarageDoorFetchBatchStatusEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
await DevicesManagementApi().getBatchStatus(event.deviceIds); deviceStatus = GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
deviceStatus =
GarageDoorStatusModel.fromJson(event.deviceIds.first, status.status);
emit(GarageDoorBatchStatusLoaded(deviceStatus)); emit(GarageDoorBatchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(GarageDoorBatchControlError(e.toString())); emit(GarageDoorBatchControlError(e.toString()));
} }
} }
Future<void> _addSchedule( Future<void> _addSchedule(AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
AddGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
try { try {
ScheduleEntry newSchedule = ScheduleEntry( ScheduleEntry newSchedule = ScheduleEntry(
category: event.category, category: event.category,
@ -76,11 +71,9 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
function: Status(code: 'switch_1', value: event.functionOn), function: Status(code: 'switch_1', value: event.functionOn),
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays), days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
); );
bool success = bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
await DevicesManagementApi().addScheduleRecord(newSchedule, deviceId);
if (success) { if (success) {
add(FetchGarageDoorSchedulesEvent( add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
deviceId: deviceId, category: 'switch_1'));
} else { } else {
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} }
@ -89,19 +82,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _onUpdateCountdownAlarm( void _onUpdateCountdownAlarm(UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
UpdateCountdownAlarmEvent event, Emitter<GarageDoorState> emit) {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(
status: status: currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
currentState.status.copyWith(countdownAlarm: event.countdownAlarm),
)); ));
} }
} }
void _onUpdateTrTimeCon( void _onUpdateTrTimeCon(UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
UpdateTrTimeConEvent event, Emitter<GarageDoorState> emit) {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(
@ -110,8 +100,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event, Future<void> _updateSchedule(UpdateGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
try { try {
final updatedSchedules = deviceStatus.schedules?.map((schedule) { final updatedSchedules = deviceStatus.schedules?.map((schedule) {
if (schedule.scheduleId == event.scheduleId) { if (schedule.scheduleId == event.scheduleId) {
@ -138,15 +127,12 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event, Future<void> _deleteSchedule(DeleteGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
try { try {
bool success = await DevicesManagementApi() bool success = await DevicesManagementApi().deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
.deleteScheduleRecord(deviceStatus.uuid, event.scheduleId);
if (success) { if (success) {
final updatedSchedules = deviceStatus.schedules final updatedSchedules =
?.where((schedule) => schedule.scheduleId != event.scheduleId) deviceStatus.schedules?.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
.toList();
deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules); deviceStatus = deviceStatus.copyWith(schedules: updatedSchedules);
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} else { } else {
@ -157,12 +143,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event, Future<void> _fetchSchedules(FetchGarageDoorSchedulesEvent event, Emitter<GarageDoorState> emit) async {
Emitter<GarageDoorState> emit) async {
emit(ScheduleGarageLoadingState()); emit(ScheduleGarageLoadingState());
try { try {
List<ScheduleModel> schedules = await DevicesManagementApi() List<ScheduleModel> schedules =
.getDeviceSchedules(deviceStatus.uuid, event.category); await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
deviceStatus = deviceStatus.copyWith(schedules: schedules); deviceStatus = deviceStatus.copyWith(schedules: schedules);
emit( emit(
GarageDoorLoadedState( GarageDoorLoadedState(
@ -180,37 +165,30 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _updateSelectedTime( Future<void> _updateSelectedTime(UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
UpdateSelectedTimeEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith(selectedTime: event.selectedTime)); emit(currentState.copyWith(selectedTime: event.selectedTime));
} }
} }
Future<void> _updateSelectedDay( Future<void> _updateSelectedDay(UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
UpdateSelectedDayEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
List<bool> updatedDays = List.from(currentState.selectedDays); List<bool> updatedDays = List.from(currentState.selectedDays);
updatedDays[event.dayIndex] = event.isSelected; updatedDays[event.dayIndex] = event.isSelected;
emit(currentState.copyWith( emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
} }
} }
Future<void> _updateFunctionOn( Future<void> _updateFunctionOn(UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
UpdateFunctionOnEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(functionOn: event.functionOn, selectedTime: currentState.selectedTime));
functionOn: event.functionOn,
selectedTime: currentState.selectedTime));
} }
} }
Future<void> _initializeAddSchedule( Future<void> _initializeAddSchedule(InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
InitializeAddScheduleEvent event, Emitter<GarageDoorState> emit) async {
final currentState = state; final currentState = state;
if (currentState is GarageDoorLoadedState) { if (currentState is GarageDoorLoadedState) {
emit(currentState.copyWith( emit(currentState.copyWith(
@ -222,25 +200,20 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _fetchRecords( Future<void> _fetchRecords(FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
FetchGarageDoorRecordsEvent event, Emitter<GarageDoorState> emit) async {
emit(GarageDoorReportsLoadingState()); emit(GarageDoorReportsLoadingState());
try { try {
final from = DateTime.now() final from = DateTime.now().subtract(const Duration(days: 30)).millisecondsSinceEpoch;
.subtract(const Duration(days: 30))
.millisecondsSinceEpoch;
final to = DateTime.now().millisecondsSinceEpoch; final to = DateTime.now().millisecondsSinceEpoch;
final DeviceReport records = final DeviceReport records =
await DevicesManagementApi.getDeviceReportsByDate( await DevicesManagementApi.getDeviceReportsByDate(event.deviceId, 'switch_1', from.toString(), to.toString());
event.deviceId, 'switch_1', from.toString(), to.toString());
emit(GarageDoorReportsState(deviceReport: records)); emit(GarageDoorReportsState(deviceReport: records));
} catch (e) { } catch (e) {
emit(GarageDoorReportsFailedState(error: e.toString())); emit(GarageDoorReportsFailedState(error: e.toString()));
} }
} }
Future<void> _onBatchControl( Future<void> _onBatchControl(GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorBatchControlEvent event, Emitter<GarageDoorState> emit) async {
final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false; final oldValue = event.code == 'switch_1' ? deviceStatus.switch1 : false;
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
@ -260,13 +233,11 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _backToGridView( void _backToGridView(BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
BackToGarageDoorGridViewEvent event, Emitter<GarageDoorState> emit) {
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} }
void _handleUpdate( void _handleUpdate(GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
GarageDoorUpdatedEvent event, Emitter<GarageDoorState> emit) {
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
} }
@ -282,11 +253,9 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
late bool status; late bool status;
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 500));
if (isBatch) { if (isBatch) {
status = await DevicesManagementApi() status = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
.deviceBatchControl(deviceId, code, value);
} else { } else {
status = await DevicesManagementApi() status = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
.deviceControl(deviceId, Status(code: code, value: value));
} }
if (!status) { if (!status) {
@ -301,12 +270,10 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
Future<void> _onFactoryReset( Future<void> _onFactoryReset(GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorFactoryResetEvent event, Emitter<GarageDoorState> emit) async {
emit(GarageDoorLoadingState()); emit(GarageDoorLoadingState());
try { try {
final response = await DevicesManagementApi() final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
.factoryReset(event.factoryReset, event.deviceId);
if (!response) { if (!response) {
emit(const GarageDoorErrorState(message: 'Failed to reset device')); emit(const GarageDoorErrorState(message: 'Failed to reset device'));
} else { } else {
@ -317,47 +284,34 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _increaseDelay( void _increaseDelay(IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
IncreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
// if (deviceStatus.countdown1 != 0) { // if (deviceStatus.countdown1 != 0) {
try { try {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay + Duration(minutes: 10));
delay: deviceStatus.delay + Duration(minutes: 10));
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
add(GarageDoorControlEvent( add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
deviceId: event.deviceId,
value: deviceStatus.delay.inSeconds,
code: 'countdown_1'));
} catch (e) { } catch (e) {
emit(GarageDoorErrorState(message: e.toString())); emit(GarageDoorErrorState(message: e.toString()));
} }
// } // }
} }
void _decreaseDelay( void _decreaseDelay(DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
DecreaseGarageDoorDelayEvent event, Emitter<GarageDoorState> emit) async {
// if (deviceStatus.countdown1 != 0) { // if (deviceStatus.countdown1 != 0) {
try { try {
if (deviceStatus.delay.inMinutes > 10) { if (deviceStatus.delay.inMinutes > 10) {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(delay: deviceStatus.delay - Duration(minutes: 10));
delay: deviceStatus.delay - Duration(minutes: 10));
} }
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
add(GarageDoorControlEvent( add(GarageDoorControlEvent(deviceId: event.deviceId, value: deviceStatus.delay.inSeconds, code: 'countdown_1'));
deviceId: event.deviceId,
value: deviceStatus.delay.inSeconds,
code: 'countdown_1'));
} catch (e) { } catch (e) {
emit(GarageDoorErrorState(message: e.toString())); emit(GarageDoorErrorState(message: e.toString()));
} }
//} //}
} }
void _garageDoorControlEvent( void _garageDoorControlEvent(GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async {
GarageDoorControlEvent event, Emitter<GarageDoorState> emit) async { final oldValue = event.code == 'countdown_1' ? deviceStatus.countdown1 : deviceStatus.switch1;
final oldValue = event.code == 'countdown_1'
? deviceStatus.countdown1
: deviceStatus.switch1;
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(GarageDoorLoadedState(status: deviceStatus)); emit(GarageDoorLoadedState(status: deviceStatus));
final success = await _runDeBouncer( final success = await _runDeBouncer(
@ -373,8 +327,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
} }
} }
void _revertValue( void _revertValue(String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
String code, dynamic oldValue, Emitter<GarageDoorState> emit) {
switch (code) { switch (code) {
case 'switch_1': case 'switch_1':
if (oldValue is bool) { if (oldValue is bool) {
@ -383,8 +336,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
break; break;
case 'countdown_1': case 'countdown_1':
if (oldValue is int) { if (oldValue is int) {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(countdown1: oldValue, delay: Duration(seconds: oldValue));
countdown1: oldValue, delay: Duration(seconds: oldValue));
} }
break; break;
// Add other cases if needed // Add other cases if needed
@ -406,8 +358,7 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
break; break;
case 'countdown_1': case 'countdown_1':
if (value is int) { if (value is int) {
deviceStatus = deviceStatus.copyWith( deviceStatus = deviceStatus.copyWith(countdown1: value, delay: Duration(seconds: value));
countdown1: value, delay: Duration(seconds: value));
} }
break; break;
case 'countdown_alarm': case 'countdown_alarm':
@ -420,6 +371,25 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
deviceStatus = deviceStatus.copyWith(trTimeCon: value); deviceStatus = deviceStatus.copyWith(trTimeCon: value);
} }
break; break;
case 'door_state_1':
if (value is String) {
deviceStatus = deviceStatus.copyWith(doorState1: value);
}
break;
case 'door_control_1':
if (value is String) {
deviceStatus = deviceStatus.copyWith(doorControl1: value);
}
break;
case 'voice_control_1':
if (value is bool) {
deviceStatus = deviceStatus.copyWith(voiceControl1: value);
}
break;
case 'door_contact_state':
if (value is bool) {
deviceStatus = deviceStatus.copyWith(doorContactState: value);
}
default: default:
break; break;
} }
@ -430,4 +400,24 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorState> {
_timer?.cancel(); _timer?.cancel();
return super.close(); return super.close();
} }
FutureOr<void> _onEditSchedule(EditGarageDoorScheduleEvent event, Emitter<GarageDoorState> emit) async {
try {
ScheduleEntry newSchedule = ScheduleEntry(
scheduleId: event.scheduleId,
category: event.category,
time: formatTimeOfDayToISO(event.time),
function: Status(code: 'switch_1', value: event.functionOn),
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
);
bool success = await DevicesManagementApi().editScheduleRecord(deviceId, newSchedule);
if (success) {
add(FetchGarageDoorSchedulesEvent(deviceId: deviceId, category: 'switch_1'));
} else {
emit(GarageDoorLoadedState(status: deviceStatus));
}
} catch (e) {
emit(GarageDoorLoadedState(status: deviceStatus));
}
}
} }

View File

@ -25,8 +25,7 @@ class GarageDoorControlEvent extends GarageDoorEvent {
final dynamic value; final dynamic value;
final String code; final String code;
const GarageDoorControlEvent( const GarageDoorControlEvent({required this.deviceId, required this.value, required this.code});
{required this.deviceId, required this.value, required this.code});
@override @override
List<Object?> get props => [deviceId, value]; List<Object?> get props => [deviceId, value];
@ -46,6 +45,22 @@ class AddGarageDoorScheduleEvent extends GarageDoorEvent {
}); });
} }
class EditGarageDoorScheduleEvent extends GarageDoorEvent {
final String scheduleId;
final String category;
final TimeOfDay time;
final bool functionOn;
final List<bool> selectedDays;
const EditGarageDoorScheduleEvent({
required this.scheduleId,
required this.category,
required this.time,
required this.functionOn,
required this.selectedDays,
});
}
class UpdateGarageDoorScheduleEvent extends GarageDoorEvent { class UpdateGarageDoorScheduleEvent extends GarageDoorEvent {
final String deviceId; final String deviceId;
final String scheduleId; final String scheduleId;
@ -106,8 +121,7 @@ class FetchGarageDoorRecordsEvent extends GarageDoorEvent {
final String deviceId; final String deviceId;
final String code; final String code;
const FetchGarageDoorRecordsEvent( const FetchGarageDoorRecordsEvent({required this.deviceId, required this.code});
{required this.deviceId, required this.code});
@override @override
List<Object?> get props => [deviceId, code]; List<Object?> get props => [deviceId, code];

View File

@ -76,13 +76,10 @@ class GarageDoorDialogHelper {
padding: 8, padding: 8,
backgroundColor: ColorsManager.boxColor, backgroundColor: ColorsManager.boxColor,
borderRadius: 15, borderRadius: 15,
onPressed: isEdit == true onPressed: () async {
? null
: () async {
TimeOfDay? time = await showTimePicker( TimeOfDay? time = await showTimePicker(
context: context, context: context,
initialTime: initialTime: state.selectedTime ?? TimeOfDay.now(),
state.selectedTime ?? TimeOfDay.now(),
builder: (context, child) { builder: (context, child) {
return Theme( return Theme(
data: Theme.of(context).copyWith( data: Theme.of(context).copyWith(
@ -102,9 +99,7 @@ class GarageDoorDialogHelper {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
state.selectedTime == null state.selectedTime == null ? 'Time' : state.selectedTime!.format(context),
? 'Time'
: state.selectedTime!.format(context),
style: context.textTheme.bodySmall!.copyWith( style: context.textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
), ),
@ -119,8 +114,7 @@ class GarageDoorDialogHelper {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildDayCheckboxes(context, state.selectedDays, _buildDayCheckboxes(context, state.selectedDays, isEdit: isEdit),
isEdit: isEdit),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildFunctionSwitch(context, state.functionOn, isEdit), _buildFunctionSwitch(context, state.functionOn, isEdit),
], ],
@ -147,7 +141,13 @@ class GarageDoorDialogHelper {
onPressed: () { onPressed: () {
if (state.selectedTime != null) { if (state.selectedTime != null) {
if (state.isEditing && index != null) { if (state.isEditing && index != null) {
return; bloc.add(EditGarageDoorScheduleEvent(
scheduleId: schedule?.scheduleId ?? '',
category: 'switch_1',
time: state.selectedTime!,
selectedDays: state.selectedDays,
functionOn: state.functionOn,
));
} else { } else {
bloc.add(AddGarageDoorScheduleEvent( bloc.add(AddGarageDoorScheduleEvent(
category: 'switch_1', category: 'switch_1',
@ -199,9 +199,7 @@ class GarageDoorDialogHelper {
return daysBoolean; return daysBoolean;
} }
static Widget _buildDayCheckboxes( static Widget _buildDayCheckboxes(BuildContext context, List<bool> selectedDays, {bool? isEdit}) {
BuildContext context, List<bool> selectedDays,
{bool? isEdit}) {
final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
return Row( return Row(
@ -210,12 +208,8 @@ class GarageDoorDialogHelper {
children: [ children: [
Checkbox( Checkbox(
value: selectedDays[index], value: selectedDays[index],
onChanged: isEdit == true onChanged: (bool? value) {
? null context.read<GarageDoorBloc>().add(UpdateSelectedDayEvent(index, value!));
: (bool? value) {
context
.read<GarageDoorBloc>()
.add(UpdateSelectedDayEvent(index, value!));
}, },
), ),
Text(dayLabels[index]), Text(dayLabels[index]),
@ -225,27 +219,19 @@ class GarageDoorDialogHelper {
); );
} }
static Widget _buildFunctionSwitch( static Widget _buildFunctionSwitch(BuildContext context, bool isOn, bool? isEdit) {
BuildContext context, bool isOn, bool? isEdit) {
return Row( return Row(
children: [ children: [
Text( Text(
'Function:', 'Function:',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor),
.copyWith(color: ColorsManager.grayColor),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Radio<bool>( Radio<bool>(
value: true, value: true,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<GarageDoorBloc>().add(const UpdateFunctionOnEvent(functionOn: true));
return;
} else {
context
.read<GarageDoorBloc>()
.add(const UpdateFunctionOnEvent(functionOn: true));
}
}, },
), ),
const Text('On'), const Text('On'),
@ -254,13 +240,7 @@ class GarageDoorDialogHelper {
value: false, value: false,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<GarageDoorBloc>().add(const UpdateFunctionOnEvent(functionOn: false));
return;
} else {
context
.read<GarageDoorBloc>()
.add(const UpdateFunctionOnEvent(functionOn: false));
}
}, },
), ),
const Text('Off'), const Text('Off'),
@ -317,33 +297,36 @@ class GarageDoorDialogHelper {
alertBody: TimeOutAlarmDialogBody(bloc), alertBody: TimeOutAlarmDialogBody(bloc),
title: 'Time Out Alarm', title: 'Time Out Alarm',
onConfirm: () { onConfirm: () {
final updatedState = final updatedState = context.read<GarageDoorBloc>().state;
context.read<GarageDoorBloc>().state; if (updatedState is GarageDoorLoadedState) {
if (updatedState
is GarageDoorLoadedState) {
context.read<GarageDoorBloc>().add( context.read<GarageDoorBloc>().add(
GarageDoorControlEvent( GarageDoorControlEvent(
deviceId: deviceId: updatedState.status.uuid,
updatedState.status.uuid,
code: 'countdown_alarm', code: 'countdown_alarm',
value: updatedState value: updatedState.status.countdownAlarm,
.status.countdownAlarm,
), ),
); );
Navigator.pop(context); Navigator.pop(context);
// context.read<GarageDoorBloc>().add(
// GarageDoorInitialEvent(
// bloc.deviceId));
} }
}); });
}, },
child: ToggleWidget( child: ToggleWidget(
icon: "-1", icon: "-1",
value: state.status.countdownAlarm > 0, value: state.status.doorState1 == "close_time_alarm" ? false : true,
code: 'countdown_alarm', code: 'door_state_1',
deviceId: bloc.deviceId, deviceId: bloc.deviceId,
label: 'Alarm when door is open', label: 'Alarm when door is open',
onChange: (value) {}), onChange: (value) {
context.read<GarageDoorBloc>().add(
GarageDoorControlEvent(
deviceId: bloc.deviceId,
code: 'door_state_1',
value: state.status.doorState1 == "close_time_alarm"
? "unclosed_time"
: "close_time_alarm",
),
);
}),
), ),
), ),
const SizedBox( const SizedBox(
@ -365,23 +348,16 @@ class GarageDoorDialogHelper {
), ),
title: 'Opening and Closing Time', title: 'Opening and Closing Time',
onConfirm: () { onConfirm: () {
final updatedState = final updatedState = context.read<GarageDoorBloc>().state;
context.read<GarageDoorBloc>().state; if (updatedState is GarageDoorLoadedState) {
if (updatedState
is GarageDoorLoadedState) {
context.read<GarageDoorBloc>().add( context.read<GarageDoorBloc>().add(
GarageDoorControlEvent( GarageDoorControlEvent(
deviceId: deviceId: updatedState.status.uuid,
updatedState.status.uuid,
code: 'tr_timecon', code: 'tr_timecon',
value: updatedState value: updatedState.status.trTimeCon,
.status.trTimeCon,
), ),
); );
Navigator.pop(context); Navigator.pop(context);
// context.read<GarageDoorBloc>().add(
// GarageDoorInitialEvent(
// bloc.deviceId));
} }
}); });
}, },

View File

@ -65,7 +65,7 @@ class GarageDoorStatusModel {
voiceControl1 = status.value ?? false; voiceControl1 = status.value ?? false;
break; break;
case 'door_state_1': case 'door_state_1':
doorState1 = status.value ?? 'closed'; doorState1 = status.value ?? 'close_time_alarm';
break; break;
} }
} }

View File

@ -2,9 +2,18 @@ import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class NotificationDialog extends StatelessWidget { class NotificationDialog extends StatefulWidget {
const NotificationDialog({super.key}); const NotificationDialog({super.key});
@override
State<NotificationDialog> createState() => _NotificationDialogState();
}
class _NotificationDialogState extends State<NotificationDialog> {
bool isLowBatteryNotificationEnabled = true;
bool isClosingRemindersEnabled = true;
bool isDoorAlarmEnabled = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Dialog( return Dialog(
@ -66,7 +75,11 @@ class NotificationDialog extends StatelessWidget {
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Low Battery', label: 'Low Battery',
onChange: (v) {}, onChange: (v) {
setState(() {
isLowBatteryNotificationEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
ToggleWidget( ToggleWidget(
@ -74,7 +87,11 @@ class NotificationDialog extends StatelessWidget {
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Closing\nReminders', label: 'Closing\nReminders',
onChange: (v) {}, onChange: (v) {
setState(() {
isClosingRemindersEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
ToggleWidget( ToggleWidget(
@ -82,7 +99,11 @@ class NotificationDialog extends StatelessWidget {
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Door Alarm', label: 'Door Alarm',
onChange: (v) {}, onChange: (v) {
setState(() {
isDoorAlarmEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
], ],

View File

@ -10,14 +10,12 @@ import 'package:syncrow_web/services/devices_mang_api.dart';
part 'one_gang_glass_switch_event.dart'; part 'one_gang_glass_switch_event.dart';
part 'one_gang_glass_switch_state.dart'; part 'one_gang_glass_switch_state.dart';
class OneGangGlassSwitchBloc class OneGangGlassSwitchBloc extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
extends Bloc<OneGangGlassSwitchEvent, OneGangGlassSwitchState> {
OneGangGlassStatusModel deviceStatus; OneGangGlassStatusModel deviceStatus;
Timer? _timer; Timer? _timer;
OneGangGlassSwitchBloc({required String deviceId}) OneGangGlassSwitchBloc({required String deviceId})
: deviceStatus = OneGangGlassStatusModel( : deviceStatus = OneGangGlassStatusModel(uuid: deviceId, switch1: false, countDown: 0),
uuid: deviceId, switch1: false, countDown: 0),
super(OneGangGlassSwitchInitial()) { super(OneGangGlassSwitchInitial()) {
on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus); on<OneGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
on<OneGangGlassSwitchControl>(_onControl); on<OneGangGlassSwitchControl>(_onControl);
@ -26,22 +24,19 @@ class OneGangGlassSwitchBloc
on<OneGangGlassFactoryResetEvent>(_onFactoryReset); on<OneGangGlassFactoryResetEvent>(_onFactoryReset);
} }
Future<void> _onFetchDeviceStatus(OneGangGlassSwitchFetchDeviceEvent event, Future<void> _onFetchDeviceStatus(
Emitter<OneGangGlassSwitchState> emit) async { OneGangGlassSwitchFetchDeviceEvent event, Emitter<OneGangGlassSwitchState> emit) async {
emit(OneGangGlassSwitchLoading()); emit(OneGangGlassSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId); deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
deviceStatus =
OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
emit(OneGangGlassSwitchStatusLoaded(deviceStatus)); emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(OneGangGlassSwitchError(e.toString())); emit(OneGangGlassSwitchError(e.toString()));
} }
} }
Future<void> _onControl(OneGangGlassSwitchControl event, Future<void> _onControl(OneGangGlassSwitchControl event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
final oldValue = _getValueByCode(event.code); final oldValue = _getValueByCode(event.code);
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
@ -57,12 +52,10 @@ class OneGangGlassSwitchBloc
); );
} }
Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event, Future<void> _onFactoryReset(OneGangGlassFactoryResetEvent event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
emit(OneGangGlassSwitchLoading()); emit(OneGangGlassSwitchLoading());
try { try {
final response = await DevicesManagementApi() final response = await DevicesManagementApi().factoryReset(event.factoryReset, event.deviceId);
.factoryReset(event.factoryReset, event.deviceId);
if (!response) { if (!response) {
emit(OneGangGlassSwitchError('Failed to reset device')); emit(OneGangGlassSwitchError('Failed to reset device'));
} else { } else {
@ -73,12 +66,11 @@ class OneGangGlassSwitchBloc
} }
} }
Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event, Future<void> _onBatchControl(OneGangGlassSwitchBatchControl event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
final oldValue = _getValueByCode(event.code); final oldValue = _getValueByCode(event.code);
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(OneGangGlassSwitchBatchStatusLoaded(deviceStatus)); emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
await _runDebounce( await _runDebounce(
deviceId: event.deviceIds, deviceId: event.deviceIds,
@ -91,15 +83,12 @@ class OneGangGlassSwitchBloc
} }
Future<void> _onFetchBatchStatus( Future<void> _onFetchBatchStatus(
OneGangGlassSwitchFetchBatchStatusEvent event, OneGangGlassSwitchFetchBatchStatusEvent event, Emitter<OneGangGlassSwitchState> emit) async {
Emitter<OneGangGlassSwitchState> emit) async {
emit(OneGangGlassSwitchLoading()); emit(OneGangGlassSwitchLoading());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
await DevicesManagementApi().getBatchStatus(event.deviceIds); deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceIds.first, status.status);
deviceStatus = OneGangGlassStatusModel.fromJson( emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
event.deviceIds.first, status.status);
emit(OneGangGlassSwitchBatchStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
emit(OneGangGlassSwitchError(e.toString())); emit(OneGangGlassSwitchError(e.toString()));
} }
@ -128,11 +117,9 @@ class OneGangGlassSwitchBloc
try { try {
late bool response; late bool response;
if (isBatch) { if (isBatch) {
response = await DevicesManagementApi() response = await DevicesManagementApi().deviceBatchControl(deviceId, code, value);
.deviceBatchControl(deviceId, code, value);
} else { } else {
response = await DevicesManagementApi() response = await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value));
.deviceControl(deviceId, Status(code: code, value: value));
} }
if (!response) { if (!response) {
@ -144,8 +131,7 @@ class OneGangGlassSwitchBloc
}); });
} }
void _revertValueAndEmit(String deviceId, String code, bool oldValue, void _revertValueAndEmit(String deviceId, String code, bool oldValue, Emitter<OneGangGlassSwitchState> emit) {
Emitter<OneGangGlassSwitchState> emit) {
_updateLocalValue(code, oldValue); _updateLocalValue(code, oldValue);
emit(OneGangGlassSwitchStatusLoaded(deviceStatus)); emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
} }

View File

@ -55,7 +55,7 @@ class OneGangGlassSwitchControlView extends StatelessWidget with HelperResponsiv
value: status.switch1, value: status.switch1,
code: 'switch_1', code: 'switch_1',
deviceId: deviceId, deviceId: deviceId,
label: 'Wall Lightً', label: "Wall Light",
onChange: (value) { onChange: (value) {
context.read<OneGangGlassSwitchBloc>().add( context.read<OneGangGlassSwitchBloc>().add(
OneGangGlassSwitchControl( OneGangGlassSwitchControl(

View File

@ -31,6 +31,7 @@ class ToggleWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint(label.toString());
return DeviceControlsContainer( return DeviceControlsContainer(
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,

View File

@ -57,7 +57,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
value: status.switch1, value: status.switch1,
code: 'switch_1', code: 'switch_1',
deviceId: deviceIds.first, deviceId: deviceIds.first,
label: 'Glass Switch 1', label: "Wall Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchBatchControl( ThreeGangGlassSwitchBatchControl(
@ -72,7 +72,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
value: status.switch2, value: status.switch2,
code: 'switch_2', code: 'switch_2',
deviceId: deviceIds.first, deviceId: deviceIds.first,
label: 'Glass Switch 2', label: "Ceiling Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchBatchControl( ThreeGangGlassSwitchBatchControl(
@ -87,7 +87,7 @@ class ThreeGangGlassSwitchBatchControlView extends StatelessWidget with HelperRe
value: status.switch3, value: status.switch3,
code: 'switch_3', code: 'switch_3',
deviceId: deviceIds.first, deviceId: deviceIds.first,
label: 'Glass Switch 3', label: "SpotLight",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchBatchControl( ThreeGangGlassSwitchBatchControl(

View File

@ -56,7 +56,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
value: status.switch1, value: status.switch1,
code: 'switch_1', code: 'switch_1',
deviceId: deviceId, deviceId: deviceId,
label: 'Wall Light', label: "Wall Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchControl( ThreeGangGlassSwitchControl(
@ -71,7 +71,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
value: status.switch2, value: status.switch2,
code: 'switch_2', code: 'switch_2',
deviceId: deviceId, deviceId: deviceId,
label: 'Ceiling Light', label: "Ceiling Light",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchControl( ThreeGangGlassSwitchControl(
@ -86,7 +86,7 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget with HelperRespons
value: status.switch3, value: status.switch3,
code: 'switch_3', code: 'switch_3',
deviceId: deviceId, deviceId: deviceId,
label: 'SpotLight', label: "SpotLight",
onChange: (value) { onChange: (value) {
context.read<ThreeGangGlassSwitchBloc>().add( context.read<ThreeGangGlassSwitchBloc>().add(
ThreeGangGlassSwitchControl( ThreeGangGlassSwitchControl(

View File

@ -1,6 +1,7 @@
// water_heater_bloc.dart // water_heater_bloc.dart
import 'dart:async'; import 'dart:async';
import 'package:bloc/bloc.dart'; import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -30,6 +31,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
on<GetSchedulesEvent>(_getSchedule); on<GetSchedulesEvent>(_getSchedule);
on<AddScheduleEvent>(_onAddSchedule); on<AddScheduleEvent>(_onAddSchedule);
on<EditWaterHeaterScheduleEvent>(_onEditSchedule);
on<DeleteScheduleEvent>(_onDeleteSchedule); on<DeleteScheduleEvent>(_onDeleteSchedule);
on<UpdateScheduleEntryEvent>(_onUpdateSchedule); on<UpdateScheduleEntryEvent>(_onUpdateSchedule);
} }
@ -76,8 +78,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
final updatedDays = List<bool>.from(currentState.selectedDays); final updatedDays = List<bool>.from(currentState.selectedDays);
updatedDays[event.index] = event.value; updatedDays[event.index] = event.value;
emit(currentState.copyWith( emit(currentState.copyWith(selectedDays: updatedDays, selectedTime: currentState.selectedTime));
selectedDays: updatedDays, selectedTime: currentState.selectedTime));
} }
FutureOr<void> _updateFunctionOn( FutureOr<void> _updateFunctionOn(
@ -85,8 +86,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
Emitter<WaterHeaterState> emit, Emitter<WaterHeaterState> emit,
) { ) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
emit(currentState.copyWith( emit(currentState.copyWith(functionOn: event.isOn, selectedTime: currentState.selectedTime));
functionOn: event.isOn, selectedTime: currentState.selectedTime));
} }
FutureOr<void> _updateScheduleEvent( FutureOr<void> _updateScheduleEvent(
@ -101,8 +101,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
)); ));
} }
if (event.scheduleMode == ScheduleModes.countdown) { if (event.scheduleMode == ScheduleModes.countdown) {
final countdownRemaining = final countdownRemaining = Duration(hours: event.hours, minutes: event.minutes);
Duration(hours: event.hours, minutes: event.minutes);
emit(currentState.copyWith( emit(currentState.copyWith(
scheduleMode: ScheduleModes.countdown, scheduleMode: ScheduleModes.countdown,
@ -112,13 +111,11 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
countdownRemaining: countdownRemaining, countdownRemaining: countdownRemaining,
)); ));
if (!currentState.isCountdownActive! && if (!currentState.isCountdownActive! && countdownRemaining > Duration.zero) {
countdownRemaining > Duration.zero) {
_startCountdownTimer(emit, countdownRemaining); _startCountdownTimer(emit, countdownRemaining);
} }
} else if (event.scheduleMode == ScheduleModes.inching) { } else if (event.scheduleMode == ScheduleModes.inching) {
final inchingDuration = final inchingDuration = Duration(hours: event.hours, minutes: event.minutes);
Duration(hours: event.hours, minutes: event.minutes);
emit(currentState.copyWith( emit(currentState.copyWith(
scheduleMode: ScheduleModes.inching, scheduleMode: ScheduleModes.inching,
@ -220,8 +217,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
try { try {
final status = await DevicesManagementApi().deviceControl( final status = await DevicesManagementApi().deviceControl(
event.deviceId, event.deviceId,
Status( Status(code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
code: isCountDown ? 'countdown_1' : 'switch_inching', value: 0),
); );
if (!status) { if (!status) {
emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.')); emit(const WaterHeaterFailedState(error: 'Failed to stop schedule.'));
@ -239,10 +235,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
emit(WaterHeaterLoadingState()); emit(WaterHeaterLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId); deviceStatus = WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
deviceStatus =
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
if (deviceStatus.scheduleMode == ScheduleModes.countdown) { if (deviceStatus.scheduleMode == ScheduleModes.countdown) {
final countdownRemaining = Duration( final countdownRemaining = Duration(
@ -340,10 +334,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
if (currentState.countdownRemaining != null && if (currentState.countdownRemaining != null && currentState.countdownRemaining! > Duration.zero) {
currentState.countdownRemaining! > Duration.zero) { final newRemaining = currentState.countdownRemaining! - const Duration(minutes: 1);
final newRemaining =
currentState.countdownRemaining! - const Duration(minutes: 1);
if (newRemaining <= Duration.zero) { if (newRemaining <= Duration.zero) {
_countdownTimer?.cancel(); _countdownTimer?.cancel();
@ -438,8 +430,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
void _revertValue(String code, dynamic oldValue, void _revertValue(String code, dynamic oldValue, void Function(WaterHeaterState state) emit) {
void Function(WaterHeaterState state) emit) {
_updateLocalValue(code, oldValue); _updateLocalValue(code, oldValue);
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
@ -486,13 +477,12 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
return super.close(); return super.close();
} }
FutureOr<void> _getSchedule( FutureOr<void> _getSchedule(GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
GetSchedulesEvent event, Emitter<WaterHeaterState> emit) async {
emit(ScheduleLoadingState()); emit(ScheduleLoadingState());
try { try {
List<ScheduleModel> schedules = await DevicesManagementApi() List<ScheduleModel> schedules =
.getDeviceSchedules(deviceStatus.uuid, event.category); await DevicesManagementApi().getDeviceSchedules(deviceStatus.uuid, event.category);
emit(WaterHeaterDeviceStatusLoaded( emit(WaterHeaterDeviceStatusLoaded(
deviceStatus, deviceStatus,
@ -524,8 +514,35 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
// emit(ScheduleLoadingState()); // emit(ScheduleLoadingState());
bool success = await DevicesManagementApi() bool success = await DevicesManagementApi().addScheduleRecord(newSchedule, currentState.status.uuid);
.addScheduleRecord(newSchedule, currentState.status.uuid);
if (success) {
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
} else {
emit(currentState);
//emit(const WaterHeaterFailedState(error: 'Failed to add schedule.'));
}
}
}
FutureOr<void> _onEditSchedule(EditWaterHeaterScheduleEvent event, Emitter<WaterHeaterState> emit) async {
if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded;
ScheduleEntry newSchedule = ScheduleEntry(
scheduleId: event.scheduleId,
category: event.category,
time: formatTimeOfDayToISO(event.time),
function: Status(code: 'switch_1', value: event.functionOn),
days: ScheduleModel.convertSelectedDaysToStrings(event.selectedDays),
);
// emit(ScheduleLoadingState());
bool success = await DevicesManagementApi().editScheduleRecord(
currentState.status.uuid,
newSchedule,
);
if (success) { if (success) {
add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid)); add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
@ -577,13 +594,11 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
// emit(ScheduleLoadingState()); // emit(ScheduleLoadingState());
bool success = await DevicesManagementApi() bool success = await DevicesManagementApi().deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
.deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
if (success) { if (success) {
final updatedSchedules = currentState.schedules final updatedSchedules =
.where((schedule) => schedule.scheduleId != event.scheduleId) currentState.schedules.where((schedule) => schedule.scheduleId != event.scheduleId).toList();
.toList();
emit(currentState.copyWith(schedules: updatedSchedules)); emit(currentState.copyWith(schedules: updatedSchedules));
} else { } else {
@ -593,15 +608,12 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, FutureOr<void> _batchFetchWaterHeater(FetchWaterHeaterBatchStatusEvent event, Emitter<WaterHeaterState> emit) async {
Emitter<WaterHeaterState> emit) async {
emit(WaterHeaterLoadingState()); emit(WaterHeaterLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.devicesUuid);
await DevicesManagementApi().getBatchStatus(event.devicesUuid); deviceStatus = WaterHeaterStatusModel.fromJson(event.devicesUuid.first, status.status);
deviceStatus = WaterHeaterStatusModel.fromJson(
event.devicesUuid.first, status.status);
emit(WaterHeaterDeviceStatusLoaded(deviceStatus)); emit(WaterHeaterDeviceStatusLoaded(deviceStatus));
} catch (e) { } catch (e) {
@ -609,8 +621,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
} }
} }
FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, FutureOr<void> _batchControlWaterHeater(ControlWaterHeaterBatchEvent event, Emitter<WaterHeaterState> emit) async {
Emitter<WaterHeaterState> emit) async {
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;

View File

@ -71,6 +71,22 @@ final class AddScheduleEvent extends WaterHeaterEvent {
List<Object?> get props => [selectedDays, time, functionOn, category]; List<Object?> get props => [selectedDays, time, functionOn, category];
} }
class EditWaterHeaterScheduleEvent extends WaterHeaterEvent {
final String scheduleId;
final String category;
final TimeOfDay time;
final bool functionOn;
final List<bool> selectedDays;
const EditWaterHeaterScheduleEvent({
required this.scheduleId,
required this.category,
required this.time,
required this.functionOn,
required this.selectedDays,
});
}
final class DeleteScheduleEvent extends WaterHeaterEvent { final class DeleteScheduleEvent extends WaterHeaterEvent {
final int index; final int index;
final String scheduleId; final String scheduleId;

View File

@ -1,14 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart'; import 'package:syncrow_web/pages/device_managment/water_heater/bloc/water_heater_bloc.dart';
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_model.dart'; import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_model.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
class ScheduleDialogHelper { class ScheduleDialogHelper {
static void showAddScheduleDialog(BuildContext context, static void showAddScheduleDialog(BuildContext context, {ScheduleModel? schedule, int? index, bool? isEdit}) {
{ScheduleModel? schedule, int? index, bool? isEdit}) {
final bloc = context.read<WaterHeaterBloc>(); final bloc = context.read<WaterHeaterBloc>();
if (schedule == null) { if (schedule == null) {
@ -70,13 +69,10 @@ class ScheduleDialogHelper {
padding: 8, padding: 8,
backgroundColor: ColorsManager.boxColor, backgroundColor: ColorsManager.boxColor,
borderRadius: 15, borderRadius: 15,
onPressed: isEdit == true onPressed: () async {
? null
: () async {
TimeOfDay? time = await showTimePicker( TimeOfDay? time = await showTimePicker(
context: context, context: context,
initialTime: initialTime: state.selectedTime ?? TimeOfDay.now(),
state.selectedTime ?? TimeOfDay.now(),
builder: (context, child) { builder: (context, child) {
return Theme( return Theme(
data: Theme.of(context).copyWith( data: Theme.of(context).copyWith(
@ -96,9 +92,7 @@ class ScheduleDialogHelper {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
state.selectedTime == null state.selectedTime == null ? 'Time' : state.selectedTime!.format(context),
? 'Time'
: state.selectedTime!.format(context),
style: context.textTheme.bodySmall!.copyWith( style: context.textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
), ),
@ -113,8 +107,7 @@ class ScheduleDialogHelper {
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildDayCheckboxes(context, state.selectedDays, _buildDayCheckboxes(context, state.selectedDays, isEdit: isEdit),
isEdit: isEdit),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildFunctionSwitch(context, state.functionOn, isEdit), _buildFunctionSwitch(context, state.functionOn, isEdit),
], ],
@ -141,7 +134,13 @@ class ScheduleDialogHelper {
onPressed: () { onPressed: () {
if (state.selectedTime != null) { if (state.selectedTime != null) {
if (state.isEditing && index != null) { if (state.isEditing && index != null) {
return; bloc.add(EditWaterHeaterScheduleEvent(
scheduleId: schedule?.scheduleId ?? '',
category: 'switch_1',
time: state.selectedTime!,
selectedDays: state.selectedDays,
functionOn: state.functionOn,
));
} else { } else {
bloc.add(AddScheduleEvent( bloc.add(AddScheduleEvent(
category: 'switch_1', category: 'switch_1',
@ -193,9 +192,7 @@ class ScheduleDialogHelper {
return daysBoolean; return daysBoolean;
} }
static Widget _buildDayCheckboxes( static Widget _buildDayCheckboxes(BuildContext context, List<bool> selectedDays, {bool? isEdit}) {
BuildContext context, List<bool> selectedDays,
{bool? isEdit}) {
final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; final dayLabels = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
return Row( return Row(
@ -204,12 +201,8 @@ class ScheduleDialogHelper {
children: [ children: [
Checkbox( Checkbox(
value: selectedDays[index], value: selectedDays[index],
onChanged: isEdit == true onChanged: (bool? value) {
? null context.read<WaterHeaterBloc>().add(UpdateSelectedDayEvent(index, value!));
: (bool? value) {
context
.read<WaterHeaterBloc>()
.add(UpdateSelectedDayEvent(index, value!));
}, },
), ),
Text(dayLabels[index]), Text(dayLabels[index]),
@ -219,27 +212,19 @@ class ScheduleDialogHelper {
); );
} }
static Widget _buildFunctionSwitch( static Widget _buildFunctionSwitch(BuildContext context, bool isOn, bool? isEdit) {
BuildContext context, bool isOn, bool? isEdit) {
return Row( return Row(
children: [ children: [
Text( Text(
'Function:', 'Function:',
style: context.textTheme.bodySmall! style: context.textTheme.bodySmall!.copyWith(color: ColorsManager.grayColor),
.copyWith(color: ColorsManager.grayColor),
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Radio<bool>( Radio<bool>(
value: true, value: true,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<WaterHeaterBloc>().add(const UpdateFunctionOnEvent(true));
return;
} else {
context
.read<WaterHeaterBloc>()
.add(const UpdateFunctionOnEvent(true));
}
}, },
), ),
const Text('On'), const Text('On'),
@ -248,13 +233,7 @@ class ScheduleDialogHelper {
value: false, value: false,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) { context.read<WaterHeaterBloc>().add(const UpdateFunctionOnEvent(false));
return;
} else {
context
.read<WaterHeaterBloc>()
.add(const UpdateFunctionOnEvent(false));
}
}, },
), ),
const Text('Off'), const Text('Off'),

View File

@ -1,7 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
class ScheduleEntry { class ScheduleEntry {
@ -9,12 +8,14 @@ class ScheduleEntry {
final String time; final String time;
final Status function; final Status function;
final List<String> days; final List<String> days;
final String? scheduleId;
ScheduleEntry({ ScheduleEntry({
required this.category, required this.category,
required this.time, required this.time,
required this.function, required this.function,
required this.days, required this.days,
this.scheduleId,
}); });
@override @override
@ -38,6 +39,7 @@ class ScheduleEntry {
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
return { return {
'scheduleId': scheduleId,
'category': category, 'category': category,
'time': time, 'time': time,
'function': function.toMap(), 'function': function.toMap(),
@ -56,8 +58,7 @@ class ScheduleEntry {
String toJson() => json.encode(toMap()); String toJson() => json.encode(toMap());
factory ScheduleEntry.fromJson(String source) => factory ScheduleEntry.fromJson(String source) => ScheduleEntry.fromMap(json.decode(source));
ScheduleEntry.fromMap(json.decode(source));
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
@ -72,9 +73,6 @@ class ScheduleEntry {
@override @override
int get hashCode { int get hashCode {
return category.hashCode ^ return category.hashCode ^ time.hashCode ^ function.hashCode ^ days.hashCode;
time.hashCode ^
function.hashCode ^
days.hashCode;
} }
} }

View File

@ -2,9 +2,17 @@ import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart'; import 'package:syncrow_web/pages/device_managment/shared/toggle_widget.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class WaterLeakNotificationDialog extends StatelessWidget { class WaterLeakNotificationDialog extends StatefulWidget {
const WaterLeakNotificationDialog({super.key}); const WaterLeakNotificationDialog({super.key});
@override
State<WaterLeakNotificationDialog> createState() => _WaterLeakNotificationDialogState();
}
class _WaterLeakNotificationDialogState extends State<WaterLeakNotificationDialog> {
bool isLowBatteryNotificationEnabled = true;
bool isWaterLeakageNotificationEnabled = true;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Dialog( return Dialog(
@ -66,7 +74,11 @@ class WaterLeakNotificationDialog extends StatelessWidget {
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Low Battery', label: 'Low Battery',
onChange: (v) {}, onChange: (v) {
setState(() {
isLowBatteryNotificationEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
ToggleWidget( ToggleWidget(
@ -74,7 +86,11 @@ class WaterLeakNotificationDialog extends StatelessWidget {
code: 'notification', code: 'notification',
deviceId: '', deviceId: '',
label: 'Water Leakage', label: 'Water Leakage',
onChange: (v) {}, onChange: (v) {
setState(() {
isWaterLeakageNotificationEnabled = v;
});
},
icon: '-1', icon: '-1',
), ),
], ],

View File

@ -71,6 +71,12 @@ class DeviceModel {
tempIcon = Assets.twoGang; tempIcon = Assets.twoGang;
} else if (type == DeviceType.WH) { } else if (type == DeviceType.WH) {
tempIcon = Assets.waterHeater; tempIcon = Assets.waterHeater;
} else if (type == DeviceType.DoorSensor) {
tempIcon = Assets.sensors;
} else if (type == DeviceType.GarageDoor) {
tempIcon = Assets.openedDoor;
} else if (type == DeviceType.WaterLeak) {
tempIcon = Assets.waterLeakNormal;
} else { } else {
tempIcon = Assets.blackLogo; tempIcon = Assets.blackLogo;
} }

View File

@ -232,6 +232,22 @@ class DevicesManagementApi {
} }
} }
Future<bool> editScheduleRecord(String uuid, ScheduleEntry newSchedule) async {
try {
final response = await HTTPService().put(
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
body: newSchedule.toMap(),
expectedResponseModel: (json) {
return json['success'] ?? false;
},
);
return response;
} catch (e) {
debugPrint('Error fetching $e');
return false;
}
}
Future<bool> deleteScheduleRecord(String uuid, String scheduleId) async { Future<bool> deleteScheduleRecord(String uuid, String scheduleId) async {
try { try {
final response = await HTTPService().delete( final response = await HTTPService().delete(

View File

@ -11,8 +11,30 @@ enum DeviceType {
CeilingSensor, CeilingSensor,
WallSensor, WallSensor,
WH, WH,
DoorSensor,
GarageDoor,
WaterLeak,
Other, Other,
} }
/*
3G:
1G:
2G:
GW:
DL:
WPS:
CPS:
AC:
CUR:
WH:
DS:
1GT:
2GT:
3GT:
GD:
WL:
*/
Map<String, DeviceType> devicesTypesMap = { Map<String, DeviceType> devicesTypesMap = {
"AC": DeviceType.AC, "AC": DeviceType.AC,
@ -25,4 +47,10 @@ Map<String, DeviceType> devicesTypesMap = {
"1G": DeviceType.OneGang, "1G": DeviceType.OneGang,
"CUR": DeviceType.Curtain, "CUR": DeviceType.Curtain,
"WH": DeviceType.WH, "WH": DeviceType.WH,
'DS': DeviceType.DoorSensor,
"1GT": DeviceType.OneGang,
"2GT": DeviceType.TwoGang,
"3GT": DeviceType.ThreeGang,
'GD': DeviceType.GarageDoor,
'WL': DeviceType.WaterLeak
}; };