Add countdown functionality and device type support across device management views

This commit is contained in:
mohammad
2025-06-30 15:05:59 +03:00
parent cf4bfc41f6
commit 289922071a
21 changed files with 292 additions and 179 deletions

View File

@ -11,6 +11,7 @@ class CountdownModeButtons extends StatelessWidget {
final String deviceId;
final int hours;
final int minutes;
final String countDownCode;
const CountdownModeButtons({
super.key,
@ -18,6 +19,7 @@ class CountdownModeButtons extends StatelessWidget {
required this.deviceId,
required this.hours,
required this.minutes,
required this.countDownCode,
});
@override
@ -43,6 +45,7 @@ class CountdownModeButtons extends StatelessWidget {
StopScheduleEvent(
mode: ScheduleModes.countdown,
deviceId: deviceId,
countdownCode: countDownCode,
),
);
},
@ -54,10 +57,10 @@ class CountdownModeButtons extends StatelessWidget {
onPressed: () {
context.read<ScheduleBloc>().add(
StartScheduleEvent(
mode: ScheduleModes.countdown,
hours: hours,
minutes: minutes,
),
mode: ScheduleModes.countdown,
hours: hours,
minutes: minutes,
countDownCode: countDownCode),
);
},
backgroundColor: ColorsManager.primaryColor,

View File

@ -75,23 +75,33 @@ class _CountdownInchingViewState extends State<CountdownInchingView> {
final isCountDown = state.scheduleMode == ScheduleModes.countdown;
final isActive =
isCountDown ? state.isCountdownActive : state.isInchingActive;
final displayHours = isActive && state.countdownRemaining != null
? state.countdownRemaining!.inHours
: (isCountDown ? state.countdownHours : state.inchingHours);
final displayMinutes = isActive && state.countdownRemaining != null
? state.countdownRemaining!.inMinutes.remainder(60)
: (isCountDown ? state.countdownMinutes : state.inchingMinutes);
final displaySeconds = isActive && state.countdownRemaining != null
? state.countdownRemaining!.inSeconds.remainder(60)
: (isCountDown ? state.countdownSeconds : state.inchingSeconds);
_updateControllers(displayHours, displayMinutes, displaySeconds!);
final displayHours =
isActive && state.countdownRemaining != Duration.zero
? state.countdownRemaining.inHours
: (isCountDown ? state.countdownHours : state.inchingHours);
if (displayHours == 0 && displayMinutes == 0 && displaySeconds == 0) {
final displayMinutes =
isActive && state.countdownRemaining != Duration.zero
? state.countdownRemaining.inMinutes.remainder(60)
: (isCountDown ? state.countdownMinutes : state.inchingMinutes);
final displaySeconds =
isActive && state.countdownRemaining != Duration.zero
? state.countdownRemaining.inSeconds.remainder(60)
: (isCountDown ? (state.countdownSeconds ?? 0) : 0);
_updateControllers(displayHours, displayMinutes, displaySeconds);
if (isActive &&
displayHours == 0 &&
displayMinutes == 0 &&
displaySeconds == 0) {
context.read<ScheduleBloc>().add(
StopScheduleEvent(
mode: ScheduleModes.countdown,
deviceId: widget.deviceId,
countdownCode: '',
),
);
}

View File

@ -43,7 +43,9 @@ class InchingModeButtons extends StatelessWidget {
onPressed: () {
context.read<ScheduleBloc>().add(
StopScheduleEvent(
deviceId: deviceId, mode: ScheduleModes.inching),
deviceId: deviceId,
mode: ScheduleModes.inching,
countdownCode: ''),
);
},
backgroundColor: Colors.red,

View File

@ -18,11 +18,15 @@ class BuildScheduleView extends StatelessWidget {
super.key,
required this.deviceUuid,
required this.category,
required this.countdownCode,
this.code,
required this.deviceType,
});
final String deviceUuid;
final String category;
final String? code;
final String? countdownCode;
final String deviceType;
@override
Widget build(BuildContext context) {
@ -31,7 +35,8 @@ class BuildScheduleView extends StatelessWidget {
deviceId: deviceUuid,
)
..add(ScheduleGetEvent(category: category))
..add(ScheduleFetchStatusEvent(deviceUuid)),
..add(ScheduleFetchStatusEvent(
deviceId: deviceUuid, countdownCode: countdownCode ?? '')),
child: Dialog(
backgroundColor: Colors.white,
insetPadding: const EdgeInsets.all(20),
@ -52,28 +57,32 @@ class BuildScheduleView extends StatelessWidget {
children: [
const ScheduleHeader(),
const SizedBox(height: 20),
ScheduleModeSelector(
currentMode: state.scheduleMode,
),
if (deviceType == 'CUR_2')
const SizedBox()
else
ScheduleModeSelector(
countdownCode: countdownCode ?? '',
currentMode: state.scheduleMode,
),
const SizedBox(height: 20),
if (state.scheduleMode == ScheduleModes.schedule)
ScheduleManagementUI(
deviceType: deviceType,
category: category,
deviceUuid: deviceUuid,
onAddSchedule: () async {
final entry = await ScheduleDialogHelper
.showAddScheduleDialog(
context,
schedule: ScheduleEntry(
category: category,
time: '',
function: Status(
code: code.toString(), value: null),
days: [],
),
isEdit: false,
code: code,
);
.showAddScheduleDialog(context,
schedule: ScheduleEntry(
category: category,
time: '',
function: Status(
code: code.toString(), value: null),
days: [],
),
isEdit: false,
code: code,
deviceType: deviceType);
if (entry != null) {
context.read<ScheduleBloc>().add(
ScheduleAddEvent(
@ -87,14 +96,16 @@ class BuildScheduleView extends StatelessWidget {
}
},
),
if (state.scheduleMode == ScheduleModes.countdown ||
state.scheduleMode == ScheduleModes.inching)
CountdownInchingView(
deviceId: deviceUuid,
),
if (deviceType != 'CUR_2')
if (state.scheduleMode == ScheduleModes.countdown ||
state.scheduleMode == ScheduleModes.inching)
CountdownInchingView(
deviceId: deviceUuid,
),
const SizedBox(height: 20),
if (state.scheduleMode == ScheduleModes.countdown)
CountdownModeButtons(
countDownCode: countdownCode ?? '',
isActive: state.isCountdownActive,
deviceId: deviceUuid,
hours: state.countdownHours,

View File

@ -5,14 +5,16 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class ScheduleManagementUI extends StatelessWidget {
final String deviceUuid;
final String deviceUuid;
final VoidCallback onAddSchedule;
final String category;
final String deviceType;
const ScheduleManagementUI({
super.key,
required this.deviceUuid,
required this.onAddSchedule,
required this.deviceType,
this.category = 'switch_1',
});
@ -44,7 +46,11 @@ class ScheduleManagementUI extends StatelessWidget {
),
),
const SizedBox(height: 20),
ScheduleTableWidget(deviceUuid: deviceUuid, category: category),
ScheduleTableWidget(
deviceUuid: deviceUuid,
category: category,
deviceType: deviceType,
),
],
);
}

View File

@ -7,10 +7,12 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
class ScheduleModeSelector extends StatelessWidget {
final ScheduleModes currentMode;
final String countdownCode;
const ScheduleModeSelector({
super.key,
required this.currentMode,
required this.countdownCode,
});
@override
@ -71,7 +73,8 @@ class ScheduleModeSelector extends StatelessWidget {
onChanged: (ScheduleModes? value) {
if (value != null) {
context.read<ScheduleBloc>().add(
UpdateScheduleModeEvent(scheduleMode: value),
UpdateScheduleModeEvent(
scheduleMode: value, countdownCode: countdownCode),
);
if (value == ScheduleModes.schedule) {
context.read<ScheduleBloc>().add(

View File

@ -12,11 +12,13 @@ import 'package:syncrow_web/utils/format_date_time.dart';
class ScheduleTableWidget extends StatelessWidget {
final String deviceUuid;
final String category;
final String deviceType;
const ScheduleTableWidget({
super.key,
required this.deviceUuid,
this.category = 'switch_1',
required this.deviceType,
});
@override
@ -25,13 +27,14 @@ class ScheduleTableWidget extends StatelessWidget {
create: (_) => ScheduleBloc(
deviceId: deviceUuid,
)..add(ScheduleGetEvent(category: category)),
child: _ScheduleTableView(),
child: _ScheduleTableView(deviceType),
);
}
}
class _ScheduleTableView extends StatelessWidget {
const _ScheduleTableView();
final String deviceType;
const _ScheduleTableView(this.deviceType);
@override
Widget build(BuildContext context) {
@ -81,7 +84,7 @@ class _ScheduleTableView extends StatelessWidget {
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20)),
),
child: _buildTableBody(state.schedules, context));
child: _buildTableBody(state.schedules, context, deviceType));
}
if (state is ScheduleError) {
return Center(child: Text(state.error));
@ -123,7 +126,8 @@ class _ScheduleTableView extends StatelessWidget {
);
}
Widget _buildTableBody(List<ScheduleModel> schedules, BuildContext context) {
Widget _buildTableBody(
List<ScheduleModel> schedules, BuildContext context, String deviceType) {
return SizedBox(
height: 200,
child: SingleChildScrollView(
@ -132,7 +136,8 @@ class _ScheduleTableView extends StatelessWidget {
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
for (int i = 0; i < schedules.length; i++)
_buildScheduleRow(schedules[i], i, context),
_buildScheduleRow(schedules[i], i, context,
deviceType: deviceType),
],
),
),
@ -155,25 +160,19 @@ class _ScheduleTableView extends StatelessWidget {
}
TableRow _buildScheduleRow(
ScheduleModel schedule, int index, BuildContext context) {
ScheduleModel schedule, int index, BuildContext context,
{required String deviceType}) {
return TableRow(
children: [
Center(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
bool temp;
if (schedule.category == 'CUR_2') {
temp = schedule.function.value == 'open' ? true : false;
} else {
temp = schedule.function.value as bool;
}
context.read<ScheduleBloc>().add(
ScheduleUpdateEntryEvent(
category: schedule.category,
scheduleId: schedule.scheduleId,
functionOn: temp,
// schedule.function.value,
functionOn: schedule.function.value,
enable: !schedule.enable,
),
);
@ -195,10 +194,11 @@ class _ScheduleTableView extends StatelessWidget {
child: Text(_getSelectedDays(
ScheduleModel.parseSelectedDays(schedule.days)))),
Center(child: Text(formatIsoStringToTime(schedule.time, context))),
schedule.category == 'CUR_2'
? Center(
child: Text(schedule.function.value == true ? 'open' : 'close'))
: Center(child: Text(schedule.function.value ? 'On' : 'Off')),
if (deviceType == 'CUR_2')
Center(
child: Text(schedule.function.value == true ? 'open' : 'close'))
else
Center(child: Text(schedule.function.value ? 'On' : 'Off')),
Center(
child: Wrap(
runAlignment: WrapAlignment.center,
@ -206,18 +206,28 @@ class _ScheduleTableView extends StatelessWidget {
TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.zero),
onPressed: () {
ScheduleDialogHelper.showAddScheduleDialog(
context,
schedule: ScheduleEntry.fromScheduleModel(schedule),
isEdit: true,
).then((updatedSchedule) {
ScheduleDialogHelper.showAddScheduleDialog(context,
schedule: ScheduleEntry.fromScheduleModel(schedule),
isEdit: true,
deviceType: deviceType)
.then((updatedSchedule) {
if (updatedSchedule != null) {
bool temp;
if (deviceType == 'CUR_2') {
updatedSchedule.function.value == 'open'
? temp = true
: temp = false;
} else {
temp = updatedSchedule.function.value;
}
print('deviceType $deviceType');
context.read<ScheduleBloc>().add(
ScheduleEditEvent(
deviceType: deviceType,
scheduleId: schedule.scheduleId,
category: schedule.category,
time: updatedSchedule.time,
functionOn: updatedSchedule.function.value,
functionOn: temp,
selectedDays: updatedSchedule.days),
);
}