Merge pull request #27 from SyncrowIOT/schedual_view

Schedual view
This commit is contained in:
Abdullah
2024-09-24 12:31:39 +03:00
committed by GitHub
12 changed files with 345 additions and 230 deletions

View File

@ -35,25 +35,15 @@ class TwoGangDeviceControlView extends StatelessWidget
} }
Widget _buildStatusControls(BuildContext context, TwoGangStatusModel status) { Widget _buildStatusControls(BuildContext context, TwoGangStatusModel status) {
final isExtraLarge = isExtraLargeScreenSize(context); return Center(
final isLarge = isLargeScreenSize(context); child: Wrap(
final isMedium = isMediumScreenSize(context); alignment: WrapAlignment.center,
return GridView( spacing: 12,
padding: const EdgeInsets.symmetric(horizontal: 50), runSpacing: 12,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: isLarge || isExtraLarge
? 3
: isMedium
? 2
: 1,
mainAxisExtent: 140,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
children: [ children: [
ToggleWidget( SizedBox(
width: 200,
child: ToggleWidget(
value: status.switch1, value: status.switch1,
code: 'switch_1', code: 'switch_1',
deviceId: deviceId, deviceId: deviceId,
@ -66,7 +56,10 @@ class TwoGangDeviceControlView extends StatelessWidget
)); ));
}, },
), ),
ToggleWidget( ),
SizedBox(
width: 200,
child: ToggleWidget(
value: status.switch2, value: status.switch2,
code: 'switch_2', code: 'switch_2',
deviceId: deviceId, deviceId: deviceId,
@ -79,7 +72,9 @@ class TwoGangDeviceControlView extends StatelessWidget
)); ));
}, },
), ),
),
], ],
),
); );
} }
} }

View File

@ -5,6 +5,7 @@ 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';
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';
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.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/pages/device_managment/water_heater/models/water_heater_status_model.dart'; import 'package:syncrow_web/pages/device_managment/water_heater/models/water_heater_status_model.dart';
import 'package:syncrow_web/services/devices_mang_api.dart'; import 'package:syncrow_web/services/devices_mang_api.dart';
@ -487,10 +488,8 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
emit(ScheduleLoadingState()); emit(ScheduleLoadingState());
try { try {
// List<ScheduleModel> schedules = await DevicesManagementApi() List<ScheduleModel> schedules = await DevicesManagementApi()
// .getDeviceSchedules(deviceStatus.uuid, event.category); .getDeviceSchedules(deviceStatus.uuid, event.category);
List<ScheduleModel> schedules = const [];
emit(WaterHeaterDeviceStatusLoaded( emit(WaterHeaterDeviceStatusLoaded(
deviceStatus, deviceStatus,
@ -513,7 +512,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
ScheduleModel newSchedule = ScheduleModel( ScheduleEntry newSchedule = ScheduleEntry(
category: event.category, category: event.category,
time: formatTimeOfDayToISO(event.time), time: formatTimeOfDayToISO(event.time),
function: Status(code: 'switch_1', value: event.functionOn), function: Status(code: 'switch_1', value: event.functionOn),
@ -526,10 +525,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
.addScheduleRecord(newSchedule, currentState.status.uuid); .addScheduleRecord(newSchedule, currentState.status.uuid);
if (success) { if (success) {
final updatedSchedules = add(GetSchedulesEvent(category: 'switch_1', uuid: deviceStatus.uuid));
List<ScheduleModel>.from(currentState.schedules)..add(newSchedule);
emit(currentState.copyWith(schedules: updatedSchedules));
} else { } else {
emit(currentState); emit(currentState);
//emit(const WaterHeaterFailedState(error: 'Failed to add schedule.')); //emit(const WaterHeaterFailedState(error: 'Failed to add schedule.'));
@ -544,23 +540,23 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
if (state is WaterHeaterDeviceStatusLoaded) { if (state is WaterHeaterDeviceStatusLoaded) {
final currentState = state as WaterHeaterDeviceStatusLoaded; final currentState = state as WaterHeaterDeviceStatusLoaded;
ScheduleModel updatedSchedule = currentState.schedules[event.index] final updatedSchedules = currentState.schedules.map((schedule) {
.copyWith( if (schedule.scheduleId == event.scheduleId) {
function: Status(code: 'switch_1', value: event.functionOn)); return schedule.copyWith(
function: Status(code: 'switch_1', value: event.functionOn),
// emit(ScheduleLoadingState()); enable: event.enable,
);
}
return schedule;
}).toList();
bool success = await DevicesManagementApi().updateScheduleRecord( bool success = await DevicesManagementApi().updateScheduleRecord(
enable: event.functionOn, enable: event.enable,
uuid: currentState.status.uuid, uuid: currentState.status.uuid,
scheduleId: event.scheduleId, scheduleId: event.scheduleId,
); );
if (success) { if (success) {
final updatedSchedules =
List<ScheduleModel>.from(currentState.schedules)
..[event.index] = updatedSchedule;
emit(currentState.copyWith(schedules: updatedSchedules)); emit(currentState.copyWith(schedules: updatedSchedules));
} else { } else {
emit(currentState); emit(currentState);
@ -582,9 +578,9 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
.deleteScheduleRecord(currentState.status.uuid, event.scheduleId); .deleteScheduleRecord(currentState.status.uuid, event.scheduleId);
if (success) { if (success) {
final updatedSchedules = final updatedSchedules = currentState.schedules
List<ScheduleModel>.from(currentState.schedules) .where((schedule) => schedule.scheduleId != event.scheduleId)
..removeAt(event.index); .toList();
emit(currentState.copyWith(schedules: updatedSchedules)); emit(currentState.copyWith(schedules: updatedSchedules));
} else { } else {

View File

@ -82,23 +82,22 @@ final class DeleteScheduleEvent extends WaterHeaterEvent {
} }
final class UpdateScheduleEntryEvent extends WaterHeaterEvent { final class UpdateScheduleEntryEvent extends WaterHeaterEvent {
final bool functionOn; final bool enable;
final String category; final dynamic functionOn;
final String deviceId; final String deviceId;
final int index; final int index;
final String scheduleId; final String scheduleId;
const UpdateScheduleEntryEvent({ const UpdateScheduleEntryEvent({
required this.enable,
required this.functionOn, required this.functionOn,
required this.category,
required this.deviceId, required this.deviceId,
required this.scheduleId, required this.scheduleId,
required this.index, required this.index,
}); });
@override @override
List<Object?> get props => List<Object?> get props => [enable, deviceId, scheduleId];
[category, functionOn, deviceId, scheduleId, index];
} }
class GetSchedulesEvent extends WaterHeaterEvent { class GetSchedulesEvent extends WaterHeaterEvent {

View File

@ -118,7 +118,7 @@ class ScheduleDialogHelper {
_buildDayCheckboxes(context, state.selectedDays, _buildDayCheckboxes(context, state.selectedDays,
isEdit: isEdit), isEdit: isEdit),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildFunctionSwitch(context, state.functionOn), _buildFunctionSwitch(context, state.functionOn, isEdit),
], ],
), ),
actions: [ actions: [
@ -143,16 +143,10 @@ class ScheduleDialogHelper {
onPressed: () { onPressed: () {
if (state.selectedTime != null) { if (state.selectedTime != null) {
if (state.isEditing && index != null) { if (state.isEditing && index != null) {
bloc.add(UpdateScheduleEntryEvent( return;
index: index,
deviceId: state.status.uuid,
category: 'kg',
functionOn: state.functionOn,
scheduleId: state.schedules[index].scheduleId,
));
} else { } else {
bloc.add(AddScheduleEvent( bloc.add(AddScheduleEvent(
category: 'kg', category: 'switch_1',
time: state.selectedTime!, time: state.selectedTime!,
selectedDays: state.selectedDays, selectedDays: state.selectedDays,
functionOn: state.functionOn, functionOn: state.functionOn,
@ -177,8 +171,15 @@ class ScheduleDialogHelper {
} }
static TimeOfDay _convertStringToTimeOfDay(String timeString) { static TimeOfDay _convertStringToTimeOfDay(String timeString) {
final DateTime dateTime = DateTime.parse(timeString); final regex = RegExp(r'^(\d{2}):(\d{2})$');
return TimeOfDay(hour: dateTime.hour, minute: dateTime.minute); final match = regex.firstMatch(timeString);
if (match != null) {
final hour = int.parse(match.group(1)!);
final minute = int.parse(match.group(2)!);
return TimeOfDay(hour: hour, minute: minute);
} else {
throw const FormatException('Invalid time format');
}
} }
static List<bool> _convertDaysStringToBooleans(List<String> selectedDays) { static List<bool> _convertDaysStringToBooleans(List<String> selectedDays) {
@ -220,7 +221,8 @@ class ScheduleDialogHelper {
); );
} }
static Widget _buildFunctionSwitch(BuildContext context, bool isOn) { static Widget _buildFunctionSwitch(
BuildContext context, bool isOn, bool? isEdit) {
return Row( return Row(
children: [ children: [
Text( Text(
@ -233,9 +235,13 @@ class ScheduleDialogHelper {
value: true, value: true,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) {
return;
} else {
context context
.read<WaterHeaterBloc>() .read<WaterHeaterBloc>()
.add(const UpdateFunctionOnEvent(true)); .add(const UpdateFunctionOnEvent(true));
}
}, },
), ),
const Text('On'), const Text('On'),
@ -244,9 +250,13 @@ class ScheduleDialogHelper {
value: false, value: false,
groupValue: isOn, groupValue: isOn,
onChanged: (bool? value) { onChanged: (bool? value) {
if (isEdit == true) {
return;
} else {
context context
.read<WaterHeaterBloc>() .read<WaterHeaterBloc>()
.add(const UpdateFunctionOnEvent(false)); .add(const UpdateFunctionOnEvent(false));
}
}, },
), ),
const Text('Off'), const Text('Off'),

View File

@ -1,19 +1,80 @@
// import 'package:flutter/material.dart'; import 'dart:convert';
// class ScheduleEntry { import 'package:flutter/foundation.dart';
// final List<bool> selectedDays;
// final TimeOfDay time;
// final bool functionOn;
// final String category;
// ScheduleEntry({ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
// required this.selectedDays,
// required this.time,
// required this.functionOn,
// required this.category,
// });
// @override class ScheduleEntry {
// String toString() => final String category;
// 'ScheduleEntry(selectedDays: $selectedDays, time: $time, functionOn: $functionOn)'; final String time;
// } final Status function;
final List<String> days;
ScheduleEntry({
required this.category,
required this.time,
required this.function,
required this.days,
});
@override
String toString() {
return 'ScheduleEntry(category: $category, time: $time, function: $function, days: $days)';
}
ScheduleEntry copyWith({
String? category,
String? time,
Status? function,
List<String>? days,
}) {
return ScheduleEntry(
category: category ?? this.category,
time: time ?? this.time,
function: function ?? this.function,
days: days ?? this.days,
);
}
Map<String, dynamic> toMap() {
return {
'category': category,
'time': time,
'function': function.toMap(),
'days': days,
};
}
factory ScheduleEntry.fromMap(Map<String, dynamic> map) {
return ScheduleEntry(
category: map['category'] ?? '',
time: map['time'] ?? '',
function: Status.fromMap(map['function']),
days: List<String>.from(map['days']),
);
}
String toJson() => json.encode(toMap());
factory ScheduleEntry.fromJson(String source) =>
ScheduleEntry.fromMap(json.decode(source));
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ScheduleEntry &&
other.category == category &&
other.time == time &&
other.function == function &&
listEquals(other.days, days);
}
@override
int get hashCode {
return category.hashCode ^
time.hashCode ^
function.hashCode ^
days.hashCode;
}
}

View File

@ -9,25 +9,30 @@ class ScheduleModel {
final String time; final String time;
final Status function; final Status function;
final List<String> days; final List<String> days;
final TimeOfDay? timeOfDay;
final List<bool>? selectedDays; final List<bool>? selectedDays;
final String timezoneId;
final bool enable;
ScheduleModel({ ScheduleModel({
required this.scheduleId,
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.timeOfDay,
this.selectedDays, this.selectedDays,
this.scheduleId = '', required this.timezoneId,
required this.enable,
}); });
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(),
'days': days, 'days': days,
'timezoneId': timezoneId,
'enable': enable,
}; };
} }
@ -37,11 +42,11 @@ class ScheduleModel {
category: map['category'] ?? '', category: map['category'] ?? '',
time: map['time'] ?? '', time: map['time'] ?? '',
function: Status.fromMap(map['function']), function: Status.fromMap(map['function']),
days: List<String>.from(map['days']), days: List<String>.from(map['days'].map((e) => e.toString())),
timeOfDay: timezoneId: map['timezoneId'] ?? '',
parseTimeOfDay(map['time']), enable: map['enable'] ?? false,
selectedDays: selectedDays: parseSelectedDays(
parseSelectedDays(map['days']), List<String>.from(map['days'].map((e) => e.toString()))),
); );
} }
@ -51,22 +56,24 @@ class ScheduleModel {
ScheduleModel.fromMap(json.decode(source)); ScheduleModel.fromMap(json.decode(source));
ScheduleModel copyWith({ ScheduleModel copyWith({
String? scheduleId,
String? category, String? category,
String? time, String? time,
Status? function, Status? function,
List<String>? days, List<String>? days,
TimeOfDay? timeOfDay,
List<bool>? selectedDays, List<bool>? selectedDays,
String? scheduleId, String? timezoneId,
bool? enable,
}) { }) {
return ScheduleModel( return ScheduleModel(
scheduleId: scheduleId ?? this.scheduleId,
category: category ?? this.category, category: category ?? this.category,
time: time ?? this.time, time: time ?? this.time,
function: function ?? this.function, function: function ?? this.function,
days: days ?? this.days, days: days ?? this.days,
timeOfDay: timeOfDay ?? this.timeOfDay,
selectedDays: selectedDays ?? this.selectedDays, selectedDays: selectedDays ?? this.selectedDays,
scheduleId: scheduleId ?? this.scheduleId, timezoneId: timezoneId ?? this.timezoneId,
enable: enable ?? this.enable,
); );
} }
@ -97,7 +104,7 @@ class ScheduleModel {
@override @override
String toString() { String toString() {
return 'ScheduleModel(category: $category, time: $time, function: $function, days: $days, timeOfDay: $timeOfDay, selectedDays: $selectedDays)'; return 'ScheduleModel(category: $category, time: $time, function: $function, days: $days, selectedDays: $selectedDays)';
} }
@override @override
@ -109,7 +116,7 @@ class ScheduleModel {
other.time == time && other.time == time &&
other.function == function && other.function == function &&
listEquals(other.days, days) && listEquals(other.days, days) &&
timeOfDay == other.timeOfDay && // timeOfDay == other.timeOfDay &&
listEquals(other.selectedDays, selectedDays); listEquals(other.selectedDays, selectedDays);
} }
@ -119,7 +126,7 @@ class ScheduleModel {
time.hashCode ^ time.hashCode ^
function.hashCode ^ function.hashCode ^
days.hashCode ^ days.hashCode ^
timeOfDay.hashCode ^ // timeOfDay.hashCode ^
selectedDays.hashCode; selectedDays.hashCode;
} }
} }

View File

@ -56,8 +56,7 @@ class _BuildScheduleViewState extends State<BuildScheduleView> {
context, context,
schedule: null, schedule: null,
index: null, index: null,
isEdit: false isEdit: false),
),
), ),
if (state.scheduleMode == ScheduleModes.countdown || if (state.scheduleMode == ScheduleModes.countdown ||
state.scheduleMode == ScheduleModes.inching) state.scheduleMode == ScheduleModes.inching)
@ -80,15 +79,31 @@ class _BuildScheduleViewState extends State<BuildScheduleView> {
if (state.scheduleMode != ScheduleModes.countdown && if (state.scheduleMode != ScheduleModes.countdown &&
state.scheduleMode != ScheduleModes.inching) state.scheduleMode != ScheduleModes.inching)
ScheduleModeButtons( ScheduleModeButtons(
onSave: () {}, onSave: () {
Navigator.pop(context);
},
), ),
], ],
); );
} }
if (state is WaterHeaterLoadingState) { if (state is WaterHeaterLoadingState) {
return const Center(child: CircularProgressIndicator()); return const SizedBox(
height: 200,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ScheduleHeader(),
SizedBox(
height: 20,
),
Center(child: CircularProgressIndicator()),
],
));
} }
return const SizedBox(); return const SizedBox(
height: 200,
child: ScheduleHeader(),
);
}, },
), ),
), ),

View File

@ -72,7 +72,7 @@ class ScheduleModeSelector extends StatelessWidget {
if (value == ScheduleModes.schedule) { if (value == ScheduleModes.schedule) {
context.read<WaterHeaterBloc>().add( context.read<WaterHeaterBloc>().add(
GetSchedulesEvent( GetSchedulesEvent(
category: 'kg', category: 'switch_1',
uuid: state.status.uuid, uuid: state.status.uuid,
), ),
); );

View File

@ -1,76 +1,76 @@
import 'package:flutter/material.dart'; // import 'package:flutter/material.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/format_date_time.dart'; // import 'package:syncrow_web/utils/format_date_time.dart';
import 'package:syncrow_web/utils/color_manager.dart'; // import 'package:syncrow_web/utils/color_manager.dart';
class ScheduleRowWidget extends StatelessWidget { // class ScheduleRowWidget extends StatelessWidget {
final ScheduleModel schedule; // final ScheduleModel schedule;
final int index; // final int index;
final Function onEdit; // final Function onEdit;
final Function onDelete; // final Function onDelete;
const ScheduleRowWidget({ // const ScheduleRowWidget({
super.key, // super.key,
required this.schedule, // required this.schedule,
required this.index, // required this.index,
required this.onEdit, // required this.onEdit,
required this.onDelete, // required this.onDelete,
}); // });
@override // @override
Widget build(BuildContext context) { // Widget build(BuildContext context) {
return Table( // return Table(
border: TableBorder.all(color: ColorsManager.graysColor), // border: TableBorder.all(color: ColorsManager.graysColor),
defaultVerticalAlignment: TableCellVerticalAlignment.middle, // defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [ // children: [
TableRow( // TableRow(
children: [ // children: [
Center( // Center(
child: schedule.function.value // child: schedule.enable
? const Icon(Icons.radio_button_checked, // ? const Icon(Icons.radio_button_checked,
color: ColorsManager.blueColor) // color: ColorsManager.blueColor)
: const Icon(Icons.radio_button_unchecked), // : const Icon(Icons.radio_button_unchecked),
), // ),
Center(child: Text(_getSelectedDays(schedule.selectedDays ?? []))), // Center(child: Text(_getSelectedDays(schedule.selectedDays ?? []))),
Center(child: Text(formatIsoStringToTime(schedule.time))), // Center(child: Text(formatIsoStringToTime(schedule.time, context))),
Center(child: Text(schedule.function.value ? 'On' : 'Off')), // Center(child: Text(schedule.enable ? 'On' : 'Off')),
Center( // Center(
child: Wrap( // child: Wrap(
runAlignment: WrapAlignment.center, // runAlignment: WrapAlignment.center,
children: [ // children: [
TextButton( // TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.zero), // style: TextButton.styleFrom(padding: EdgeInsets.zero),
onPressed: () => onEdit(), // onPressed: () => onEdit(),
child: const Text( // child: const Text(
'Edit', // 'Edit',
style: TextStyle(color: ColorsManager.blueColor), // style: TextStyle(color: ColorsManager.blueColor),
), // ),
), // ),
TextButton( // TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.zero), // style: TextButton.styleFrom(padding: EdgeInsets.zero),
onPressed: () => onDelete(), // onPressed: () => onDelete(),
child: const Text( // child: const Text(
'Delete', // 'Delete',
style: TextStyle(color: ColorsManager.blueColor), // style: TextStyle(color: ColorsManager.blueColor),
), // ),
), // ),
], // ],
), // ),
), // ),
], // ],
), // ),
], // ],
); // );
} // }
String _getSelectedDays(List<bool> selectedDays) { // String _getSelectedDays(List<bool> selectedDays) {
final days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; // final days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
List<String> selectedDaysStr = []; // List<String> selectedDaysStr = [];
for (int i = 0; i < selectedDays.length; i++) { // for (int i = 0; i < selectedDays.length; i++) {
if (selectedDays[i]) { // if (selectedDays[i]) {
selectedDaysStr.add(days[i]); // selectedDaysStr.add(days[i]);
} // }
} // }
return selectedDaysStr.join(', '); // return selectedDaysStr.join(', ');
} // }
} // }

View File

@ -68,7 +68,9 @@ class ScheduleTableWidget extends StatelessWidget {
), ),
child: _buildTableBody(state, context)); child: _buildTableBody(state, context));
} }
return const SizedBox(); return const SizedBox(
height: 200,
);
}, },
), ),
], ],
@ -107,15 +109,18 @@ class ScheduleTableWidget extends StatelessWidget {
Widget _buildTableBody( Widget _buildTableBody(
WaterHeaterDeviceStatusLoaded state, BuildContext context) { WaterHeaterDeviceStatusLoaded state, BuildContext context) {
return SingleChildScrollView( return SizedBox(
height: 200,
child: SingleChildScrollView(
child: Table( child: Table(
border: TableBorder.all(color: ColorsManager.graysColor), border: TableBorder.all(color: ColorsManager.graysColor),
defaultVerticalAlignment: TableCellVerticalAlignment.middle, defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [ children: [
for (int i = 0; i < state.schedules.length; i++) for (int i = 0; i < state.schedules.length; i++)
_buildScheduleRow(state.schedules[i], i, context), _buildScheduleRow(state.schedules[i], i, context, state),
], ],
), ),
),
); );
} }
@ -134,19 +139,38 @@ class ScheduleTableWidget extends StatelessWidget {
); );
} }
TableRow _buildScheduleRow( TableRow _buildScheduleRow(ScheduleModel schedule, int index,
ScheduleModel schedule, int index, BuildContext context) { BuildContext context, WaterHeaterDeviceStatusLoaded state) {
return TableRow( return TableRow(
children: [ children: [
Center( Center(
child: schedule.function.value child: GestureDetector(
onTap: () {
context.read<WaterHeaterBloc>().add(UpdateScheduleEntryEvent(
index: index,
enable: !schedule.enable,
scheduleId: schedule.scheduleId,
deviceId: state.status.uuid,
functionOn: schedule.function.value,
));
},
child: SizedBox(
width: 24,
height: 24,
child: schedule.enable
? const Icon(Icons.radio_button_checked, ? const Icon(Icons.radio_button_checked,
color: ColorsManager.blueColor) color: ColorsManager.blueColor)
: const Icon(Icons.radio_button_unchecked)), : const Icon(
Icons.radio_button_unchecked,
color: ColorsManager.grayColor,
),
),
),
),
Center( Center(
child: Text(_getSelectedDays( child: Text(_getSelectedDays(
ScheduleModel.parseSelectedDays(schedule.days)))), ScheduleModel.parseSelectedDays(schedule.days)))),
Center(child: Text(formatIsoStringToTime(schedule.time))), Center(child: Text(formatIsoStringToTime(schedule.time, context))),
Center(child: Text(schedule.function.value ? 'On' : 'Off')), Center(child: Text(schedule.function.value ? 'On' : 'Off')),
Center( Center(
child: Wrap( child: Wrap(

View File

@ -3,6 +3,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/device_rep
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';
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
import 'package:syncrow_web/pages/device_managment/water_heater/models/schedule_entry.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/pages/visitor_password/model/device_model.dart'; import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/services/api/http_service.dart';
@ -179,7 +180,7 @@ class DevicesManagementApi {
} }
Future<bool> addScheduleRecord( Future<bool> addScheduleRecord(
ScheduleModel sendSchedule, String uuid) async { ScheduleEntry sendSchedule, String uuid) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid), path: ApiEndpoints.scheduleByDeviceId.replaceAll('{deviceUuid}', uuid),
@ -200,14 +201,14 @@ class DevicesManagementApi {
String uuid, String category) async { String uuid, String category) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: ApiEndpoints.scheduleByDeviceId path: ApiEndpoints.getScheduleByDeviceId
.replaceAll('{deviceUuid}', uuid) .replaceAll('{deviceUuid}', uuid)
.replaceAll('{category}', category), .replaceAll('{category}', category),
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
List<ScheduleModel> schedules = []; List<ScheduleModel> schedules = [];
for (var schedule in json['schedules']) { for (var schedule in json) {
schedules.add(ScheduleModel.fromJson(schedule)); schedules.add(ScheduleModel.fromMap(schedule));
} }
return schedules; return schedules;
}, },
@ -225,7 +226,7 @@ class DevicesManagementApi {
required String scheduleId}) async { required String scheduleId}) async {
try { try {
final response = await HTTPService().put( final response = await HTTPService().put(
path: ApiEndpoints.scheduleByDeviceId path: ApiEndpoints.updateScheduleByDeviceId
.replaceAll('{deviceUuid}', uuid) .replaceAll('{deviceUuid}', uuid)
.replaceAll('{scheduleUuid}', scheduleId), .replaceAll('{scheduleUuid}', scheduleId),
body: { body: {
@ -246,7 +247,7 @@ class DevicesManagementApi {
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(
path: ApiEndpoints.scheduleByDeviceId path: ApiEndpoints.deleteScheduleByDeviceId
.replaceAll('{deviceUuid}', uuid) .replaceAll('{deviceUuid}', uuid)
.replaceAll('{scheduleUuid}', scheduleId), .replaceAll('{scheduleUuid}', scheduleId),
showServerMessage: true, showServerMessage: true,

View File

@ -25,7 +25,14 @@ String formatTimeOfDayToISO(TimeOfDay time, {DateTime? currentDate}) {
return dateTime.toUtc().toIso8601String(); return dateTime.toUtc().toIso8601String();
} }
String formatIsoStringToTime(String isoString) { String formatIsoStringToTime(String isoString, BuildContext context) {
final dateTime = DateTime.parse(isoString); try {
return DateFormat('hh:mm a').format(dateTime); final parts = isoString.split(':');
final hour = int.parse(parts[0]);
final minute = int.parse(parts[1]);
final timeOfDay = TimeOfDay(hour: hour, minute: minute);
return timeOfDay.format(context);
} catch (e) {
return isoString;
}
} }