mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
Add schedule saving functionality and update schedule events
This commit is contained in:
@ -37,28 +37,39 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
||||
Timer? _countdownTimer;
|
||||
Duration countdownRemaining = Duration.zero;
|
||||
|
||||
void _onStopScheduleEvent(
|
||||
Future<void> _onStopScheduleEvent(
|
||||
StopScheduleEvent event,
|
||||
Emitter<ScheduleState> emit,
|
||||
) {
|
||||
) async {
|
||||
if (state is ScheduleLoaded) {
|
||||
final currentState = state as ScheduleLoaded;
|
||||
_countdownTimer?.cancel();
|
||||
|
||||
if (event.mode == ScheduleModes.countdown) {
|
||||
emit(currentState.copyWith(
|
||||
countdownHours: 0,
|
||||
countdownMinutes: 0,
|
||||
isCountdownActive: false,
|
||||
countdownRemaining: Duration.zero,
|
||||
));
|
||||
} else if (event.mode == ScheduleModes.inching) {
|
||||
emit(currentState.copyWith(
|
||||
inchingHours: 0,
|
||||
inchingMinutes: 0,
|
||||
isInchingActive: false,
|
||||
countdownRemaining: Duration.zero,
|
||||
));
|
||||
final success = await RemoteControlDeviceService().controlDevice(
|
||||
deviceUuid: deviceId,
|
||||
status: Status(
|
||||
code: 'countdown_1',
|
||||
value: 0,
|
||||
),
|
||||
);
|
||||
if (success) {
|
||||
_countdownTimer?.cancel();
|
||||
if (event.mode == ScheduleModes.countdown) {
|
||||
emit(currentState.copyWith(
|
||||
countdownHours: 0,
|
||||
countdownMinutes: 0,
|
||||
isCountdownActive: false,
|
||||
countdownRemaining: Duration.zero,
|
||||
));
|
||||
} else if (event.mode == ScheduleModes.inching) {
|
||||
emit(currentState.copyWith(
|
||||
inchingHours: 0,
|
||||
inchingMinutes: 0,
|
||||
isInchingActive: false,
|
||||
countdownRemaining: Duration.zero,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
emit(const ScheduleError('Failed to stop schedule'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -241,16 +252,14 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
||||
) async {
|
||||
try {
|
||||
if (state is ScheduleLoaded) {
|
||||
final newSchedule = ScheduleEntry(
|
||||
final dateTime = DateTime.parse(event.time);
|
||||
final success = await DevicesManagementApi().postSchedule(
|
||||
category: event.category,
|
||||
time: event.time,
|
||||
function: Status(code: 'switch_1', value: event.functionOn),
|
||||
deviceId: deviceId,
|
||||
time: getTimeStampWithoutSeconds(dateTime).toString(),
|
||||
code: 'switch_1',
|
||||
value: event.functionOn,
|
||||
days: event.selectedDays);
|
||||
final success = await DevicesManagementApi().addScheduleRecord(
|
||||
newSchedule,
|
||||
deviceId,
|
||||
);
|
||||
|
||||
if (success) {
|
||||
add(const ScheduleGetEvent(category: 'switch_1'));
|
||||
} else {
|
||||
@ -268,14 +277,14 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
||||
) async {
|
||||
try {
|
||||
if (state is ScheduleLoaded) {
|
||||
final dateTime = DateTime.parse(event.time);
|
||||
final updatedSchedule = ScheduleEntry(
|
||||
scheduleId: event.scheduleId,
|
||||
category: event.category,
|
||||
time: event.time,
|
||||
time: getTimeStampWithoutSeconds(dateTime).toString(),
|
||||
function: Status(code: 'switch_1', value: event.functionOn),
|
||||
days: event.selectedDays,
|
||||
);
|
||||
|
||||
final success = await DevicesManagementApi().editScheduleRecord(
|
||||
deviceId,
|
||||
updatedSchedule,
|
||||
@ -299,10 +308,12 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
||||
try {
|
||||
if (state is ScheduleLoaded) {
|
||||
final currentState = state as ScheduleLoaded;
|
||||
|
||||
final updatedSchedules = currentState.schedules.map((schedule) {
|
||||
if (schedule.scheduleId == event.scheduleId) {
|
||||
return schedule.copyWith(
|
||||
function: Status(code: 'switch_1', value: event.functionOn),
|
||||
enable: event.enable,
|
||||
);
|
||||
}
|
||||
return schedule;
|
||||
@ -491,10 +502,16 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
||||
try {
|
||||
final status =
|
||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||
print(status.status);
|
||||
final deviceStatus =
|
||||
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||
|
||||
final scheduleMode = deviceStatus.scheduleMode;
|
||||
final scheduleMode =
|
||||
deviceStatus.countdownHours > 0 || deviceStatus.countdownMinutes > 0
|
||||
? ScheduleModes.countdown
|
||||
: deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0
|
||||
? ScheduleModes.inching
|
||||
: ScheduleModes.schedule;
|
||||
final isCountdown = scheduleMode == ScheduleModes.countdown;
|
||||
final isInching = scheduleMode == ScheduleModes.inching;
|
||||
|
||||
@ -516,6 +533,10 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
||||
Duration.zero;
|
||||
}
|
||||
if (state is ScheduleLoaded) {
|
||||
print('Updating existing state with fetched status');
|
||||
print('scheduleMode: $scheduleMode');
|
||||
print('countdownRemaining: $countdownRemaining');
|
||||
print('isCountdownActive: $isCountdownActive');
|
||||
final currentState = state as ScheduleLoaded;
|
||||
emit(currentState.copyWith(
|
||||
scheduleMode: scheduleMode,
|
||||
@ -546,12 +567,54 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
||||
));
|
||||
}
|
||||
|
||||
if (isCountdownActive && countdownRemaining != null) {
|
||||
_startCountdownTimer(emit, countdownRemaining);
|
||||
}
|
||||
// if (isCountdownActive && countdownRemaining != null) {
|
||||
// _startCountdownTimer(emit, countdownRemaining);
|
||||
// }
|
||||
} catch (e) {
|
||||
emit(ScheduleError('Failed to fetch device status: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
String extractTime(String isoDateTime) {
|
||||
// Example input: "2025-06-19T15:45:00.000"
|
||||
return isoDateTime.split('T')[1].split('.')[0]; // gives "15:45:00"
|
||||
}
|
||||
|
||||
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
|
||||
if (dateTime == null) return null;
|
||||
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
|
||||
dateTime.day, dateTime.hour, dateTime.minute);
|
||||
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
|
||||
}
|
||||
|
||||
// Future <void> _updateScheduleEvent(
|
||||
// StatusUpdatedScheduleEvent event,
|
||||
// Emitter<ScheduleState> emit,
|
||||
// ) async {
|
||||
// if (state is ScheduleLoaded) {
|
||||
// final currentState = state as ScheduleLoaded;
|
||||
|
||||
// final updatedSchedules = currentState.schedules.map((schedule) {
|
||||
// if (schedule.scheduleId == event.scheduleId) {
|
||||
// return schedule.copyWith(
|
||||
// function: Status(code: 'switch_1', value: event.functionOn),
|
||||
// enable: event.enable,
|
||||
// );
|
||||
// }
|
||||
// return schedule;
|
||||
// }).toList();
|
||||
|
||||
// bool success = await DevicesManagementApi().updateScheduleRecord(
|
||||
// enable: event.enable,
|
||||
// uuid: currentState.status.uuid,
|
||||
// scheduleId: event.scheduleId,
|
||||
// );
|
||||
|
||||
// if (success) {
|
||||
// emit(currentState.copyWith(schedules: updatedSchedules));
|
||||
// } else {
|
||||
// emit(currentState);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class ScheduleGetEvent extends ScheduleEvent {
|
||||
|
||||
class ScheduleAddEvent extends ScheduleEvent {
|
||||
final String category;
|
||||
final String time;
|
||||
final String time;
|
||||
final List<String> selectedDays;
|
||||
final bool functionOn;
|
||||
|
||||
@ -219,3 +219,12 @@ class DeleteScheduleEvent extends ScheduleEvent {
|
||||
@override
|
||||
List<Object> get props => [scheduleId];
|
||||
}
|
||||
|
||||
class StatusUpdatedScheduleEvent extends ScheduleEvent {
|
||||
final String id;
|
||||
|
||||
const StatusUpdatedScheduleEvent(this.id);
|
||||
|
||||
@override
|
||||
List<Object> get props => [id];
|
||||
}
|
||||
|
@ -160,28 +160,26 @@ class _ScheduleTableView extends StatelessWidget {
|
||||
children: [
|
||||
Center(
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
///TODO: Implement toggle functionality
|
||||
|
||||
// Toggle enabled state using ScheduleBloc
|
||||
// context.read<ScheduleBloc>().add(
|
||||
// UpdateScheduleEvent(
|
||||
// scheduleId: schedule.scheduleId,
|
||||
// functionOn: schedule.function.value,
|
||||
// enable: !schedule.enable,
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: schedule.enable
|
||||
? const Icon(Icons.radio_button_checked,
|
||||
color: ColorsManager.blueColor)
|
||||
: const Icon(
|
||||
Icons.radio_button_unchecked,
|
||||
color: ColorsManager.grayColor,
|
||||
context.read<ScheduleBloc>().add(
|
||||
ScheduleUpdateEntryEvent(
|
||||
scheduleId: schedule.scheduleId,
|
||||
functionOn: schedule.function.value,
|
||||
enable: !schedule.enable,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: 24,
|
||||
height: 24,
|
||||
child: schedule.enable
|
||||
? const Icon(Icons.radio_button_checked,
|
||||
color: ColorsManager.blueColor)
|
||||
: const Icon(Icons.radio_button_unchecked,
|
||||
color: ColorsManager.grayColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -202,7 +200,6 @@ class _ScheduleTableView extends StatelessWidget {
|
||||
schedule: ScheduleEntry.fromScheduleModel(schedule),
|
||||
isEdit: true,
|
||||
).then((updatedSchedule) {
|
||||
print('updatedSchedule : $updatedSchedule');
|
||||
if (updatedSchedule != null) {
|
||||
context.read<ScheduleBloc>().add(
|
||||
ScheduleEditEvent(
|
||||
@ -225,12 +222,38 @@ class _ScheduleTableView extends StatelessWidget {
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
||||
onPressed: () {
|
||||
context.read<ScheduleBloc>().add(
|
||||
DeleteScheduleEvent(
|
||||
schedule.scheduleId,
|
||||
),
|
||||
onPressed: () async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext dialogContext) {
|
||||
return AlertDialog(
|
||||
title: const Text('Confirm Delete'),
|
||||
content: const Text(
|
||||
'Are you sure you want to delete this schedule?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(dialogContext).pop(false),
|
||||
child: Text('Cancel'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
Navigator.of(dialogContext).pop(true),
|
||||
child: const Text(
|
||||
'Delete',
|
||||
style: TextStyle(color: Colors.red),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
if (confirmed == true) {
|
||||
context.read<ScheduleBloc>().add(
|
||||
ScheduleDeleteEvent(schedule.scheduleId),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
'Delete',
|
||||
@ -239,7 +262,7 @@ class _ScheduleTableView extends StatelessWidget {
|
||||
.bodySmall!
|
||||
.copyWith(color: ColorsManager.blueColor),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -248,7 +271,6 @@ class _ScheduleTableView extends StatelessWidget {
|
||||
}
|
||||
|
||||
String _getSelectedDays(List<bool> selectedDays) {
|
||||
// Use the same order as in ScheduleDialogHelper
|
||||
const days = ScheduleDialogHelper.allDays;
|
||||
return selectedDays
|
||||
.asMap()
|
||||
@ -257,6 +279,4 @@ class _ScheduleTableView extends StatelessWidget {
|
||||
.map((entry) => days[entry.key])
|
||||
.join(', ');
|
||||
}
|
||||
|
||||
// Removed allDays from here as it is now in ScheduleDialogHelper
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:core';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_reports.dart';
|
||||
@ -386,4 +387,34 @@ class DevicesManagementApi {
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<bool> postSchedule({
|
||||
required String category,
|
||||
required String deviceId,
|
||||
required String time,
|
||||
required String code,
|
||||
required bool value,
|
||||
required List<String> 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,
|
||||
},
|
||||
'days': days
|
||||
},
|
||||
),
|
||||
expectedResponseModel: (json) {
|
||||
return json['success'] ?? false;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -136,4 +136,5 @@ abstract class ApiEndpoints {
|
||||
|
||||
static const String assignDeviceToRoom =
|
||||
'/projects/{projectUuid}/communities/{communityUuid}/spaces/{spaceUuid}/subspaces/{subSpaceUuid}/devices/{deviceUuid}';
|
||||
static const String saveSchedule = '/schedule/{deviceUuid}';
|
||||
}
|
||||
|
Reference in New Issue
Block a user