mirror of
https://github.com/SyncrowIOT/syncrow-app.git
synced 2026-10-25 03:27:56 +00:00
count_down_ac
This commit is contained in:
@@ -14,6 +14,7 @@ import 'package:syncrow_app/utils/resource_manager/constants.dart';
|
||||
class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
final String acId;
|
||||
AcStatusModel deviceStatus = AcStatusModel(
|
||||
countdown1: 0,
|
||||
uuid: '',
|
||||
acSwitch: true,
|
||||
modeString: 'hot',
|
||||
@@ -41,6 +42,12 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
on<IncreaseAllTemp>(_increaseAllTemp);
|
||||
on<DecreaseAllTemp>(_decreaseAllTemp);
|
||||
on<AcUpdated>(_onAcUpdated);
|
||||
on<OnClose>(_onClose);
|
||||
on<GetCounterEvent>(_getCounterValue);
|
||||
on<SetCounterValue>(_setCounterValue);
|
||||
on<TickTimer>(_onTickTimer);
|
||||
|
||||
// on<SetTimeOutValue>(_setTimeOutAlarm);
|
||||
}
|
||||
|
||||
void _fetchAcsStatus(AcsInitial event, Emitter<AcsState> emit) async {
|
||||
@@ -61,7 +68,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
for (var status in response['status']) {
|
||||
statusModelList.add(StatusModel.fromJson(status));
|
||||
}
|
||||
deviceStatus = AcStatusModel.fromJson(response['productUuid'], statusModelList);
|
||||
deviceStatus =
|
||||
AcStatusModel.fromJson(response['productUuid'], statusModelList);
|
||||
emit(GetAcStatusState(acStatusModel: deviceStatus));
|
||||
Future.delayed(const Duration(milliseconds: 500));
|
||||
// _listenToChanges();
|
||||
@@ -74,18 +82,22 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
|
||||
_listenToChanges() {
|
||||
try {
|
||||
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$acId');
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$acId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) {
|
||||
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
List<StatusModel> statusList = [];
|
||||
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList.add(StatusModel(code: element['code'], value: element['value']));
|
||||
statusList
|
||||
.add(StatusModel(code: element['code'], value: element['value']));
|
||||
});
|
||||
|
||||
deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
deviceStatus =
|
||||
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||
add(AcUpdated());
|
||||
});
|
||||
} catch (_) {}
|
||||
@@ -102,12 +114,14 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
HomeCubit.getInstance().selectedSpace?.id ?? '', 'AC');
|
||||
|
||||
for (int i = 0; i < devicesList.length; i++) {
|
||||
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
|
||||
var response =
|
||||
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
|
||||
List<StatusModel> statusModelList = [];
|
||||
for (var status in response['status']) {
|
||||
statusModelList.add(StatusModel.fromJson(status));
|
||||
}
|
||||
deviceStatusList.add(AcStatusModel.fromJson(response['productUuid'], statusModelList));
|
||||
deviceStatusList.add(
|
||||
AcStatusModel.fromJson(response['productUuid'], statusModelList));
|
||||
}
|
||||
_setAllAcsTempsAndSwitches();
|
||||
}
|
||||
@@ -129,7 +143,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
emit(AcModifyingState(acStatusModel: deviceStatus));
|
||||
}
|
||||
|
||||
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
|
||||
await _runDeBouncerForOneDevice(
|
||||
deviceId: event.deviceId, code: 'switch', value: acSwitchValue);
|
||||
}
|
||||
|
||||
void _changeAllAcSwitch(ChangeAllSwitch event, Emitter<AcsState> emit) async {
|
||||
@@ -190,7 +205,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
deviceStatus.childLock = lockValue;
|
||||
emit(AcModifyingState(acStatusModel: deviceStatus));
|
||||
|
||||
await _runDeBouncerForOneDevice(deviceId: acId, code: 'child_lock', value: lockValue);
|
||||
await _runDeBouncerForOneDevice(
|
||||
deviceId: acId, code: 'child_lock', value: lockValue);
|
||||
}
|
||||
|
||||
void _increaseCoolTo(IncreaseCoolToTemp event, Emitter<AcsState> emit) async {
|
||||
@@ -218,7 +234,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
emit(AcModifyingState(acStatusModel: deviceStatus));
|
||||
}
|
||||
|
||||
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
|
||||
await _runDeBouncerForOneDevice(
|
||||
deviceId: event.deviceId, code: 'temp_set', value: value);
|
||||
}
|
||||
|
||||
void _decreaseCoolTo(DecreaseCoolToTemp event, Emitter<AcsState> emit) async {
|
||||
@@ -246,7 +263,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
emit(AcModifyingState(acStatusModel: deviceStatus));
|
||||
}
|
||||
|
||||
await _runDeBouncerForOneDevice(deviceId: event.deviceId, code: 'temp_set', value: value);
|
||||
await _runDeBouncerForOneDevice(
|
||||
deviceId: event.deviceId, code: 'temp_set', value: value);
|
||||
}
|
||||
|
||||
void _changeAcMode(ChangeAcMode event, Emitter<AcsState> emit) async {
|
||||
@@ -268,7 +286,9 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
}
|
||||
|
||||
await _runDeBouncerForOneDevice(
|
||||
deviceId: event.deviceId, code: 'mode', value: getACModeString(tempMode));
|
||||
deviceId: event.deviceId,
|
||||
code: 'mode',
|
||||
value: getACModeString(tempMode));
|
||||
}
|
||||
|
||||
void _changeFanSpeed(ChangeFanSpeed event, Emitter<AcsState> emit) async {
|
||||
@@ -281,19 +301,23 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
for (AcStatusModel ac in deviceStatusList) {
|
||||
if (ac.uuid == event.productId) {
|
||||
ac.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
|
||||
ac.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
|
||||
ac.acFanSpeed =
|
||||
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
|
||||
}
|
||||
}
|
||||
_emitAcsStatus(emit);
|
||||
} else {
|
||||
emit(AcChangeLoading(acStatusModel: deviceStatus));
|
||||
deviceStatus.fanSpeedsString = getNextFanSpeedKey(fanSpeed);
|
||||
deviceStatus.acFanSpeed = AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
|
||||
deviceStatus.acFanSpeed =
|
||||
AcStatusModel.getFanSpeed(getNextFanSpeedKey(fanSpeed));
|
||||
emit(AcModifyingState(acStatusModel: deviceStatus));
|
||||
}
|
||||
|
||||
await _runDeBouncerForOneDevice(
|
||||
deviceId: event.deviceId, code: 'level', value: getNextFanSpeedKey(fanSpeed));
|
||||
deviceId: event.deviceId,
|
||||
code: 'level',
|
||||
value: getNextFanSpeedKey(fanSpeed));
|
||||
}
|
||||
|
||||
String getACModeString(TempModes value) {
|
||||
@@ -338,7 +362,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
for (int i = 0; i < deviceStatusList.length; i++) {
|
||||
try {
|
||||
await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(deviceId: devicesList[i].uuid, code: code, value: value),
|
||||
DeviceControlModel(
|
||||
deviceId: devicesList[i].uuid, code: code, value: value),
|
||||
devicesList[i].uuid ?? '');
|
||||
} catch (_) {
|
||||
await Future.delayed(const Duration(milliseconds: 500));
|
||||
@@ -360,7 +385,10 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
_timer = Timer(const Duration(seconds: 1), () async {
|
||||
try {
|
||||
final response = await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(deviceId: allAcsPage ? deviceId : acId, code: code, value: value),
|
||||
DeviceControlModel(
|
||||
deviceId: allAcsPage ? deviceId : acId,
|
||||
code: code,
|
||||
value: value),
|
||||
allAcsPage ? deviceId : acId);
|
||||
|
||||
if (!response['success']) {
|
||||
@@ -377,7 +405,8 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
if (value >= 20 && value <= 30) {
|
||||
return true;
|
||||
} else {
|
||||
emit(const AcsFailedState(errorMessage: 'The temperature must be between 20 and 30'));
|
||||
emit(const AcsFailedState(
|
||||
errorMessage: 'The temperature must be between 20 and 30'));
|
||||
emit(GetAllAcsStatusState(
|
||||
allAcsStatues: deviceStatusList,
|
||||
allAcs: devicesList,
|
||||
@@ -396,4 +425,90 @@ class ACsBloc extends Bloc<AcsEvent, AcsState> {
|
||||
allTempSame: allTempSame,
|
||||
temp: globalTemp));
|
||||
}
|
||||
|
||||
void _setCounterValue(SetCounterValue event, Emitter<AcsState> emit) async {
|
||||
emit(AcsLoadingState());
|
||||
int seconds = 0;
|
||||
try {
|
||||
seconds = event.seconds;
|
||||
final response = await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(
|
||||
deviceId: acId, code: 'countdown_time', value: event.duration),
|
||||
acId);
|
||||
|
||||
if (response['success'] ?? false) {
|
||||
deviceStatus.countdown1 = seconds;
|
||||
|
||||
emit(UpdateTimerState(seconds: deviceStatus.countdown1));
|
||||
} else {
|
||||
emit(const AcsFailedState(errorMessage: 'Something went wrong'));
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
emit(AcsFailedState(errorMessage: e.toString()));
|
||||
return;
|
||||
}
|
||||
if (seconds > 0) {
|
||||
_onStartTimer(seconds);
|
||||
} else {
|
||||
_timer?.cancel();
|
||||
emit(TimerRunComplete());
|
||||
}
|
||||
}
|
||||
|
||||
void _getCounterValue(GetCounterEvent event, Emitter<AcsState> emit) async {
|
||||
try {
|
||||
emit(AcsLoadingState());
|
||||
var response = await DevicesAPI.getDeviceStatus(acId);
|
||||
List<StatusModel> statusModelList = [];
|
||||
for (var status in response['status']) {
|
||||
statusModelList.add(StatusModel.fromJson(status));
|
||||
}
|
||||
deviceStatus =
|
||||
AcStatusModel.fromJson(response['productUuid'], statusModelList);
|
||||
|
||||
if (event.deviceCode == 'countdown_time') {
|
||||
deviceStatus.countdown1 > 0
|
||||
? _onStartTimer(deviceStatus.countdown1)
|
||||
: emit(UpdateTimerState(seconds: deviceStatus.countdown1));
|
||||
}
|
||||
} catch (e) {
|
||||
emit(AcsFailedState(errorMessage: e.toString()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _onStartTimer(int seconds) {
|
||||
_timer?.cancel(); // Cancel any existing timer
|
||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||
final remainingTime = seconds - timer.tick;
|
||||
if (remainingTime > 0) {
|
||||
if (!isClosed) {
|
||||
// Check if the Bloc is still active
|
||||
add(TickTimer(remainingTime: remainingTime));
|
||||
}
|
||||
} else {
|
||||
_timer?.cancel();
|
||||
if (!isClosed) {
|
||||
emit(TimerRunComplete());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _onTickTimer(TickTimer event, Emitter<AcsState> emit) {
|
||||
if (!isClosed) {
|
||||
// Check if the Bloc is still active
|
||||
if (event.remainingTime > 0) {
|
||||
emit(TimerRunInProgress(event.remainingTime));
|
||||
} else {
|
||||
_timer?.cancel();
|
||||
emit(TimerRunComplete());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _onClose(OnClose event, Emitter<AcsState> emit) {
|
||||
_timer?.cancel(); // Cancel the timer
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ class AcSwitch extends AcsEvent {
|
||||
final bool acSwitch;
|
||||
final String deviceId;
|
||||
final String productId;
|
||||
const AcSwitch({required this.acSwitch, this.deviceId = '', this.productId = ''});
|
||||
const AcSwitch(
|
||||
{required this.acSwitch, this.deviceId = '', this.productId = ''});
|
||||
|
||||
@override
|
||||
List<Object> get props => [acSwitch, deviceId, productId];
|
||||
@@ -35,7 +36,8 @@ class IncreaseCoolToTemp extends AcsEvent {
|
||||
final double value;
|
||||
final String deviceId;
|
||||
final String productId;
|
||||
const IncreaseCoolToTemp({required this.value, this.deviceId = '', this.productId = ''});
|
||||
const IncreaseCoolToTemp(
|
||||
{required this.value, this.deviceId = '', this.productId = ''});
|
||||
|
||||
@override
|
||||
List<Object> get props => [value, deviceId];
|
||||
@@ -46,7 +48,8 @@ class DecreaseCoolToTemp extends AcsEvent {
|
||||
final String deviceId;
|
||||
final String productId;
|
||||
|
||||
const DecreaseCoolToTemp({required this.value, this.deviceId = '', this.productId = ''});
|
||||
const DecreaseCoolToTemp(
|
||||
{required this.value, this.deviceId = '', this.productId = ''});
|
||||
|
||||
@override
|
||||
List<Object> get props => [value, deviceId];
|
||||
@@ -56,7 +59,8 @@ class ChangeAcMode extends AcsEvent {
|
||||
final TempModes tempModes;
|
||||
final String deviceId;
|
||||
final String productId;
|
||||
const ChangeAcMode({required this.tempModes, this.deviceId = '', this.productId = ''});
|
||||
const ChangeAcMode(
|
||||
{required this.tempModes, this.deviceId = '', this.productId = ''});
|
||||
|
||||
@override
|
||||
List<Object> get props => [tempModes, deviceId, productId];
|
||||
@@ -67,7 +71,8 @@ class ChangeFanSpeed extends AcsEvent {
|
||||
final String deviceId;
|
||||
final String productId;
|
||||
|
||||
const ChangeFanSpeed({required this.fanSpeeds, this.deviceId = '', this.productId = ''});
|
||||
const ChangeFanSpeed(
|
||||
{required this.fanSpeeds, this.deviceId = '', this.productId = ''});
|
||||
|
||||
@override
|
||||
List<Object> get props => [fanSpeeds, deviceId, productId];
|
||||
@@ -104,3 +109,52 @@ class DecreaseAllTemp extends AcsEvent {
|
||||
@override
|
||||
List<Object> get props => [value];
|
||||
}
|
||||
|
||||
class SetCounterValue extends AcsEvent {
|
||||
final int duration;
|
||||
final String deviceCode;
|
||||
final int seconds;
|
||||
const SetCounterValue(
|
||||
{required this.duration,
|
||||
required this.deviceCode,
|
||||
required this.seconds});
|
||||
@override
|
||||
List<Object> get props => [duration, deviceCode, seconds];
|
||||
}
|
||||
|
||||
class SetTimeOutValue extends AcsEvent {
|
||||
final Duration duration;
|
||||
final String deviceCode;
|
||||
const SetTimeOutValue({required this.duration, required this.deviceCode});
|
||||
@override
|
||||
List<Object> get props => [duration, deviceCode];
|
||||
}
|
||||
|
||||
class StartTimer extends AcsEvent {
|
||||
final int duration;
|
||||
|
||||
const StartTimer(this.duration);
|
||||
|
||||
@override
|
||||
List<Object> get props => [duration];
|
||||
}
|
||||
|
||||
class TickTimer extends AcsEvent {
|
||||
final int remainingTime;
|
||||
|
||||
const TickTimer({required this.remainingTime});
|
||||
|
||||
@override
|
||||
List<Object> get props => [remainingTime];
|
||||
}
|
||||
|
||||
class StopTimer extends AcsEvent {}
|
||||
|
||||
class GetCounterEvent extends AcsEvent {
|
||||
final String deviceCode;
|
||||
const GetCounterEvent({required this.deviceCode});
|
||||
@override
|
||||
List<Object> get props => [deviceCode];
|
||||
}
|
||||
|
||||
class OnClose extends AcsEvent {}
|
||||
|
||||
@@ -63,3 +63,22 @@ class AcsFailedState extends AcsState {
|
||||
@override
|
||||
List<Object> get props => [errorMessage];
|
||||
}
|
||||
|
||||
class UpdateTimerState extends AcsState {
|
||||
final int seconds;
|
||||
const UpdateTimerState({required this.seconds});
|
||||
|
||||
@override
|
||||
List<Object> get props => [seconds];
|
||||
}
|
||||
|
||||
class TimerRunInProgress extends AcsState {
|
||||
final int remainingTime;
|
||||
|
||||
const TimerRunInProgress(this.remainingTime);
|
||||
|
||||
@override
|
||||
List<Object> get props => [remainingTime];
|
||||
}
|
||||
|
||||
class TimerRunComplete extends AcsState {}
|
||||
|
||||
@@ -65,7 +65,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
batteryPercentage: 0,
|
||||
);
|
||||
|
||||
void _fetchStatus(GarageDoorInitial event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _fetchStatus(
|
||||
GarageDoorInitial event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(GarageDoorLoadingState());
|
||||
try {
|
||||
var response = await DevicesAPI.getDeviceStatus(GDId);
|
||||
@@ -113,8 +114,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleClosingReminder(
|
||||
ToggleClosingReminderEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _toggleClosingReminder(ToggleClosingReminderEvent event,
|
||||
Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||
try {
|
||||
closingReminder = event.isClosingReminderEnabled;
|
||||
@@ -132,7 +133,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleDoorAlarm(ToggleDoorAlarmEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _toggleDoorAlarm(
|
||||
ToggleDoorAlarmEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||
try {
|
||||
doorAlarm = event.isDoorAlarmEnabled;
|
||||
@@ -150,7 +152,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
DeviceReport recordGroups = DeviceReport(startTime: '0', endTime: '0', data: []);
|
||||
DeviceReport recordGroups =
|
||||
DeviceReport(startTime: '0', endTime: '0', data: []);
|
||||
|
||||
Future<void> fetchLogsForLastMonth(
|
||||
ReportLogsInitial event, Emitter<GarageDoorSensorState> emit) async {
|
||||
@@ -179,14 +182,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
|
||||
_listenToChanges() {
|
||||
try {
|
||||
DatabaseReference ref = FirebaseDatabase.instance.ref('device-status/$GDId');
|
||||
DatabaseReference ref =
|
||||
FirebaseDatabase.instance.ref('device-status/$GDId');
|
||||
Stream<DatabaseEvent> stream = ref.onValue;
|
||||
|
||||
stream.listen((DatabaseEvent event) async {
|
||||
if (_timer != null) {
|
||||
await Future.delayed(const Duration(seconds: 2));
|
||||
}
|
||||
Map<dynamic, dynamic> usersMap = event.snapshot.value as Map<dynamic, dynamic>;
|
||||
Map<dynamic, dynamic> usersMap =
|
||||
event.snapshot.value as Map<dynamic, dynamic>;
|
||||
List<StatusModel> statusList = [];
|
||||
usersMap['status'].forEach((element) {
|
||||
statusList.add(StatusModel(code: element['code'], value: true));
|
||||
@@ -261,7 +266,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
deviceId: GDId,
|
||||
);
|
||||
List<dynamic> jsonData = response;
|
||||
listSchedule = jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
|
||||
listSchedule =
|
||||
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
|
||||
emit(UpdateState(garageSensor: deviceStatus));
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
@@ -272,12 +278,13 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
|
||||
int? getTimeStampWithoutSeconds(DateTime? dateTime) {
|
||||
if (dateTime == null) return null;
|
||||
DateTime dateTimeWithoutSeconds =
|
||||
DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute);
|
||||
DateTime dateTimeWithoutSeconds = DateTime(dateTime.year, dateTime.month,
|
||||
dateTime.day, dateTime.hour, dateTime.minute);
|
||||
return dateTimeWithoutSeconds.millisecondsSinceEpoch ~/ 1000;
|
||||
}
|
||||
|
||||
Future toggleChange(ToggleScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
Future toggleChange(
|
||||
ToggleScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
try {
|
||||
emit(GarageDoorLoadingState());
|
||||
final response = await DevicesAPI.changeSchedule(
|
||||
@@ -295,7 +302,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
Future deleteSchedule(DeleteScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
Future deleteSchedule(
|
||||
DeleteScheduleEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
try {
|
||||
emit(GarageDoorLoadingState());
|
||||
final response = await DevicesAPI.deleteSchedule(
|
||||
@@ -314,13 +322,15 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void toggleSelectedIndex(ToggleSelectedEvent event, Emitter<GarageDoorSensorState> emit) {
|
||||
void toggleSelectedIndex(
|
||||
ToggleSelectedEvent event, Emitter<GarageDoorSensorState> emit) {
|
||||
emit(GarageDoorLoadingState());
|
||||
selectedTabIndex = event.index;
|
||||
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
|
||||
}
|
||||
|
||||
void toggleCreateSchedule(ToggleCreateScheduleEvent event, Emitter<GarageDoorSensorState> emit) {
|
||||
void toggleCreateSchedule(
|
||||
ToggleCreateScheduleEvent event, Emitter<GarageDoorSensorState> emit) {
|
||||
emit(GarageDoorLoadingState());
|
||||
createSchedule = !createSchedule;
|
||||
selectedDays.clear();
|
||||
@@ -337,13 +347,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
|
||||
int secondSelected = 0;
|
||||
bool toggleDoor = false;
|
||||
Future<void> selectSeconds(SelectSecondsEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
Future<void> selectSeconds(
|
||||
SelectSecondsEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
try {
|
||||
emit(GarageDoorLoadingState());
|
||||
secondSelected = event.seconds;
|
||||
|
||||
await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(deviceId: GDId, code: 'tr_timecon', value: secondSelected), GDId);
|
||||
DeviceControlModel(
|
||||
deviceId: GDId, code: 'tr_timecon', value: secondSelected),
|
||||
GDId);
|
||||
emit(UpdateState(garageSensor: deviceStatus));
|
||||
} on DioException catch (e) {
|
||||
final errorData = e.response!.data;
|
||||
@@ -352,12 +365,15 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
openCloseGarageDoor(ToggleDoorEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
openCloseGarageDoor(
|
||||
ToggleDoorEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(GarageDoorLoadingState());
|
||||
try {
|
||||
toggleDoor = !event.toggle;
|
||||
await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(deviceId: GDId, code: 'switch_1', value: toggleDoor), GDId);
|
||||
DeviceControlModel(
|
||||
deviceId: GDId, code: 'switch_1', value: toggleDoor),
|
||||
GDId);
|
||||
add(const GarageDoorInitial());
|
||||
emit(UpdateState(garageSensor: deviceStatus));
|
||||
} on DioException catch (e) {
|
||||
@@ -367,13 +383,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _setCounterValue(SetCounterValue event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _setCounterValue(
|
||||
SetCounterValue event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||
int seconds = 0;
|
||||
try {
|
||||
seconds = event.duration.inSeconds;
|
||||
final response = await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(deviceId: GDId, code: 'countdown_1', value: seconds), GDId);
|
||||
DeviceControlModel(
|
||||
deviceId: GDId, code: 'countdown_1', value: seconds),
|
||||
GDId);
|
||||
|
||||
if (response['success'] ?? false) {
|
||||
deviceStatus.countdown1 = seconds;
|
||||
@@ -393,7 +412,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _getCounterValue(GetCounterEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _getCounterValue(
|
||||
GetCounterEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingInitialState());
|
||||
try {
|
||||
var response = await DevicesAPI.getDeviceStatus(GDId);
|
||||
@@ -434,7 +454,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
List<GroupGarageModel> groupList = [];
|
||||
bool allSwitchesOn = true;
|
||||
|
||||
void _fetchWizardStatus(InitialWizardEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _fetchWizardStatus(
|
||||
InitialWizardEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingInitialState());
|
||||
try {
|
||||
devicesList = [];
|
||||
@@ -444,7 +465,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
HomeCubit.getInstance().selectedSpace?.id ?? '', 'GD');
|
||||
|
||||
for (int i = 0; i < devicesList.length; i++) {
|
||||
var response = await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
|
||||
var response =
|
||||
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
|
||||
List<StatusModel> statusModelList = [];
|
||||
for (var status in response['status']) {
|
||||
statusModelList.add(StatusModel.fromJson(status));
|
||||
@@ -473,7 +495,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _groupAllOn(GroupAllOnEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _groupAllOn(
|
||||
GroupAllOnEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||
try {
|
||||
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
|
||||
@@ -485,7 +508,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
emit(UpdateGroupState(garageList: groupList, allSwitches: true));
|
||||
|
||||
// Get a list of all device IDs
|
||||
List<String> allDeviceIds = groupList.map((device) => device.deviceId).toList();
|
||||
List<String> allDeviceIds =
|
||||
groupList.map((device) => device.deviceId).toList();
|
||||
|
||||
// First call for switch_1
|
||||
final response = await DevicesAPI.deviceBatchController(
|
||||
@@ -505,7 +529,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _groupAllOff(GroupAllOffEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _groupAllOff(
|
||||
GroupAllOffEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||
try {
|
||||
// Set all switches (firstSwitch and secondSwitch) based on the event value (on/off)
|
||||
@@ -517,7 +542,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
emit(UpdateGroupState(garageList: groupList, allSwitches: false));
|
||||
|
||||
// Get a list of all device IDs
|
||||
List<String> allDeviceIds = groupList.map((device) => device.deviceId).toList();
|
||||
List<String> allDeviceIds =
|
||||
groupList.map((device) => device.deviceId).toList();
|
||||
|
||||
// First call for switch_1
|
||||
final response = await DevicesAPI.deviceBatchController(
|
||||
@@ -538,8 +564,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _changeFirstWizardSwitch(
|
||||
ChangeFirstWizardSwitchStatusEvent event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
|
||||
Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||
try {
|
||||
bool allSwitchesValue = true;
|
||||
@@ -552,7 +578,8 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
});
|
||||
|
||||
emit(UpdateGroupState(garageList: groupList, allSwitches: allSwitchesValue));
|
||||
emit(UpdateGroupState(
|
||||
garageList: groupList, allSwitches: allSwitchesValue));
|
||||
|
||||
final response = await DevicesAPI.deviceBatchController(
|
||||
code: 'switch_1',
|
||||
@@ -568,13 +595,16 @@ class GarageDoorBloc extends Bloc<GarageDoorEvent, GarageDoorSensorState> {
|
||||
}
|
||||
}
|
||||
|
||||
void _setTimeOutAlarm(SetTimeOutValue event, Emitter<GarageDoorSensorState> emit) async {
|
||||
void _setTimeOutAlarm(
|
||||
SetTimeOutValue event, Emitter<GarageDoorSensorState> emit) async {
|
||||
emit(LoadingNewSate(doorSensor: deviceStatus));
|
||||
int seconds = 0;
|
||||
try {
|
||||
seconds = event.duration.inSeconds;
|
||||
final response = await DevicesAPI.controlDevice(
|
||||
DeviceControlModel(deviceId: GDId, code: 'countdown_alarm', value: seconds), GDId);
|
||||
DeviceControlModel(
|
||||
deviceId: GDId, code: 'countdown_alarm', value: seconds),
|
||||
GDId);
|
||||
|
||||
if (response['success'] ?? false) {
|
||||
deviceStatus.countdownAlarm = seconds;
|
||||
|
||||
@@ -11,12 +11,14 @@ class AcStatusModel {
|
||||
bool childLock;
|
||||
late TempModes acMode;
|
||||
late FanSpeeds acFanSpeed;
|
||||
int countdown1;
|
||||
|
||||
AcStatusModel(
|
||||
{required this.uuid,
|
||||
required this.acSwitch,
|
||||
required this.modeString,
|
||||
required this.tempSet,
|
||||
required this.countdown1,
|
||||
required this.currentTemp,
|
||||
required this.fanSpeedsString,
|
||||
required this.childLock}) {
|
||||
@@ -30,6 +32,7 @@ class AcStatusModel {
|
||||
late int _tempSet;
|
||||
late int _currentTemp;
|
||||
late String _fanSpeeds;
|
||||
late int _countdown1;
|
||||
late bool _childLock;
|
||||
for (int i = 0; i < jsonList.length; i++) {
|
||||
if (jsonList[i].code == 'switch') {
|
||||
@@ -44,6 +47,8 @@ class AcStatusModel {
|
||||
_fanSpeeds = jsonList[i].value ?? 210;
|
||||
} else if (jsonList[i].code == 'child_lock') {
|
||||
_childLock = jsonList[i].value ?? false;
|
||||
} else if (jsonList[i].code == 'countdown_time') {
|
||||
_countdown1 = jsonList[i].value ?? 0;
|
||||
}
|
||||
}
|
||||
return AcStatusModel(
|
||||
@@ -53,6 +58,7 @@ class AcStatusModel {
|
||||
tempSet: _tempSet,
|
||||
currentTemp: _currentTemp,
|
||||
fanSpeedsString: _fanSpeeds,
|
||||
countdown1: _countdown1,
|
||||
childLock: _childLock);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomHalfHourPicker extends StatefulWidget {
|
||||
final Function(double) onValueChanged;
|
||||
|
||||
const CustomHalfHourPicker({Key? key, required this.onValueChanged})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_CustomHalfHourPickerState createState() => _CustomHalfHourPickerState();
|
||||
}
|
||||
|
||||
class _CustomHalfHourPickerState extends State<CustomHalfHourPicker> {
|
||||
double selectedValue = 0.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
height: 200,
|
||||
child: ListWheelScrollView.useDelegate(
|
||||
itemExtent: 50,
|
||||
perspective: 0.005,
|
||||
physics: const FixedExtentScrollPhysics(),
|
||||
overAndUnderCenterOpacity: 0.3,
|
||||
onSelectedItemChanged: (index) {
|
||||
setState(() {
|
||||
selectedValue =
|
||||
index * 0.5; // Convert index to half-hour increments
|
||||
widget.onValueChanged(selectedValue);
|
||||
});
|
||||
},
|
||||
childDelegate: ListWheelChildBuilderDelegate(
|
||||
builder: (context, index) {
|
||||
if (index < 0 || index > 48)
|
||||
return null; // Limit to 24.0 (48 * 0.5)
|
||||
return Center(
|
||||
child: Text(
|
||||
(index * 0.5)
|
||||
.toStringAsFixed(1), // Display value as 0.0, 0.5, etc.
|
||||
style: const TextStyle(
|
||||
fontSize: 25,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w800),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: 49, // 0.0 to 24.0 (inclusive)
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ class AcInterface extends StatelessWidget {
|
||||
},
|
||||
builder: (context, state) {
|
||||
AcStatusModel statusModel = AcStatusModel(
|
||||
countdown1: 0,
|
||||
uuid: ac.uuid ?? '',
|
||||
acSwitch: true,
|
||||
modeString: 'hot',
|
||||
|
||||
@@ -7,11 +7,13 @@ import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
|
||||
import 'package:syncrow_app/features/devices/model/ac_model.dart';
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_mode_control_unit.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/ACs/ac_timer_page.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
|
||||
class AcInterfaceControls extends StatelessWidget {
|
||||
const AcInterfaceControls({super.key, required this.deviceModel, required this.deviceStatus});
|
||||
const AcInterfaceControls(
|
||||
{super.key, required this.deviceModel, required this.deviceStatus});
|
||||
|
||||
final DeviceModel deviceModel;
|
||||
final AcStatusModel deviceStatus;
|
||||
@@ -20,8 +22,9 @@ class AcInterfaceControls extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<ACsBloc, AcsState>(
|
||||
builder: (context, state) {
|
||||
String lockIconName =
|
||||
deviceStatus.childLock ? Assets.assetsIconsLock : Assets.assetsIconsUnLock;
|
||||
String lockIconName = deviceStatus.childLock
|
||||
? Assets.assetsIconsLock
|
||||
: Assets.assetsIconsUnLock;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
@@ -34,11 +37,22 @@ class AcInterfaceControls extends StatelessWidget {
|
||||
children: [
|
||||
Flexible(
|
||||
child: GestureDetector(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
PageRouteBuilder(
|
||||
pageBuilder: (context, animation1, animation2) =>
|
||||
AcTimerPage(
|
||||
device: deviceModel,
|
||||
deviceCode: deviceModel.type!,
|
||||
switchCode: '',
|
||||
)));
|
||||
},
|
||||
child: DefaultContainer(
|
||||
height: 55,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(Assets.assetsIconsAutomatedClock),
|
||||
child:
|
||||
SvgPicture.asset(Assets.assetsIconsAutomatedClock),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/6_scene_switch_bloc/6_scene_state.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_bloc.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_event.dart';
|
||||
import 'package:syncrow_app/features/devices/bloc/acs_bloc/acs_state.dart';
|
||||
|
||||
import 'package:syncrow_app/features/devices/model/device_model.dart';
|
||||
import 'package:syncrow_app/features/devices/view/widgets/ACs/CustomHalfHourTimerPicker.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
|
||||
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
|
||||
import 'package:syncrow_app/generated/assets.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
|
||||
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
|
||||
|
||||
class AcTimerPage extends StatelessWidget {
|
||||
final DeviceModel device;
|
||||
final String deviceCode;
|
||||
final String switchCode;
|
||||
const AcTimerPage(
|
||||
{required this.device,
|
||||
required this.deviceCode,
|
||||
required this.switchCode,
|
||||
super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnnotatedRegion(
|
||||
value: SystemUiOverlayStyle(
|
||||
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
|
||||
statusBarIconBrightness: Brightness.light,
|
||||
),
|
||||
child: BlocProvider(
|
||||
create: (context) => ACsBloc(acId: device.uuid ?? ''),
|
||||
child: BlocBuilder<ACsBloc, AcsState>(
|
||||
builder: (context, state) {
|
||||
final oneGangBloc = BlocProvider.of<ACsBloc>(context);
|
||||
Duration duration = Duration.zero;
|
||||
int selectedValue = 0;
|
||||
|
||||
int countNum = 0;
|
||||
if (state is UpdateTimerState) {
|
||||
countNum = state.seconds;
|
||||
} else if (state is TimerRunInProgress) {
|
||||
countNum = state.remainingTime;
|
||||
} else if (state is TimerRunComplete) {
|
||||
countNum = 0;
|
||||
}
|
||||
// else if (state is LoadingNewSate) {
|
||||
// countNum = 0;
|
||||
// }
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) {
|
||||
if (!didPop) {
|
||||
oneGangBloc.add(OnClose());
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: DefaultTabController(
|
||||
length: 2,
|
||||
child: DefaultScaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.transparent,
|
||||
centerTitle: true,
|
||||
title: const BodyLarge(
|
||||
text: 'Countdown',
|
||||
fontColor: ColorsManager.primaryColor,
|
||||
fontWeight: FontsManager.bold,
|
||||
),
|
||||
),
|
||||
child: state is AcsLoadingState
|
||||
? const Center(child: CircularProgressIndicator())
|
||||
: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: const ShapeDecoration(
|
||||
color: ColorsManager.onPrimaryColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(30)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Container(
|
||||
child: Column(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
countNum > 0
|
||||
? BodyLarge(
|
||||
text: formatDuration(countNum),
|
||||
fontColor: ColorsManager
|
||||
.slidingBlueColor,
|
||||
fontSize: 40,
|
||||
)
|
||||
: Container(
|
||||
child: CustomHalfHourPicker(
|
||||
onValueChanged: (value) {
|
||||
selectedValue =
|
||||
(value * 10).toInt();
|
||||
if (selectedValue == 5) {
|
||||
duration = const Duration(
|
||||
minutes:
|
||||
30); // 0.5 translates to 30 minutes
|
||||
countNum =
|
||||
duration.inSeconds;
|
||||
} else {
|
||||
duration = Duration(
|
||||
minutes: selectedValue *
|
||||
6); // Each step represents 6 minutes
|
||||
countNum =
|
||||
duration.inSeconds;
|
||||
}
|
||||
print(
|
||||
"Selected Value: $selectedValue, Duration: $duration");
|
||||
},
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (state is LoadingNewSate) {
|
||||
return;
|
||||
}
|
||||
if (countNum > 0) {
|
||||
oneGangBloc.add(SetCounterValue(
|
||||
seconds: countNum,
|
||||
deviceCode:
|
||||
'countdown_time',
|
||||
duration: selectedValue));
|
||||
} else if (duration !=
|
||||
Duration.zero) {
|
||||
oneGangBloc.add(SetCounterValue(
|
||||
seconds: 0,
|
||||
deviceCode:
|
||||
'countdown_time',
|
||||
duration: selectedValue));
|
||||
}
|
||||
},
|
||||
child: SvgPicture.asset(countNum > 0
|
||||
? Assets.pauseIcon
|
||||
: Assets.playIcon)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String formatDuration(int seconds) {
|
||||
final hours = (seconds ~/ 3600).toString().padLeft(2, '0');
|
||||
final minutes = ((seconds % 3600) ~/ 60).toString().padLeft(2, '0');
|
||||
final secs = (seconds % 60).toString().padLeft(2, '0');
|
||||
return '$hours:$minutes:$secs';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user