mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 15:17:31 +00:00
start working on scheduling
This commit is contained in:
@ -12,6 +12,7 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
WaterHeaterBloc() : super(WaterHeaterInitial()) {
|
WaterHeaterBloc() : super(WaterHeaterInitial()) {
|
||||||
on<WaterHeaterFetchStatusEvent>(_fetchWaterHeaterStatus);
|
on<WaterHeaterFetchStatusEvent>(_fetchWaterHeaterStatus);
|
||||||
on<ToggleWaterHeaterEvent>(_controlWaterHeater);
|
on<ToggleWaterHeaterEvent>(_controlWaterHeater);
|
||||||
|
on<ShowScheduleViewEvent>(_showScheduleView);
|
||||||
on<UpdateScheduleEvent>(_updateScheduleEvent);
|
on<UpdateScheduleEvent>(_updateScheduleEvent);
|
||||||
on<StopScheduleEvent>(_stopScheduleEvent);
|
on<StopScheduleEvent>(_stopScheduleEvent);
|
||||||
}
|
}
|
||||||
@ -23,14 +24,24 @@ class WaterHeaterBloc extends Bloc<WaterHeaterEvent, WaterHeaterState> {
|
|||||||
UpdateScheduleEvent event,
|
UpdateScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
) {
|
) {
|
||||||
emit(WaterHeaterScheduleState(
|
emit(WaterHeaterScheduleViewState(
|
||||||
scheduleType: event.scheduleType,
|
scheduleMode: event.scheduleMode,
|
||||||
hours: event.hours,
|
hours: event.hours,
|
||||||
minutes: event.minutes,
|
minutes: event.minutes,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FutureOr<void> _showScheduleView(
|
||||||
|
ShowScheduleViewEvent event, Emitter<WaterHeaterState> emit) {
|
||||||
|
emit(const WaterHeaterScheduleViewState(
|
||||||
|
scheduleMode: ScheduleModes.countdown,
|
||||||
|
hours: 6,
|
||||||
|
minutes: 23,
|
||||||
|
isActive: false,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
FutureOr<void> _stopScheduleEvent(
|
FutureOr<void> _stopScheduleEvent(
|
||||||
StopScheduleEvent event,
|
StopScheduleEvent event,
|
||||||
Emitter<WaterHeaterState> emit,
|
Emitter<WaterHeaterState> emit,
|
||||||
|
@ -18,14 +18,15 @@ final class ToggleWaterHeaterEvent extends WaterHeaterEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class UpdateScheduleEvent extends WaterHeaterEvent {
|
final class UpdateScheduleEvent extends WaterHeaterEvent {
|
||||||
final ScheduleType scheduleType;
|
final ScheduleModes scheduleMode;
|
||||||
final int hours;
|
final int hours;
|
||||||
final int minutes;
|
final int minutes;
|
||||||
|
|
||||||
const UpdateScheduleEvent(this.scheduleType, this.hours, this.minutes);
|
const UpdateScheduleEvent(
|
||||||
|
{required this.scheduleMode, required this.hours, required this.minutes});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [scheduleType, hours, minutes];
|
List<Object?> get props => [scheduleMode, hours, minutes];
|
||||||
}
|
}
|
||||||
|
|
||||||
final class StopScheduleEvent extends WaterHeaterEvent {}
|
final class StopScheduleEvent extends WaterHeaterEvent {}
|
||||||
@ -47,3 +48,7 @@ class WaterHeaterFetchBatchStatusEvent extends WaterHeaterEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [deviceId];
|
List<Object?> get props => [deviceId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShowScheduleViewEvent extends WaterHeaterEvent {
|
||||||
|
const ShowScheduleViewEvent();
|
||||||
|
}
|
||||||
|
@ -21,7 +21,7 @@ final class WaterHeaterToggleState extends WaterHeaterState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class WaterHeaterScheduleState extends WaterHeaterState {
|
final class WaterHeaterScheduleState extends WaterHeaterState {
|
||||||
final ScheduleType scheduleType;
|
final ScheduleModes scheduleType;
|
||||||
final int hours;
|
final int hours;
|
||||||
final int minutes;
|
final int minutes;
|
||||||
final bool isActive;
|
final bool isActive;
|
||||||
@ -74,3 +74,20 @@ final class WaterHeaterBatchFailedState extends WaterHeaterState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final class WaterHeaterLoadingState extends WaterHeaterState {}
|
final class WaterHeaterLoadingState extends WaterHeaterState {}
|
||||||
|
|
||||||
|
class WaterHeaterScheduleViewState extends WaterHeaterState {
|
||||||
|
final ScheduleModes scheduleMode;
|
||||||
|
final int hours;
|
||||||
|
final int minutes;
|
||||||
|
final bool isActive;
|
||||||
|
|
||||||
|
const WaterHeaterScheduleViewState({
|
||||||
|
required this.scheduleMode,
|
||||||
|
required this.hours,
|
||||||
|
required this.minutes,
|
||||||
|
required this.isActive,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Object> get props => [scheduleMode, hours, minutes];
|
||||||
|
}
|
||||||
|
@ -28,6 +28,8 @@ class WaterHeaterDeviceControl extends StatelessWidget
|
|||||||
return const Center(child: CircularProgressIndicator());
|
return const Center(child: CircularProgressIndicator());
|
||||||
} else if (state is WaterHeaterDeviceStatusLoaded) {
|
} else if (state is WaterHeaterDeviceStatusLoaded) {
|
||||||
return _buildStatusControls(context, state.status);
|
return _buildStatusControls(context, state.status);
|
||||||
|
} else if (state is WaterHeaterScheduleViewState) {
|
||||||
|
return _buildScheduleView(context, state);
|
||||||
} else if (state is WaterHeaterFailedState ||
|
} else if (state is WaterHeaterFailedState ||
|
||||||
state is WaterHeaterBatchFailedState) {
|
state is WaterHeaterBatchFailedState) {
|
||||||
return const Center(child: Text('Error fetching status'));
|
return const Center(child: Text('Error fetching status'));
|
||||||
@ -66,39 +68,223 @@ class WaterHeaterDeviceControl extends StatelessWidget
|
|||||||
));
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
DeviceControlsContainer(
|
GestureDetector(
|
||||||
child: Column(
|
onTap: () {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
context.read<WaterHeaterBloc>().add(const ShowScheduleViewEvent());
|
||||||
children: [
|
},
|
||||||
Container(
|
child: DeviceControlsContainer(
|
||||||
width: 60,
|
child: Column(
|
||||||
height: 60,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
decoration: const BoxDecoration(
|
children: [
|
||||||
shape: BoxShape.circle,
|
Container(
|
||||||
color: ColorsManager.whiteColors,
|
width: 60,
|
||||||
),
|
height: 60,
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
decoration: const BoxDecoration(
|
||||||
padding: const EdgeInsets.all(12),
|
shape: BoxShape.circle,
|
||||||
child: ClipOval(
|
color: ColorsManager.whiteColors,
|
||||||
child: SvgPicture.asset(
|
),
|
||||||
Assets.scheduling,
|
margin: const EdgeInsets.symmetric(horizontal: 4),
|
||||||
fit: BoxFit.fill,
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: ClipOval(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.scheduling,
|
||||||
|
fit: BoxFit.fill,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const Spacer(),
|
||||||
const Spacer(),
|
Text(
|
||||||
Text(
|
'Scheduling',
|
||||||
'Scheduling',
|
textAlign: TextAlign.center,
|
||||||
textAlign: TextAlign.center,
|
style: context.textTheme.titleMedium!.copyWith(
|
||||||
style: context.textTheme.titleMedium!.copyWith(
|
fontWeight: FontWeight.w400,
|
||||||
fontWeight: FontWeight.w400,
|
color: ColorsManager.blackColor,
|
||||||
color: ColorsManager.blackColor,
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildScheduleView(
|
||||||
|
BuildContext context, WaterHeaterScheduleViewState state) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Scheduling',
|
||||||
|
style: context.textTheme.titleLarge!.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: ColorsManager.dialogBlueTitle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: ListTile(
|
||||||
|
title: const Text('Countdown'),
|
||||||
|
leading: Radio<ScheduleModes>(
|
||||||
|
value: ScheduleModes.countdown,
|
||||||
|
groupValue: state.scheduleMode,
|
||||||
|
onChanged: (ScheduleModes? value) {
|
||||||
|
if (value != null) {
|
||||||
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
||||||
|
scheduleMode: value,
|
||||||
|
hours: state.hours,
|
||||||
|
minutes: state.minutes,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListTile(
|
||||||
|
title: const Text('Schedule'),
|
||||||
|
leading: Radio<ScheduleModes>(
|
||||||
|
value: ScheduleModes.schedule,
|
||||||
|
groupValue: state.scheduleMode,
|
||||||
|
onChanged: (ScheduleModes? value) {
|
||||||
|
if (value != null) {
|
||||||
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
||||||
|
scheduleMode: value,
|
||||||
|
hours: state.hours,
|
||||||
|
minutes: state.minutes,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListTile(
|
||||||
|
title: const Text('Circulate'),
|
||||||
|
leading: Radio<ScheduleModes>(
|
||||||
|
value: ScheduleModes.circulate,
|
||||||
|
groupValue: state.scheduleMode,
|
||||||
|
onChanged: (ScheduleModes? value) {
|
||||||
|
if (value != null) {
|
||||||
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
||||||
|
scheduleMode: value,
|
||||||
|
hours: state.hours,
|
||||||
|
minutes: state.minutes,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListTile(
|
||||||
|
title: const Text('Inching'),
|
||||||
|
leading: Radio<ScheduleModes>(
|
||||||
|
value: ScheduleModes.inching,
|
||||||
|
groupValue: state.scheduleMode,
|
||||||
|
onChanged: (ScheduleModes? value) {
|
||||||
|
if (value != null) {
|
||||||
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
||||||
|
scheduleMode: value,
|
||||||
|
hours: state.hours,
|
||||||
|
minutes: state.minutes,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
if (state.scheduleMode == ScheduleModes.countdown ||
|
||||||
|
state.scheduleMode == ScheduleModes.inching) ...[
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
// Hours input
|
||||||
|
_buildTimeInputField(
|
||||||
|
label: 'h',
|
||||||
|
initialValue: state.hours.toString(),
|
||||||
|
onChanged: (value) {
|
||||||
|
int hours = int.tryParse(value) ?? 0;
|
||||||
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
||||||
|
scheduleMode: state.scheduleMode,
|
||||||
|
hours: hours,
|
||||||
|
minutes: state.minutes,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
// Minutes input
|
||||||
|
_buildTimeInputField(
|
||||||
|
label: 'm',
|
||||||
|
initialValue: state.minutes.toString(),
|
||||||
|
onChanged: (value) {
|
||||||
|
int minutes = int.tryParse(value) ?? 0;
|
||||||
|
context.read<WaterHeaterBloc>().add(UpdateScheduleEvent(
|
||||||
|
scheduleMode: state.scheduleMode,
|
||||||
|
hours: state.hours,
|
||||||
|
minutes: minutes,
|
||||||
|
));
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context)
|
||||||
|
.pop(); // Close the dialog or scheduling view
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.grey[400],
|
||||||
|
),
|
||||||
|
child: const Text('Cancel'),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 20),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
// Handle saving schedule logic
|
||||||
|
},
|
||||||
|
child: const Text('Save'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildTimeInputField({
|
||||||
|
required String label,
|
||||||
|
required String initialValue,
|
||||||
|
required Function(String) onChanged,
|
||||||
|
}) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Text(label, style: const TextStyle(fontSize: 18)),
|
||||||
|
SizedBox(
|
||||||
|
width: 50,
|
||||||
|
child: TextField(
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
decoration: const InputDecoration(border: UnderlineInputBorder()),
|
||||||
|
onChanged: onChanged,
|
||||||
|
controller: TextEditingController(text: initialValue),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user