two touch & three touch

This commit is contained in:
mohammad
2024-10-01 16:24:36 +03:00
parent b8b6ec67c7
commit d75d438106
33 changed files with 5813 additions and 100 deletions

View File

@ -508,7 +508,54 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
String statusSelected = '';
String optionSelected = '';
// void _changeStatus(
Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
final Map<String, Map<String, String>> controlMap = {
"relay_status": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"light_mode": {
'Off': 'none',
'On/Off Status': 'relay',
'Switch Position': 'pos',
},
"relay_status_1": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
};
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: oneTouchId, code: optionSelected, value: selectedControl),
oneTouchId,
);
Future.delayed(const Duration(seconds: 1), () async {
add(const InitialEvent(groupScreen: false));
});
Future.delayed(const Duration(seconds: 1), () async {
emit(UpdateState(oneTouchModel: deviceStatus));
});
// add(const InitialEvent(groupScreen: false));
} else {
print('Invalid statusSelected or optionSelected');
}
}
}
// void _changeStatus(
// ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
// emit(LoadingNewSate(oneTouchModel: deviceStatus));
// try {
@ -581,55 +628,18 @@ class OneTouchBloc extends Bloc<OneTouchEvent, OneTouchState> {
// }
// }
void _changeStatus(
ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
emit(LoadingInitialState());
emit(UpdateState(oneTouchModel: deviceStatus));
emit(LoadingNewSate(oneTouchModel: deviceStatus));
try {
await _handleDeviceControl(event.deviceId, event.context);
add(InitialEvent(groupScreen: oneTouchGroup));
emit(UpdateState(oneTouchModel: deviceStatus));
} catch (error) {
print('Error controlling device: $error');
add(InitialEvent(groupScreen: oneTouchGroup));
}
}
Future<void> _handleDeviceControl(
String deviceId, BuildContext context) async {
final Map<String, Map<String, String>> controlMap = {
"relay_status": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"light_mode": {
'Off': 'none',
'On/Off Status': 'relay',
'Switch Position': 'pos',
},
"relay_status_1": {
'Power On': 'power_off',
'Power Off': 'power_on',
'Restart Memory': 'last',
},
};
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: oneTouchId, code: optionSelected, value: selectedControl),
oneTouchId,
).then(
(value) {
Navigator.pop(context);
},
);
} else {
print('Invalid statusSelected or optionSelected');
}
}
}
// Future<void> _changeStatus(
// ChangeStatusEvent event, Emitter<OneTouchState> emit) async {
// try {
// emit(LoadingInitialState());
// // emit(LoadingNewSate(oneTouchModel: deviceStatus));
// await _handleDeviceControl(event.deviceId, event.context);
// Future.delayed(const Duration(seconds: 1), () async {
// add(const InitialEvent(groupScreen: false));
// });
// emit(UpdateState(oneTouchModel: deviceStatus));
// } catch (error) {
// print('Error controlling device: $error');
// add(InitialEvent(groupScreen: oneTouchGroup));
// }
// }

View File

@ -0,0 +1,748 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_three_touch_model.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/three_touch_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ThreeTouchBloc extends Bloc<ThreeTouchEvent, ThreeTouchState> {
final String threeTouchId;
final String switchCode;
ThreeTouchModel deviceStatus = ThreeTouchModel(
firstSwitch: false,
secondSwitch: false,
thirdSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
thirdCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off,
relay_status_2: status.off,
relay_status_3: status.off,
);
Timer? _timer;
bool threeTouchGroup = false;
List<DeviceModel> devicesList = [];
List<GroupThreeTouchModel> groupThreeTouchList = [];
bool allSwitchesOn = true;
ThreeTouchBloc({required this.threeTouchId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchThreeTouchStatus);
on<ThreeTouchUpdated>(_threeTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSecondSwitchStatusEvent>(_changeSecondSwitch);
on<ChangeThirdSwitchStatusEvent>(_changeThirdSwitch);
on<AllOffEvent>(_allOff);
on<AllOnEvent>(_allOn);
on<ChangeSlidingSegment>(_changeSliding);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<ThreeTouchSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleChange);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<ChangeStatusEvent>(_changeStatus);
}
void _fetchThreeTouchStatus(
InitialEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingInitialState());
try {
threeTouchGroup = event.groupScreen;
if (threeTouchGroup) {
devicesList = [];
groupThreeTouchList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '3GT');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = ThreeTouchModel.fromJson(statusModelList);
groupThreeTouchList.add(GroupThreeTouchModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
secondSwitch: deviceStatus.secondSwitch,
thirdSwitch: deviceStatus.thirdSwitch));
}
if (groupThreeTouchList.isNotEmpty) {
groupThreeTouchList.firstWhere((element) {
if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
threeTouchList: groupThreeTouchList, allSwitches: allSwitchesOn));
} else {
var response = await DevicesAPI.getDeviceStatus(threeTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = ThreeTouchModel.fromJson(statusModelList);
emit(UpdateState(threeTouchModel: deviceStatus));
_listenToChanges();
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$threeTouchId');
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>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = ThreeTouchModel.fromJson(statusList);
if (!isClosed) {
add(ThreeTouchUpdated());
}
});
} catch (_) {}
}
_threeTouchUpdated(ThreeTouchUpdated event, Emitter<ThreeTouchState> emit) {
emit(UpdateState(threeTouchModel: deviceStatus));
}
void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
if (threeTouchGroup) {
bool allSwitchesValue = true;
groupThreeTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
threeTouchList: groupThreeTouchList,
allSwitches: allSwitchesValue));
} else {
deviceStatus.firstSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus));
}
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchGroup ? event.deviceId : threeTouchId,
code: 'switch_1',
value: !event.value),
threeTouchGroup ? event.deviceId : threeTouchId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
}
void _changeSecondSwitch(ChangeSecondSwitchStatusEvent event,
Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
if (threeTouchGroup) {
bool allSwitchesValue = true;
groupThreeTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value;
}
if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
threeTouchList: groupThreeTouchList,
allSwitches: allSwitchesValue));
} else {
deviceStatus.secondSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus));
}
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchGroup ? event.deviceId : threeTouchId,
code: 'switch_2',
value: !event.value),
threeTouchGroup ? event.deviceId : threeTouchId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
}
void _changeThirdSwitch(
ChangeThirdSwitchStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
if (threeTouchGroup) {
bool allSwitchesValue = true;
groupThreeTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.thirdSwitch = !event.value;
}
if (!element.firstSwitch ||
!element.secondSwitch ||
!element.thirdSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
threeTouchList: groupThreeTouchList,
allSwitches: allSwitchesValue));
} else {
deviceStatus.thirdSwitch = !event.value;
emit(UpdateState(threeTouchModel: deviceStatus));
}
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchGroup ? event.deviceId : threeTouchId,
code: 'switch_3',
value: !event.value),
threeTouchGroup ? event.deviceId : threeTouchId);
if (!response['success']) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
});
} catch (_) {
add(InitialEvent(groupScreen: threeTouchGroup));
}
}
void _allOff(AllOffEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = false;
deviceStatus.secondSwitch = false;
deviceStatus.thirdSwitch = false;
emit(UpdateState(threeTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId,
code: 'switch_3',
value: deviceStatus.thirdSwitch),
threeTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
}
void _allOn(AllOnEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = true;
deviceStatus.secondSwitch = true;
deviceStatus.thirdSwitch = true;
emit(UpdateState(threeTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
threeTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId,
code: 'switch_3',
value: deviceStatus.thirdSwitch),
threeTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: false));
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
for (int i = 0; i < groupThreeTouchList.length; i++) {
groupThreeTouchList[i].firstSwitch = true;
groupThreeTouchList[i].secondSwitch = true;
groupThreeTouchList[i].thirdSwitch = true;
}
emit(UpdateGroupState(
threeTouchList: groupThreeTouchList, allSwitches: true));
for (int i = 0; i < groupThreeTouchList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeTouchList[i].deviceId,
code: 'switch_1',
value: true),
groupThreeTouchList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeTouchList[i].deviceId,
code: 'switch_2',
value: true),
groupThreeTouchList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeTouchList[i].deviceId,
code: 'switch_3',
value: true),
groupThreeTouchList[i].deviceId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _groupAllOff(
GroupAllOffEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
try {
for (int i = 0; i < groupThreeTouchList.length; i++) {
groupThreeTouchList[i].firstSwitch = false;
groupThreeTouchList[i].secondSwitch = false;
groupThreeTouchList[i].thirdSwitch = false;
}
emit(UpdateGroupState(
threeTouchList: groupThreeTouchList, allSwitches: false));
for (int i = 0; i < groupThreeTouchList.length; i++) {
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeTouchList[i].deviceId,
code: 'switch_1',
value: false),
groupThreeTouchList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeTouchList[i].deviceId,
code: 'switch_2',
value: false),
groupThreeTouchList[i].deviceId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: groupThreeTouchList[i].deviceId,
code: 'switch_3',
value: false),
groupThreeTouchList[i].deviceId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
break;
}
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent(groupScreen: true));
}
}
void _changeSliding(
ChangeSlidingSegment event, Emitter<ThreeTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(
SetCounterValue event, Emitter<ThreeTouchState> emit) async {
emit(LoadingNewSate(threeTouchModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId, code: event.deviceCode, value: seconds),
threeTouchId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown = seconds;
} else if (event.deviceCode == 'countdown_3') {
deviceStatus.thirdCountDown = seconds;
}
} else {
emit(const FailedState(error: 'Something went wrong'));
return;
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(threeTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = ThreeTouchModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown > 0
? _onStartTimer(deviceStatus.secondCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.secondCountDown));
} else if (event.deviceCode == 'countdown_3') {
deviceStatus.thirdCountDown > 0
? _onStartTimer(deviceStatus.thirdCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.thirdCountDown));
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _onClose(OnClose event, Emitter<ThreeTouchState> emit) {
_timer?.cancel();
}
void _onStartTimer(int seconds) {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
add(TickTimer(seconds - timer.tick));
});
}
void _onTickTimer(TickTimer event, Emitter<ThreeTouchState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"},
{"day": "Tue", "key": "Tue"},
{"day": "Wed", "key": "Wed"},
{"day": "Thu", "key": "Thu"},
{"day": "Fri", "key": "Fri"},
{"day": "Sat", "key": "Sat"},
];
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<ThreeTouchState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(
ThreeTouchSave event,
Emitter<ThreeTouchState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: threeTouchId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(ThreeTouchSaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<ThreeTouchState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: threeTouchId,
);
List<dynamic> jsonData = response;
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
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 toggleChange(
ToggleScheduleEvent event, Emitter<ThreeTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: threeTouchId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<ThreeTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: threeTouchId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<ThreeTouchState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<ThreeTouchState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
int selectedTabIndex = 0;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
DateTime? selectedTime = DateTime.now();
String statusSelected = '';
String optionSelected = '';
Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<ThreeTouchState> emit) async {
emit(LoadingInitialState());
final Map<String, Map<String, String>> controlMap = {
"relay_status": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"light_mode": {
'Off': 'none',
'On/Off Status': 'relay',
'Switch Position': 'pos',
},
"relay_status_1": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"relay_status_2": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"relay_status_3": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
};
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: threeTouchId,
code: optionSelected,
value: selectedControl),
threeTouchId,
);
Future.delayed(const Duration(seconds: 1), () async {
add(const InitialEvent(groupScreen: false));
});
Future.delayed(const Duration(seconds: 1), () async {
emit(UpdateState(threeTouchModel: deviceStatus));
});
} else {
print('Invalid statusSelected or optionSelected');
}
}
}

View File

@ -0,0 +1,147 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class ThreeTouchEvent extends Equatable {
const ThreeTouchEvent();
@override
List<Object> get props => [];
}
class LoadingEvent extends ThreeTouchEvent {}
class ThreeTouchUpdated extends ThreeTouchEvent {}
class InitialEvent extends ThreeTouchEvent {
final bool groupScreen;
const InitialEvent({required this.groupScreen});
@override
List<Object> get props => [groupScreen];
}
class ChangeFirstSwitchStatusEvent extends ThreeTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondSwitchStatusEvent extends ThreeTouchEvent {
final bool value;
final String deviceId;
const ChangeSecondSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeThirdSwitchStatusEvent extends ThreeTouchEvent {
final bool value;
final String deviceId;
const ChangeThirdSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class AllOffEvent extends ThreeTouchEvent {}
class AllOnEvent extends ThreeTouchEvent {}
class GroupAllOnEvent extends ThreeTouchEvent {}
class GroupAllOffEvent extends ThreeTouchEvent {}
class ChangeSlidingSegment extends ThreeTouchEvent {
final int value;
const ChangeSlidingSegment({required this.value});
@override
List<Object> get props => [value];
}
class GetCounterEvent extends ThreeTouchEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class SetCounterValue extends ThreeTouchEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends ThreeTouchEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends ThreeTouchEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends ThreeTouchEvent {}
class OnClose extends ThreeTouchEvent {}
//------------------- Schedule ----------=---------
class GetScheduleEvent extends ThreeTouchEvent {}
class ThreeTouchSave extends ThreeTouchEvent {}
class ToggleScheduleEvent extends ThreeTouchEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle, id];
}
class ToggleDaySelectionEvent extends ThreeTouchEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class DeleteScheduleEvent extends ThreeTouchEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class ToggleSelectedEvent extends ThreeTouchEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends ThreeTouchEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class InitialWizardDevises extends ThreeTouchEvent {}
class ChangeStatusEvent extends ThreeTouchEvent {
final String deviceId;
final BuildContext context;
const ChangeStatusEvent({this.deviceId = '', required this.context});
}

View File

@ -0,0 +1,90 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/group_three_touch_model.dart';
import 'package:syncrow_app/features/devices/model/three_touch_model.dart';
class ThreeTouchState extends Equatable {
const ThreeTouchState();
@override
List<Object> get props => [];
}
class InitialState extends ThreeTouchState {}
class LoadingInitialState extends ThreeTouchState {}
class UpdateState extends ThreeTouchState {
final ThreeTouchModel threeTouchModel;
const UpdateState({required this.threeTouchModel});
@override
List<Object> get props => [threeTouchModel];
}
class LoadingNewSate extends ThreeTouchState {
final ThreeTouchModel threeTouchModel;
const LoadingNewSate({required this.threeTouchModel});
@override
List<Object> get props => [threeTouchModel];
}
class UpdateGroupState extends ThreeTouchState {
final List<GroupThreeTouchModel> threeTouchList;
final bool allSwitches;
const UpdateGroupState({required this.threeTouchList, required this.allSwitches});
@override
List<Object> get props => [threeTouchList, allSwitches];
}
class FailedState extends ThreeTouchState {
final String error;
const FailedState({required this.error});
@override
List<Object> get props => [error];
}
class ChangeSlidingSegmentState extends ThreeTouchState {
final int value;
const ChangeSlidingSegmentState({required this.value});
@override
List<Object> get props => [value];
}
class UpdateTimerState extends ThreeTouchState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends ThreeTouchState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class TimerRunComplete extends ThreeTouchState {}
class ThreeTouchSaveSchedule extends ThreeTouchState {}
class IsToggleState extends ThreeTouchState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class ChangeTimeState extends ThreeTouchState {}
class UpdateCreateScheduleState extends ThreeTouchState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}

View File

@ -0,0 +1,688 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_control_model.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_two_touch_model.dart';
import 'package:syncrow_app/features/devices/model/schedule_model.dart';
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/features/devices/model/two_touch_model.dart';
import 'package:syncrow_app/services/api/devices_api.dart';
import 'package:syncrow_app/utils/helpers/snack_bar.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class TwoTouchBloc extends Bloc<TwoTouchEvent, TwoTouchState> {
final String twoTouchId;
final String switchCode;
TwoTouchModel deviceStatus = TwoTouchModel(
firstSwitch: false,
secondSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off,
relay_status_2: status.off,
);
Timer? _timer;
bool twoTouchGroup = false;
List<DeviceModel> devicesList = [];
List<GroupTwoTouchModel> groupTwoTouchList = [];
bool allSwitchesOn = true;
bool toggleSchedule = true;
List<String> selectedDays = [];
bool createSchedule = false;
List<ScheduleModel> listSchedule = [];
TwoTouchBloc({required this.twoTouchId, required this.switchCode})
: super(InitialState()) {
on<InitialEvent>(_fetchTwoTouchStatus);
on<TwoTouchUpdated>(_twoTouchUpdated);
on<ChangeFirstSwitchStatusEvent>(_changeFirstSwitch);
on<ChangeSecondSwitchStatusEvent>(_changeSecondSwitch);
on<AllOffEvent>(_allOff);
on<AllOnEvent>(_allOn);
on<ChangeSlidingSegment>(_changeSliding);
on<SetCounterValue>(_setCounterValue);
on<GetCounterEvent>(_getCounterValue);
on<TickTimer>(_onTickTimer);
on<OnClose>(_onClose);
on<GroupAllOnEvent>(_groupAllOn);
on<GroupAllOffEvent>(_groupAllOff);
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<TwoTouchSave>(saveSchedule);
on<GetScheduleEvent>(getSchedule);
on<ToggleScheduleEvent>(toggleRepeat);
on<DeleteScheduleEvent>(deleteSchedule);
on<ToggleSelectedEvent>(toggleSelectedIndex);
on<ToggleCreateScheduleEvent>(toggleCreateSchedule);
on<InitialWizardEvent>(_fetchTwoTouchWizardStatus);
on<ChangeFirstWizardSwitchStatusEvent>(_changeFirstWizardSwitch);
on<ChangeSecondWizardSwitchStatusEvent>(_changeSecondWizardSwitch);
on<ChangeStatusEvent>(_changeStatus);
}
DateTime? selectedTime = DateTime.now();
int selectedTabIndex = 0;
void toggleSelectedIndex(
ToggleSelectedEvent event, Emitter<TwoTouchState> emit) {
emit(LoadingInitialState());
selectedTabIndex = event.index;
emit(ChangeSlidingSegmentState(value: selectedTabIndex));
}
void toggleCreateSchedule(
ToggleCreateScheduleEvent event, Emitter<TwoTouchState> emit) {
emit(LoadingInitialState());
createSchedule = !createSchedule;
selectedDays.clear();
selectedTime = DateTime.now();
emit(UpdateCreateScheduleState(createSchedule));
}
void _fetchTwoTouchStatus(
InitialEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState());
try {
var response = await DevicesAPI.getDeviceStatus(twoTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoTouchModel.fromJson(statusModelList);
emit(UpdateState(twoTouchModel: deviceStatus));
_listenToChanges();
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
_listenToChanges() {
try {
DatabaseReference ref =
FirebaseDatabase.instance.ref('device-status/$twoTouchId');
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>;
List<StatusModel> statusList = [];
usersMap['status'].forEach((element) {
statusList
.add(StatusModel(code: element['code'], value: element['value']));
});
deviceStatus = TwoTouchModel.fromJson(statusList);
if (!isClosed) {
add(TwoTouchUpdated());
}
});
} catch (_) {}
}
_twoTouchUpdated(TwoTouchUpdated event, Emitter<TwoTouchState> emit) {
emit(UpdateState(twoTouchModel: deviceStatus));
}
void _changeFirstSwitch(
ChangeFirstSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = !event.value;
emit(UpdateState(twoTouchModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: 'switch_1', value: !event.value),
twoTouchId);
if (!response['success']) {
add(const InitialEvent());
}
});
} catch (_) {
add(const InitialEvent());
}
}
void _changeSecondSwitch(
ChangeSecondSwitchStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.secondSwitch = !event.value;
emit(UpdateState(twoTouchModel: deviceStatus));
if (_timer != null) {
_timer!.cancel();
}
_timer = Timer(const Duration(milliseconds: 500), () async {
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: 'switch_2', value: !event.value),
twoTouchId);
if (!response['success']) {
add(const InitialEvent());
}
});
} catch (_) {
add(const InitialEvent());
}
}
void _allOff(AllOffEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = false;
deviceStatus.secondSwitch = false;
emit(UpdateState(twoTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
}
void _allOn(AllOnEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
deviceStatus.firstSwitch = true;
deviceStatus.secondSwitch = true;
emit(UpdateState(twoTouchModel: deviceStatus));
final response = await Future.wait([
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId,
code: 'switch_1',
value: deviceStatus.firstSwitch),
twoTouchId),
DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId,
code: 'switch_2',
value: deviceStatus.secondSwitch),
twoTouchId),
]);
if (response.every((element) => !element['success'])) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(const InitialEvent());
}
}
void _groupAllOn(GroupAllOnEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
for (int i = 0; i < groupTwoTouchList.length; i++) {
groupTwoTouchList[i].firstSwitch = true;
groupTwoTouchList[i].secondSwitch = true;
}
emit(
UpdateGroupState(twoTouchList: groupTwoTouchList, allSwitches: true));
List<String> allDeviceIds =
groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: true,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: true,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _groupAllOff(GroupAllOffEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
for (int i = 0; i < groupTwoTouchList.length; i++) {
groupTwoTouchList[i].firstSwitch = false;
groupTwoTouchList[i].secondSwitch = false;
}
emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: false));
List<String> allDeviceIds =
groupTwoTouchList.map((device) => device.deviceId).toList();
final response1 = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: false,
);
final response2 = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: false,
);
if (response1['failedResults'].toString() != '[]' ||
response2['failedResults'].toString() != '[]') {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
} catch (_) {
await Future.delayed(const Duration(milliseconds: 500));
add(InitialWizardEvent());
}
}
void _changeSliding(
ChangeSlidingSegment event, Emitter<TwoTouchState> emit) async {
emit(ChangeSlidingSegmentState(value: event.value));
}
void _setCounterValue(
SetCounterValue event, Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
int seconds = 0;
try {
seconds = event.duration.inSeconds;
final response = await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: event.deviceCode, value: seconds),
twoTouchId);
if (response['success'] ?? false) {
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown = seconds;
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown = seconds;
}
} else {
emit(const FailedState(error: 'Something went wrong'));
return;
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
if (seconds > 0) {
_onStartTimer(seconds);
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
void _getCounterValue(
GetCounterEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState());
try {
add(GetScheduleEvent());
var response = await DevicesAPI.getDeviceStatus(twoTouchId);
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoTouchModel.fromJson(statusModelList);
if (event.deviceCode == 'countdown_1') {
deviceStatus.firstCountDown > 0
? _onStartTimer(deviceStatus.firstCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.firstCountDown));
} else if (event.deviceCode == 'countdown_2') {
deviceStatus.secondCountDown > 0
? _onStartTimer(deviceStatus.secondCountDown)
: emit(UpdateTimerState(seconds: deviceStatus.secondCountDown));
}
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _onClose(OnClose event, Emitter<TwoTouchState> emit) {
_timer?.cancel();
}
void _onStartTimer(int seconds) {
_timer?.cancel();
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
add(TickTimer(seconds - timer.tick));
});
}
void _onTickTimer(TickTimer event, Emitter<TwoTouchState> emit) {
if (event.remainingTime > 0) {
emit(TimerRunInProgress(event.remainingTime));
} else {
_timer?.cancel();
emit(TimerRunComplete());
}
}
List<Map<String, String>> days = [
{"day": "Sun", "key": "Sun"},
{"day": "Mon", "key": "Mon"},
{"day": "Tue", "key": "Tue"},
{"day": "Wed", "key": "Wed"},
{"day": "Thu", "key": "Thu"},
{"day": "Fri", "key": "Fri"},
{"day": "Sat", "key": "Sat"},
];
Future<void> toggleDaySelection(
ToggleDaySelectionEvent event,
Emitter<TwoTouchState> emit,
) async {
emit(LoadingInitialState());
if (selectedDays.contains(event.key)) {
selectedDays.remove(event.key);
} else {
selectedDays.add(event.key);
}
emit(ChangeTimeState());
add(const ChangeSlidingSegment(value: 1));
}
Future<void> saveSchedule(
TwoTouchSave event,
Emitter<TwoTouchState> emit,
) async {
try {
if (selectedDays.isNotEmpty) {
emit(LoadingInitialState());
await DevicesAPI.postSchedule(
category: switchCode,
deviceId: twoTouchId,
time: getTimeStampWithoutSeconds(selectedTime).toString(),
code: switchCode,
value: toggleSchedule,
days: selectedDays);
CustomSnackBar.displaySnackBar('Save Successfully');
add(GetScheduleEvent());
emit(TwoTouchSaveSchedule());
add(const ToggleCreateScheduleEvent(index: 1));
// toggleCreateSchedule();
} else {
CustomSnackBar.displaySnackBar('Please select days');
}
} catch (e) {
emit(FailedState(error: e.toString()));
}
}
Future<void> getSchedule(
GetScheduleEvent event,
Emitter<TwoTouchState> emit,
) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.getSchedule(
category: switchCode,
deviceId: twoTouchId,
);
List<dynamic> jsonData = response;
listSchedule =
jsonData.map((item) => ScheduleModel.fromJson(item)).toList();
emit(InitialState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
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 toggleRepeat(
ToggleScheduleEvent event, Emitter<TwoTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.changeSchedule(
scheduleId: event.id, deviceUuid: twoTouchId, enable: event.toggle);
if (response == true) {
add(GetScheduleEvent());
toggleSchedule = event.toggle;
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
Future deleteSchedule(
DeleteScheduleEvent event, Emitter<TwoTouchState> emit) async {
try {
emit(LoadingInitialState());
final response = await DevicesAPI.deleteSchedule(
scheduleId: event.id,
deviceUuid: twoTouchId,
);
if (response == true) {
add(GetScheduleEvent());
return toggleSchedule;
}
emit(IsToggleState(onOff: toggleSchedule));
add(const ChangeSlidingSegment(value: 1));
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
emit(FailedState(error: errorMessage.toString()));
}
}
void _fetchTwoTouchWizardStatus(
InitialWizardEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState());
try {
devicesList = [];
groupTwoTouchList = [];
allSwitchesOn = true;
devicesList = await DevicesAPI.getDeviceByGroupName(
HomeCubit.getInstance().selectedSpace?.id ?? '', '2GT');
for (int i = 0; i < devicesList.length; i++) {
var response =
await DevicesAPI.getDeviceStatus(devicesList[i].uuid ?? '');
List<StatusModel> statusModelList = [];
for (var status in response['status']) {
statusModelList.add(StatusModel.fromJson(status));
}
deviceStatus = TwoTouchModel.fromJson(statusModelList);
groupTwoTouchList.add(GroupTwoTouchModel(
deviceId: devicesList[i].uuid ?? '',
deviceName: devicesList[i].name ?? '',
firstSwitch: deviceStatus.firstSwitch,
secondSwitch: deviceStatus.secondSwitch,
));
}
if (groupTwoTouchList.isNotEmpty) {
groupTwoTouchList.firstWhere((element) {
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesOn = false;
}
return true;
});
}
emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: allSwitchesOn));
} catch (e) {
emit(FailedState(error: e.toString()));
return;
}
}
void _changeFirstWizardSwitch(ChangeFirstWizardSwitchStatusEvent event,
Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.firstSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
List<String> allDeviceIds =
groupTwoTouchList.map((device) => device.deviceId).toList();
final response = await DevicesAPI.deviceBatchController(
code: 'switch_1',
devicesUuid: allDeviceIds,
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
void _changeSecondWizardSwitch(ChangeSecondWizardSwitchStatusEvent event,
Emitter<TwoTouchState> emit) async {
emit(LoadingNewSate(twoTouchModel: deviceStatus));
try {
bool allSwitchesValue = true;
groupTwoTouchList.forEach((element) {
if (element.deviceId == event.deviceId) {
element.secondSwitch = !event.value;
}
if (!element.firstSwitch || !element.secondSwitch) {
allSwitchesValue = false;
}
});
List<String> allDeviceIds =
groupTwoTouchList.map((device) => device.deviceId).toList();
emit(UpdateGroupState(
twoTouchList: groupTwoTouchList, allSwitches: allSwitchesValue));
final response = await DevicesAPI.deviceBatchController(
code: 'switch_2',
devicesUuid: allDeviceIds,
value: !event.value,
);
if (response['failedResults'].toString() != '[]') {
add(InitialWizardEvent());
}
} catch (_) {
add(InitialWizardEvent());
}
}
String statusSelected = '';
String optionSelected = '';
Future<void> _changeStatus(
ChangeStatusEvent event, Emitter<TwoTouchState> emit) async {
emit(LoadingInitialState());
print(optionSelected);
print(statusSelected);
final Map<String, Map<String, String>> controlMap = {
"relay_status": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"light_mode": {
'Off': 'none',
'On/Off Status': 'relay',
'Switch Position': 'pos',
},
"relay_status_1": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
"relay_status_2": {
'Power On': 'power_on',
'Power Off': 'power_off',
'Restart Memory': 'last',
},
};
final selectedControl = controlMap[optionSelected]?[statusSelected];
if (selectedControl != null) {
await DevicesAPI.controlDevice(
DeviceControlModel(
deviceId: twoTouchId, code: optionSelected, value: selectedControl),
twoTouchId,
);
Future.delayed(const Duration(seconds: 1), () async {
add(const InitialEvent());
});
Future.delayed(const Duration(seconds: 1), () async {
emit(UpdateState(twoTouchModel: deviceStatus));
});
} else {
print('Invalid statusSelected or optionSelected');
}
}
}

View File

@ -0,0 +1,162 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class TwoTouchEvent extends Equatable {
const TwoTouchEvent();
@override
List<Object> get props => [];
}
class LoadingEvent extends TwoTouchEvent {}
class TwoTouchUpdated extends TwoTouchEvent {}
class TwoTouchSave extends TwoTouchEvent {}
class ToggleScheduleEvent extends TwoTouchEvent {
final String id;
final bool toggle;
const ToggleScheduleEvent({required this.toggle, required this.id});
@override
List<Object> get props => [toggle, id];
}
class errorMessage extends TwoTouchEvent {}
class ToggleDaySelectionEvent extends TwoTouchEvent {
final String key;
const ToggleDaySelectionEvent({required this.key});
@override
List<Object> get props => [key];
}
class InitialEvent extends TwoTouchEvent {
const InitialEvent();
@override
List<Object> get props => [];
}
class ChangeFirstSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstSwitchStatusEvent({required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeSecondSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class AllOffEvent extends TwoTouchEvent {}
class AllOnEvent extends TwoTouchEvent {}
class GroupAllOnEvent extends TwoTouchEvent {}
class GroupAllOffEvent extends TwoTouchEvent {}
class ChangeSlidingSegment extends TwoTouchEvent {
final int value;
const ChangeSlidingSegment({required this.value});
@override
List<Object> get props => [value];
}
class GetCounterEvent extends TwoTouchEvent {
final String deviceCode;
const GetCounterEvent({required this.deviceCode});
@override
List<Object> get props => [deviceCode];
}
class SetCounterValue extends TwoTouchEvent {
final Duration duration;
final String deviceCode;
const SetCounterValue({required this.duration, required this.deviceCode});
@override
List<Object> get props => [duration, deviceCode];
}
class StartTimer extends TwoTouchEvent {
final int duration;
const StartTimer(this.duration);
@override
List<Object> get props => [duration];
}
class TickTimer extends TwoTouchEvent {
final int remainingTime;
const TickTimer(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class StopTimer extends TwoTouchEvent {}
class OnClose extends TwoTouchEvent {}
class GetScheduleEvent extends TwoTouchEvent {}
class DeleteScheduleEvent extends TwoTouchEvent {
final String id;
const DeleteScheduleEvent({required this.id});
@override
List<Object> get props => [id];
}
class TabChangedEvent extends TwoTouchEvent {
final int index;
TabChangedEvent({required this.index});
}
class ToggleSelectedEvent extends TwoTouchEvent {
final int index;
const ToggleSelectedEvent({required this.index});
@override
List<Object> get props => [index];
}
class ToggleCreateScheduleEvent extends TwoTouchEvent {
final int index;
const ToggleCreateScheduleEvent({required this.index});
@override
List<Object> get props => [index];
}
class InitialWizardEvent extends TwoTouchEvent {}
class ChangeFirstWizardSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeFirstWizardSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeSecondWizardSwitchStatusEvent extends TwoTouchEvent {
final bool value;
final String deviceId;
const ChangeSecondWizardSwitchStatusEvent(
{required this.value, this.deviceId = ''});
@override
List<Object> get props => [value, deviceId];
}
class ChangeStatusEvent extends TwoTouchEvent {
final String deviceId;
final BuildContext context;
const ChangeStatusEvent({this.deviceId = '',required this.context});
}

View File

@ -0,0 +1,91 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_app/features/devices/model/group_two_touch_model.dart';
import 'package:syncrow_app/features/devices/model/two_touch_model.dart';
class TwoTouchState extends Equatable {
const TwoTouchState();
@override
List<Object> get props => [];
}
class InitialState extends TwoTouchState {}
class TwoTouchSaveSchedule extends TwoTouchState {}
class ChangeTimeState extends TwoTouchState {}
class LoadingInitialState extends TwoTouchState {}
class UpdateState extends TwoTouchState {
final TwoTouchModel twoTouchModel;
const UpdateState({required this.twoTouchModel});
@override
List<Object> get props => [TwoTouchModel];
}
class LoadingNewSate extends TwoTouchState {
final TwoTouchModel twoTouchModel;
const LoadingNewSate({required this.twoTouchModel});
@override
List<Object> get props => [TwoTouchModel];
}
class UpdateGroupState extends TwoTouchState {
final List<GroupTwoTouchModel> twoTouchList;
final bool allSwitches;
const UpdateGroupState({required this.twoTouchList, required this.allSwitches});
@override
List<Object> get props => [twoTouchList, allSwitches];
}
class FailedState extends TwoTouchState {
final String error;
const FailedState({required this.error});
@override
List<Object> get props => [error];
}
class ChangeSlidingSegmentState extends TwoTouchState {
final int value;
const ChangeSlidingSegmentState({required this.value});
@override
List<Object> get props => [value];
}
class UpdateTimerState extends TwoTouchState {
final int seconds;
const UpdateTimerState({required this.seconds});
@override
List<Object> get props => [seconds];
}
class TimerRunInProgress extends TwoTouchState {
final int remainingTime;
const TimerRunInProgress(this.remainingTime);
@override
List<Object> get props => [remainingTime];
}
class TimerRunComplete extends TwoTouchState {}
class IsToggleState extends TwoTouchState {
final bool? onOff;
const IsToggleState({this.onOff});
}
class UpdateCreateScheduleState extends TwoTouchState {
final bool createSchedule;
UpdateCreateScheduleState(this.createSchedule);
}

View File

@ -0,0 +1,15 @@
class GroupThreeTouchModel {
final String deviceId;
final String deviceName;
bool firstSwitch;
bool secondSwitch;
bool thirdSwitch;
GroupThreeTouchModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
required this.secondSwitch,
required this.thirdSwitch,
});
}

View File

@ -0,0 +1,13 @@
class GroupTwoTouchModel {
final String deviceId;
final String deviceName;
bool firstSwitch;
bool secondSwitch;
GroupTwoTouchModel({
required this.deviceId,
required this.deviceName,
required this.firstSwitch,
required this.secondSwitch,
});
}

View File

@ -15,7 +15,8 @@ class OneTouchModel {
required this.firstCountDown,
required this.light_mode,
required this.relay,
required this.relay_status_1});
required this.relay_status_1
});
factory OneTouchModel.fromJson(List<StatusModel> jsonList) {
late bool _switch;

View File

@ -0,0 +1,82 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ThreeTouchModel {
bool firstSwitch;
bool secondSwitch;
bool thirdSwitch;
int firstCountDown;
int secondCountDown;
int thirdCountDown;
status relay;
lightStatus light_mode;
status relay_status_1;
status relay_status_2;
status relay_status_3;
ThreeTouchModel(
{required this.firstSwitch,
required this.secondSwitch,
required this.thirdSwitch,
required this.firstCountDown,
required this.secondCountDown,
required this.thirdCountDown,
required this.light_mode,
required this.relay,
required this.relay_status_1,
required this.relay_status_2,
required this.relay_status_3});
factory ThreeTouchModel.fromJson(List<StatusModel> jsonList) {
late bool _firstSwitch;
late bool _secondSwitch;
late bool _thirdSwitch;
late int _firstCount;
late int _secondCount;
late int _thirdCount;
late int _thirdCountDown;
late String _relay;
late String _light_mode;
late String _relay_status_1;
late String _relay_status_2;
late String _relay_status_3;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') {
_firstSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'switch_2') {
_secondSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'switch_3') {
_thirdSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_1') {
_firstCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'countdown_2') {
_secondCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'countdown_3') {
_thirdCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status') {
_relay = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'light_mode') {
_light_mode = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_1') {
_relay_status_1 = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_2') {
_relay_status_2 = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_3') {
_relay_status_3 = jsonList[i].value ?? 0;
}
}
return ThreeTouchModel(
firstSwitch: _firstSwitch,
secondSwitch: _secondSwitch,
thirdSwitch: _thirdSwitch,
firstCountDown: _firstCount,
secondCountDown: _secondCount,
thirdCountDown: _thirdCount,
light_mode: lightStatusExtension.fromString(_light_mode),
relay: StatusExtension.fromString(_relay),
relay_status_1: StatusExtension.fromString(_relay_status_1),
relay_status_2: StatusExtension.fromString(_relay_status_2),
relay_status_3: StatusExtension.fromString(_relay_status_3));
}
}

View File

@ -0,0 +1,63 @@
import 'package:syncrow_app/features/devices/model/status_model.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class TwoTouchModel {
bool firstSwitch;
bool secondSwitch;
int firstCountDown;
int secondCountDown;
status relay;
lightStatus light_mode;
status relay_status_1;
status relay_status_2;
TwoTouchModel(
{required this.firstSwitch,
required this.secondSwitch,
required this.firstCountDown,
required this.secondCountDown,
required this.light_mode,
required this.relay,
required this.relay_status_1,
required this.relay_status_2});
factory TwoTouchModel.fromJson(List<StatusModel> jsonList) {
late bool _firstSwitch;
late bool _secondSwitch;
late int _firstCount;
late int _secondCount;
late String _relay;
late String _light_mode;
late String _relay_status_1;
late String _relay_status_2;
for (int i = 0; i < jsonList.length; i++) {
if (jsonList[i].code == 'switch_1') {
_firstSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'switch_2') {
_secondSwitch = jsonList[i].value ?? false;
} else if (jsonList[i].code == 'countdown_1') {
_firstCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'countdown_2') {
_secondCount = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status') {
_relay = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'light_mode') {
_light_mode = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_1') {
_relay_status_1 = jsonList[i].value ?? 0;
} else if (jsonList[i].code == 'relay_status_2') {
_relay_status_2 = jsonList[i].value ?? 0;
}
}
return TwoTouchModel(
firstSwitch: _firstSwitch,
secondSwitch: _secondSwitch,
firstCountDown: _firstCount,
secondCountDown: _secondCount,
light_mode: lightStatusExtension.fromString(_light_mode),
relay: StatusExtension.fromString(_relay),
relay_status_1: StatusExtension.fromString(_relay_status_1),
relay_status_2: StatusExtension.fromString(_relay_status_2));
}
}

View File

@ -1,12 +1,10 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class CircularButton extends StatelessWidget {
class CircularButton extends StatelessWidget {
const CircularButton({
super.key,
required this.device,
@ -31,7 +29,6 @@ class CircularButton extends StatelessWidget {
),
child: GestureDetector(
onTap: onTap,
child: Stack(
alignment: Alignment.center,
children: [
@ -51,11 +48,26 @@ class CircularButton extends StatelessWidget {
borderRadius: BorderRadius.circular(100),
),
child: Center(
child: Icon(
icons,
color: ColorsManager.primaryColorWithOpacity,
size: 25,
),
child: label == 'All On'
? BodySmall(
text: "On",
style: context.bodyMedium.copyWith(
color: ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
)
: label == 'All Off'
? BodySmall(
text: "Off",
style: context.bodyMedium.copyWith(
color:
ColorsManager.primaryColorWithOpacity,
fontWeight: FontWeight.bold),
)
: Icon(
icons,
color: ColorsManager.primaryColorWithOpacity,
size: 25,
),
),
),
],
@ -73,4 +85,4 @@ class CircularButton extends StatelessWidget {
],
);
}
}
}

View File

@ -16,7 +16,6 @@ import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';

View File

@ -4,7 +4,7 @@ import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_bloc.
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/one_touch_bloc/one_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_one_touch_model.dart';
import 'package:syncrow_app/features/devices/model/one_touch_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
@ -19,23 +19,27 @@ class OneTouchSetting extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<GroupOneTouchModel> groupOneTouchModel = [];
return DefaultScaffold(
title: 'Setting',
child: BlocProvider(
create: (context) =>
OneTouchBloc(switchCode: '', oneTouchId: device?.uuid ?? '')
..add(InitialWizardEvent()),
..add(const InitialEvent(groupScreen: false)),
child: BlocBuilder<OneTouchBloc, OneTouchState>(
builder: (context, state) {
final oneTouchBloc = BlocProvider.of<OneTouchBloc>(context);
OneTouchModel? oneTouchModel = OneTouchModel(
firstSwitch: false,
firstCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off);
bool allSwitchesOn = false;
if (state is UpdateGroupState) {
groupOneTouchModel = state.oneTouchList;
allSwitchesOn = state.allSwitches;
// if (state is UpdateState) {
// oneTouchModel = state.oneTouchModel;
// }
if (state is UpdateState) {
oneTouchModel = state.oneTouchModel;
}
return state is LoadingInitialState
? const Center(
@ -54,13 +58,15 @@ class OneTouchSetting extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () {
onTap: () async {
oneTouchBloc.optionSelected =
'relay_status';
showDialog(
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
oneTouchModel!.relay.value,
cancelTab: () {
Navigator.of(context).pop();
},
@ -68,6 +74,7 @@ class OneTouchSetting extends StatelessWidget {
oneTouchBloc.add(ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status',
label1: 'Power Off',
@ -88,6 +95,13 @@ class OneTouchSetting extends StatelessWidget {
);
},
);
if (result == true) {
// Future.delayed(const Duration(seconds: 1),
// () async {
// oneTouchBloc.add(const InitialEvent(
// groupScreen: false));
// });
}
},
child: Container(
padding: const EdgeInsets.only(
@ -105,8 +119,8 @@ class OneTouchSetting extends StatelessWidget {
children: [
BodyMedium(
fontSize: 13,
text: oneTouchBloc
.deviceStatus.relay.value,
text:
oneTouchModel!.relay.value,
fontColor:
ColorsManager.textGray,
),
@ -126,13 +140,14 @@ class OneTouchSetting extends StatelessWidget {
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () {
oneTouchBloc.optionSelected =
'light_mode';
showDialog(
onTap: () async {
oneTouchBloc.optionSelected ='light_mode';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
oneTouchModel!.light_mode.value,
cancelTab: () {
Navigator.of(context).pop();
},
@ -141,6 +156,7 @@ class OneTouchSetting extends StatelessWidget {
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Indicator Status',
label1: 'Off',
@ -161,6 +177,10 @@ class OneTouchSetting extends StatelessWidget {
);
},
);
if (result == true) {
// oneTouchBloc.add(const InitialEvent(
// groupScreen: false));
}
},
child: SizedBox(
child: Row(
@ -197,13 +217,16 @@ class OneTouchSetting extends StatelessWidget {
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () {
onTap: () async {
oneTouchBloc.optionSelected =
'relay_status_1';
showDialog(
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
oneTouchModel!
.relay_status_1.value,
cancelTab: () {
Navigator.of(context).pop();
},
@ -212,32 +235,36 @@ class OneTouchSetting extends StatelessWidget {
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status 1',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
print(selected);
oneTouchBloc.statusSelected =
selected;
print(
'Selected: $selected for Label 1');
},
onTapLabel2: (selected) {
print(selected);
oneTouchBloc.statusSelected =
selected;
print(
'Selected: $selected for Label 2');
},
onTapLabel3: (selected) {
print(selected);
oneTouchBloc.statusSelected =
selected;
print(
'Selected: $selected for Label 3');
},
);
},
);
if (result == true) {
oneTouchBloc.add(const InitialEvent(
groupScreen: false));
}
},
child: Row(
mainAxisAlignment:
@ -284,13 +311,14 @@ class RestartStatusDialog extends StatefulWidget {
final String label3;
final String title;
// Add onTap callbacks as parameters
final Function(String)? onTapLabel1;
final Function(String)? onTapLabel2;
final Function(String)? onTapLabel3;
final Function()? cancelTab;
final Function()? confirmTab;
final String? initialSelectedLabel;
RestartStatusDialog({
required this.label1,
required this.label2,
@ -301,6 +329,7 @@ class RestartStatusDialog extends StatefulWidget {
this.onTapLabel3,
required this.cancelTab,
required this.confirmTab,
this.initialSelectedLabel,
});
@override
@ -308,7 +337,14 @@ class RestartStatusDialog extends StatefulWidget {
}
class _RestartStatusDialogState extends State<RestartStatusDialog> {
String _selectedOption = '';
late String _selectedOption;
@override
void initState() {
super.initState();
_selectedOption = widget.initialSelectedLabel ?? '';
}
@override
Widget build(BuildContext context) {
@ -432,15 +468,14 @@ class _RestartStatusDialogState extends State<RestartStatusDialog> {
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400),
),
CircularCheckbox(
value: _selectedOption ==
label, // True if the current option is selected
value: _selectedOption == label,
onChanged: (bool? value) {
if (value == true) {
setState(() {
_selectedOption = label; // Select only one option
_selectedOption = label;
});
if (onTap != null) {
onTap(label); // Call the passed onTap callback
onTap(label);
}
}
},

View File

@ -0,0 +1,230 @@
import 'package:flutter/material.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
class RestartStatusDialog extends StatefulWidget {
final String label1;
final String label2;
final String label3;
final String title;
final Function(String)? onTapLabel1;
final Function(String)? onTapLabel2;
final Function(String)? onTapLabel3;
final Function()? cancelTab;
final Function()? confirmTab;
final String? initialSelectedLabel;
RestartStatusDialog({
required this.label1,
required this.label2,
required this.label3,
required this.title,
this.onTapLabel1,
this.onTapLabel2,
this.onTapLabel3,
required this.cancelTab,
required this.confirmTab,
this.initialSelectedLabel,
});
@override
_RestartStatusDialogState createState() => _RestartStatusDialogState();
}
class _RestartStatusDialogState extends State<RestartStatusDialog> {
late String _selectedOption;
@override
void initState() {
super.initState();
_selectedOption = widget.initialSelectedLabel ?? '';
}
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
BodyLarge(
text: widget.title,
fontWeight: FontWeight.w700,
fontColor: ColorsManager.primaryColor,
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: Column(
children: [
_buildCheckboxOption(
label: widget.label1,
onTap: widget.onTapLabel1,
),
_buildCheckboxOption(
label: widget.label2,
onTap: widget.onTapLabel2,
),
_buildCheckboxOption(
label: widget.label3,
onTap: widget.onTapLabel3,
),
],
),
),
Row(
children: [
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
right: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: SizedBox(
child: InkWell(
onTap: widget.cancelTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Cancel',
style: TextStyle(
color: ColorsManager.textGray,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
),
),
),
),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
left: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: InkWell(
onTap: widget.confirmTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Confirm',
style: TextStyle(
color: ColorsManager.primaryColor,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
Widget _buildCheckboxOption(
{required String label, Function(String)? onTap}) {
return Padding(
padding: const EdgeInsets.only(bottom: 10, top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(
text: label,
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400),
),
CircularCheckbox(
value: _selectedOption == label,
onChanged: (bool? value) {
if (value == true) {
setState(() {
_selectedOption = label;
});
if (onTap != null) {
onTap(label);
}
}
},
),
],
),
);
}
}
class CircularCheckbox extends StatefulWidget {
final bool value;
final ValueChanged<bool?> onChanged;
CircularCheckbox({required this.value, required this.onChanged});
@override
_CircularCheckboxState createState() => _CircularCheckboxState();
}
class _CircularCheckboxState extends State<CircularCheckbox> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
widget.onChanged(!widget.value);
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: widget.value
? ColorsManager.primaryColorWithOpacity.withOpacity(0.01)
: Colors.grey,
width: 2.0,
),
color: widget.value
? ColorsManager.primaryColorWithOpacity
: Colors.transparent,
),
width: 24.0,
height: 24.0,
child: widget.value
? const Icon(
Icons.check,
color: Colors.white,
size: 16.0,
)
: null,
),
);
}
}

View File

@ -14,7 +14,9 @@ import 'package:syncrow_app/features/devices/view/widgets/gateway/gateway_view.d
import 'package:syncrow_app/features/devices/view/widgets/lights/light_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_gang/one_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/one_touch/one_touch_screen.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_touch/three_touch_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_gang/two_gang_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_Interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/wall_sensor/wall_sensor_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/ceiling_sensor/ceiling_sensor_interface.dart';
import 'package:syncrow_app/features/devices/view/widgets/smart_door/door_interface.dart';
@ -172,6 +174,19 @@ void showDeviceInterface(DeviceModel device, BuildContext context) {
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
OneTouchScreen(device: device)));
case DeviceType.TowTouch:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
TwoTouchInterface(touchSwitch: device)));
case DeviceType.ThreeTouch:
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) =>
ThreeTouchInterface(touchSwitch: device)));
break;
default:
}

View File

@ -0,0 +1,56 @@
// import 'package:flutter/material.dart';
// // import 'package:flutter_bloc/flutter_bloc.dart';
// import 'package:flutter_svg/svg.dart';
// // import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/two_gang_bloc.dart';
// // import 'package:syncrow_app/features/devices/bloc/three_gang_bloc/two_gang_state.dart';
// import 'package:syncrow_app/features/devices/model/device_model.dart';
// import 'package:syncrow_app/generated/assets.dart';
// import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
// class GangSwitch extends StatelessWidget {
// const GangSwitch(
// {super.key, required this.threeGangSwitch, required this.value, required this.action});
// final DeviceModel threeGangSwitch;
// final bool value;
// final Function action;
// @override
// Widget build(BuildContext context) {
// return InkWell(
// overlayColor: WidgetStateProperty.all(Colors.transparent),
// onTap: () {
// action();
// // var tempControl = DeviceControlModel(
// // deviceId: control.deviceId, code: control.code!, value: !control.value!);
// // DevicesCubit.getInstance().deviceControl(
// // tempControl,
// // control.deviceId!,
// // );
// },
// child: Stack(
// alignment: value ? Alignment.topCenter : Alignment.bottomCenter,
// children: [
// Container(
// decoration: BoxDecoration(
// borderRadius: const BorderRadius.all(Radius.circular(100.0)),
// color: value ? ColorsManager.primaryColorWithOpacity : ColorsManager.switchOffColor,
// ),
// width: 60,
// height: 115,
// ),
// Padding(
// padding: const EdgeInsets.all(5.0),
// child: SizedBox.square(
// dimension: 60,
// child: SvgPicture.asset(
// value ? Assets.assetsIconsLightSwitchOn : Assets.assetsIconsLightSwitchOff,
// fit: BoxFit.fill,
// ),
// ),
// ),
// ],
// ),
// );
// }
// }

View File

@ -0,0 +1,186 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_touch/timer_screen.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class ScheduleScreen extends StatelessWidget {
final DeviceModel device;
const ScheduleScreen({required this.device, super.key});
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: SafeArea(
child: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 48,
),
DefaultContainer(
width: MediaQuery.sizeOf(context).width,
child: Column(
children: [
InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: "switch_1",
device: device,
deviceCode: 'countdown_1',
)));
},
child: Container(
padding: const EdgeInsets.only(
left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Bedside Light",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 18,
)
],
),
),
),
const Divider(
color: ColorsManager.dividerColor,
),
InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: "switch_2",
device: device,
deviceCode: 'countdown_2',
)));
},
child: Container(
padding: const EdgeInsets.only(
left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Ceiling Light",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 18,
)
],
),
),
),
const Divider(
color: ColorsManager.dividerColor,
),
InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder:
(context, animation1, animation2) =>
TimerScheduleScreen(
switchCode: "switch_3",
device: device,
deviceCode: 'countdown_3',
)));
},
child: Container(
padding: const EdgeInsets.only(
left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Spotlight",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 18,
)
],
),
),
),
],
)),
],
),
),
),
));
}
}

View File

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_touch/three_touch_screen.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/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class ThreeTouchInterface extends StatelessWidget {
const ThreeTouchInterface({super.key, this.touchSwitch});
final DeviceModel? touchSwitch;
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: touchSwitch != null
? DeviceAppbar(
deviceName: touchSwitch!.name!,
deviceUuid: touchSwitch!.uuid!,
)
: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: touchSwitch?.name ?? 'Lights',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: SafeArea(
child: Padding(
padding: EdgeInsets.only(
left: Constants.defaultPadding,
right: Constants.defaultPadding,
bottom: Constants.bottomNavBarHeight,
),
child: ThreeTouchScreen(device: touchSwitch),
),
),
),
),
);
}
}

View File

@ -0,0 +1,88 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_state.dart';
import 'package:syncrow_app/features/devices/model/group_three_touch_model.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class ThreeTouchList extends StatelessWidget {
const ThreeTouchList({super.key, required this.threeTouchList, required this.allSwitches});
final List<GroupThreeTouchModel> threeTouchList;
final bool allSwitches;
@override
Widget build(BuildContext context) {
return BlocBuilder<ThreeTouchBloc, ThreeTouchState>(
builder: (context, state) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 10),
const BodySmall(text: 'All Lights'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: allSwitches,
action: () {
BlocProvider.of<ThreeTouchBloc>(context).add(GroupAllOnEvent());
},
secondAction: () {
BlocProvider.of<ThreeTouchBloc>(context).add(GroupAllOffEvent());
},
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount: threeTouchList.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
BodySmall(text: '${threeTouchList[index].deviceName} beside light'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: threeTouchList[index].firstSwitch,
action: () {
BlocProvider.of<ThreeTouchBloc>(context).add(ChangeFirstSwitchStatusEvent(
value: threeTouchList[index].firstSwitch,
deviceId: threeTouchList[index].deviceId));
},
),
const SizedBox(height: 10),
BodySmall(text: '${threeTouchList[index].deviceName} ceiling light'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: threeTouchList[index].secondSwitch,
action: () {
BlocProvider.of<ThreeTouchBloc>(context).add(ChangeSecondSwitchStatusEvent(
value: threeTouchList[index].secondSwitch,
deviceId: threeTouchList[index].deviceId));
},
),
const SizedBox(height: 10),
BodySmall(text: '${threeTouchList[index].deviceName} spotlight'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: threeTouchList[index].thirdSwitch,
action: () {
BlocProvider.of<ThreeTouchBloc>(context).add(ChangeThirdSwitchStatusEvent(
value: threeTouchList[index].thirdSwitch,
deviceId: threeTouchList[index].deviceId));
},
),
],
);
},
),
],
),
);
},
);
}
}

View File

@ -0,0 +1,474 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/three_touch_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/circular_button.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_touch/schedule_screen.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ThreeTouchScreen extends StatelessWidget {
const ThreeTouchScreen({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) =>
ThreeTouchBloc(switchCode: '', threeTouchId: device?.uuid ?? '')
..add(InitialEvent(groupScreen: device != null ? false : true)),
child: BlocBuilder<ThreeTouchBloc, ThreeTouchState>(
builder: (context, state) {
ThreeTouchModel threeTouchModel = ThreeTouchModel(
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off,
relay_status_2: status.off,
relay_status_3: status.off,
firstSwitch: false,
secondSwitch: false,
thirdSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
thirdCountDown: 0);
if (state is LoadingNewSate) {
threeTouchModel = state.threeTouchModel;
} else if (state is UpdateState) {
threeTouchModel = state.threeTouchModel;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<ThreeTouchBloc>(context).add(InitialEvent(
groupScreen: device != null ? false : true));
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Expanded(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: threeTouchModel.firstSwitch,
action: () {
BlocProvider.of<ThreeTouchBloc>(
context)
.add(ChangeFirstSwitchStatusEvent(
value: threeTouchModel
.firstSwitch));
},
// control: DeviceControlModel(
// deviceId: device.uuid,
// // code: 'switch_1',
// code: device.status[0].code,
// // value: true,
// value: device.status[0].value,
// ),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Bedside Light",
fontColor:
ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: threeTouchModel.secondSwitch,
action: () {
BlocProvider.of<ThreeTouchBloc>(
context)
.add(
ChangeSecondSwitchStatusEvent(
value: threeTouchModel
.secondSwitch));
},
// control: DeviceControlModel(
// // deviceId: 'bfe10693d4fd263206ocq9',
// // code: 'switch_2',
// // value: true,
// deviceId: device.uuid,
// code: device.status[1].code,
// value: device.status[1].value,
// ),
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Ceiling Light",
fontColor:
ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: threeTouchModel.thirdSwitch,
action: () {
BlocProvider.of<ThreeTouchBloc>(
context)
.add(ChangeThirdSwitchStatusEvent(
value: threeTouchModel
.thirdSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 70,
child: BodySmall(
text: "Spotlight",
fontColor:
ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
],
),
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircularButton(
device: device,
icons: Icons.u_turn_left,
label: "All On",
onTap: () {
BlocProvider.of<ThreeTouchBloc>(context)
.add(AllOnEvent());
},
),
// Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// Card(
// elevation: 3,
// shape: RoundedRectangleBorder(
// borderRadius:
// BorderRadius.circular(100),
// ),
// child: GestureDetector(
// onTap: () {
// // DevicesCubit.getInstance().deviceControl(
// // DeviceControlModel(
// // deviceId: device.uuid,
// // code: 'switch_1',
// // value: true,
// // ),
// // device.uuid!,
// // );
// // DevicesCubit.getInstance().deviceControl(
// // DeviceControlModel(
// // deviceId: device.uuid,
// // code: 'switch_2',
// // value: true,
// // ),
// // device.uuid!,
// // );
// // DevicesCubit.getInstance().deviceControl(
// // DeviceControlModel(
// // deviceId: device.uuid,
// // code: 'switch_3',
// // value: true,
// // ),
// // device.uuid!,
// // );
// BlocProvider.of<ThreeTouchBloc>(
// context)
// .add(AllOnEvent());
// },
// child: Stack(
// alignment: Alignment.center,
// children: [
// Container(
// width: 60,
// height: 60,
// decoration: BoxDecoration(
// color: Colors.grey[300],
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// child: Center(
// child: BodySmall(
// text: "On",
// style: context.bodyMedium
// .copyWith(
// color: ColorsManager
// .primaryColorWithOpacity,
// fontWeight:
// FontWeight
// .bold),
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// const SizedBox(height: 10),
// BodySmall(
// text: "All On",
// style: context.bodyMedium.copyWith(
// color: ColorsManager.textPrimaryColor,
// ),
// ),
// ],
// ),
const SizedBox(
width: 20,
),
CircularButton(
device: device,
icons: Icons.access_time,
label: "Timer",
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
ScheduleScreen(
device: device!,
)));
},
),
// Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// Card(
// elevation: 3,
// shape: RoundedRectangleBorder(
// borderRadius:
// BorderRadius.circular(100),
// ),
// child: GestureDetector(
// onTap: () {
// Navigator.push(
// context,
// PageRouteBuilder(
// pageBuilder: (context,
// animation1,
// animation2) =>
// ScheduleScreen(
// device: device!,
// )));
// },
// child: Stack(
// alignment: Alignment.center,
// children: [
// Container(
// width: 60,
// height: 60,
// decoration: BoxDecoration(
// color: Colors.grey[300],
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// child: Center(
// child: Icon(
// Icons.access_time,
// color: ColorsManager
// .primaryColorWithOpacity,
// size: 25,
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// const SizedBox(height: 10),
// BodySmall(
// text: "Timer",
// style: context.bodyMedium.copyWith(
// color: ColorsManager.textPrimaryColor,
// ),
// ),
// ],
// ),
const SizedBox(
width: 20,
),
CircularButton(
device: device,
icons: Icons.u_turn_left,
label: "All Off",
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
ScheduleScreen(
device: device!,
)));
},
),
// Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// Card(
// elevation: 3,
// shape: RoundedRectangleBorder(
// borderRadius:
// BorderRadius.circular(100),
// ),
// child: GestureDetector(
// onTap: () {
// // DevicesCubit.getInstance().deviceControl(
// // DeviceControlModel(
// // deviceId: device.uuid,
// // code: 'switch_1',
// // value: false,
// // ),
// // device.uuid!,
// // );
// // DevicesCubit.getInstance().deviceControl(
// // DeviceControlModel(
// // deviceId: device.uuid,
// // code: 'switch_2',
// // value: false,
// // ),
// // device.uuid!,
// // );
// // DevicesCubit.getInstance().deviceControl(
// // DeviceControlModel(
// // deviceId: device.uuid,
// // code: 'switch_3',
// // value: false,
// // ),
// // device.uuid!,
// // );
// BlocProvider.of<ThreeTouchBloc>(
// context)
// .add(AllOffEvent());
// },
// child: Stack(
// alignment: Alignment.center,
// children: [
// Container(
// width: 60,
// height: 60,
// decoration: BoxDecoration(
// color: Colors.grey[300],
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// child: Center(
// child: BodySmall(
// text: "Off",
// style: context.bodyMedium
// .copyWith(
// color: ColorsManager
// .primaryColorWithOpacity,
// fontWeight:
// FontWeight
// .bold),
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// const SizedBox(height: 10),
// BodySmall(
// text: "All Off",
// style: context.bodyMedium.copyWith(
// color: ColorsManager.textPrimaryColor,
// ),
// ),
// ],
// ),
],
),
),
Expanded(child: SizedBox())
],
),
),
],
),
);
},
),
);
}
}

View File

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_three_touch_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_touch/three_touch_list.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
class ThreeTouchWizard extends StatelessWidget {
const ThreeTouchWizard({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
return DefaultScaffold(
child: BlocProvider(
create: (context) => ThreeTouchBloc(switchCode: '', threeTouchId: device?.uuid ?? '')
..add(InitialEvent(groupScreen: device != null ? false : true)),
child: BlocBuilder<ThreeTouchBloc, ThreeTouchState>(
builder: (context, state) {
List<GroupThreeTouchModel> groupThreeTouchModel = [];
bool allSwitchesOn = false;
if (state is UpdateGroupState) {
groupThreeTouchModel = state.threeTouchList;
allSwitchesOn = state.allSwitches;
}
return state is LoadingInitialState
? const Center(
child:
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
)
: ThreeTouchList(
threeTouchList: groupThreeTouchModel,
allSwitches: allSwitchesOn,
);
},
),
));
}
}

View File

@ -0,0 +1,321 @@
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/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/create_schedule.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/schedule_list.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class TimerScheduleScreen extends StatelessWidget {
final DeviceModel device;
final String deviceCode;
final String switchCode;
const TimerScheduleScreen(
{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) => ThreeTouchBloc(
switchCode: switchCode, threeTouchId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()),
child: BlocBuilder<ThreeTouchBloc, ThreeTouchState>(
builder: (context, state) {
final threeTouchBloc = BlocProvider.of<ThreeTouchBloc>(context);
Duration duration = Duration.zero;
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) {
threeTouchBloc.add(OnClose());
Navigator.pop(context);
}
},
child: DefaultTabController(
length: 2,
child: DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
actions: [
threeTouchBloc.createSchedule == true
? TextButton(
onPressed: () {
threeTouchBloc.add(ThreeTouchSave());
},
child: const Text('Save'))
: threeTouchBloc.selectedTabIndex == 1
? IconButton(
onPressed: () {
// oneTouchBloc.toggleCreateSchedule();
threeTouchBloc.add(
const ToggleCreateScheduleEvent(
index: 1));
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
],
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
decoration: const ShapeDecoration(
color: ColorsManager.onPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(30)),
),
),
child: TabBar(
// onTap: (value) {
// if (value == 0) {
// if (threeTouchBloc.createSchedule ==
// true) {
// threeTouchBloc.toggleCreateSchedule();
// }
// threeTouchBloc.toggleSelectedIndex(0);
// } else {
// threeTouchBloc.toggleSelectedIndex(1);
// }
// },
onTap: (value) {
if (value == 0) {
if (threeTouchBloc.createSchedule ==
true) {
// oneTouchBloc.toggleCreateSchedule();
threeTouchBloc.add(
const ToggleCreateScheduleEvent(
index: 0));
}
threeTouchBloc.add(
const ToggleSelectedEvent(
index: 0));
} else {
threeTouchBloc.add(
const ToggleSelectedEvent(
index: 1));
}
},
indicatorColor: Colors.white,
dividerHeight: 0,
indicatorSize: TabBarIndicatorSize.tab,
indicator: const ShapeDecoration(
color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20)),
),
),
tabs: [
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
),
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(), // Disable swiping
children: [
Center(
child: Container(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
countNum > 0
? BodyLarge(
text: _formatDuration(
countNum),
fontColor: ColorsManager
.slidingBlueColor,
fontSize: 40,
)
: CupertinoTimerPicker(
mode:
CupertinoTimerPickerMode
.hm,
onTimerDurationChanged:
(Duration
newDuration) {
duration = newDuration;
},
),
GestureDetector(
onTap: () {
if (state
is LoadingNewSate) {
return;
}
if (countNum > 0) {
threeTouchBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration: Duration
.zero));
} else if (duration !=
Duration.zero) {
threeTouchBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration:
duration));
}
},
child: SvgPicture.asset(
countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
),
SizedBox(
child: threeTouchBloc.createSchedule ==
true
? CreateSchedule(
onToggleChanged: (bool isOn) {
threeTouchBloc.toggleSchedule =
isOn;
},
onDateTimeChanged:
(DateTime dateTime) {
threeTouchBloc.selectedTime =
dateTime;
},
days: threeTouchBloc.days,
selectDays: (List<String>
selectedDays) {
threeTouchBloc.selectedDays =
selectedDays;
},
)
: Padding(
padding: const EdgeInsets.only(
top: 10),
child: Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Expanded(
child: ScheduleListView(
listSchedule: threeTouchBloc
.listSchedule, // Pass the schedule list here
onDismissed:
(scheduleId) {
threeTouchBloc
.listSchedule
.removeWhere(
(schedule) =>
schedule
.scheduleId ==
scheduleId);
threeTouchBloc.add(
DeleteScheduleEvent(
id: scheduleId));
},
onToggleSchedule:
(scheduleId,
isEnabled) {
threeTouchBloc.add(
ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
),
],
),
),
),
],
),
),
],
),
)));
},
),
),
);
}
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';
}
}

View File

@ -0,0 +1,382 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/three_touch_bloc/three_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/three_touch_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/restart_status_dialog.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class ThreeTouchSetting extends StatelessWidget {
const ThreeTouchSetting({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Setting',
child: BlocProvider(
create: (context) =>
ThreeTouchBloc(switchCode: '', threeTouchId: device?.uuid ?? '')
..add(const InitialEvent(groupScreen: false)),
child: BlocBuilder<ThreeTouchBloc, ThreeTouchState>(
builder: (context, state) {
final twoTouchBloc = BlocProvider.of<ThreeTouchBloc>(context);
ThreeTouchModel deviceStatus = ThreeTouchModel(
firstSwitch: false,
secondSwitch: false,
thirdSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
thirdCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off,
relay_status_2: status.off,
relay_status_3: status.off,
);
if (state is UpdateState) {
deviceStatus = state.threeTouchModel;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: Column(
children: [
Container(
child: DefaultContainer(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'relay_status';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
deviceStatus!.relay.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// Future.delayed(const Duration(seconds: 1),
// () async {
// oneTouchBloc.add(const InitialEvent(
// groupScreen: false));
// });
}
},
child: Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: deviceStatus.relay.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
)),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'light_mode';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
deviceStatus.light_mode.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Indicator Status',
label1: 'Off',
label2: 'On/Off Status',
label3: 'Switch Position',
onTapLabel1: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// oneTouchBloc.add(const InitialEvent(
// groupScreen: false));
}
},
child: SizedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Indicator Status',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: twoTouchBloc.deviceStatus
.light_mode.value,
fontColor: ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
)),
),
),
const Divider(
color: ColorsManager.graysColor,
),
Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'relay_status_1';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel: deviceStatus
.relay_status_1.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status 1',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// twoTouchBloc
// .add(const InitialEvent());
}
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status 1',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: twoTouchBloc.deviceStatus
.relay_status_1.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
),
)),
const Divider(
color: ColorsManager.graysColor,
),
Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'relay_status_2';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel: deviceStatus
.relay_status_2.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status 2',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// twoTouchBloc
// .add(const InitialEvent());
}
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status 2',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: twoTouchBloc.deviceStatus
.relay_status_1.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
),
)),
],
),
),
),
],
);
},
),
));
}
}

View File

@ -0,0 +1,141 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_Touch/two_timer_screen.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class TwoTouchScheduleScreen extends StatelessWidget {
final DeviceModel device;
const TwoTouchScheduleScreen({required this.device, super.key});
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: SafeArea(
child: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 48,
),
DefaultContainer(
width: MediaQuery.sizeOf(context).width,
child: Column(
children: [
InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
device: device,
deviceCode: 'countdown_1',
switchCode:'switch_1' ,
)));
},
child: Container(
padding:
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Cove Light",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 18,
)
],
),
),
),
const Divider(
color: ColorsManager.dividerColor,
),
InkWell(
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1, animation2) => TimerScheduleScreen(
device: device,
deviceCode: 'countdown_2',
switchCode:'switch_2' ,
)));
},
child: Container(
padding:
const EdgeInsets.only(left: 25, right: 15, top: 20, bottom: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodySmall(
text: "Chandelier",
style: context.bodyMedium.copyWith(
color: ColorsManager.textPrimaryColor,
fontSize: 15,
fontWeight: FontWeight.w400,
),
),
const Icon(
Icons.arrow_forward_ios,
color: ColorsManager.greyColor,
size: 18,
)
],
),
),
),
],
)),
],
),
),
),
));
}
}

View File

@ -0,0 +1,303 @@
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/flutter_svg.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/shared_widgets/create_schedule.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
import 'package:syncrow_app/features/shared_widgets/schedule_list.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/generated/assets.dart';
import 'package:syncrow_app/utils/context_extension.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class TimerScheduleScreen extends StatelessWidget {
final DeviceModel device;
final String deviceCode;
final String switchCode;
const TimerScheduleScreen(
{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) =>
TwoTouchBloc(switchCode: switchCode, twoTouchId: device.uuid ?? '')
..add(GetCounterEvent(deviceCode: deviceCode))
..add(GetScheduleEvent()),
child: BlocBuilder<TwoTouchBloc, TwoTouchState>(
builder: (context, state) {
final twoTouchBloc = BlocProvider.of<TwoTouchBloc>(context);
Duration duration = Duration.zero;
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) {
twoTouchBloc.add(OnClose());
Navigator.pop(context);
}
},
child: DefaultTabController(
length: 2,
child: DefaultScaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: const BodyLarge(
text: 'Schedule',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
actions: [
twoTouchBloc.createSchedule == true
? TextButton(
onPressed: () {
twoTouchBloc.add(TwoTouchSave());
},
child: const Text('Save'))
: twoTouchBloc.selectedTabIndex == 1
? IconButton(
onPressed: () {
// oneTouchBloc.toggleCreateSchedule();
twoTouchBloc.add(
const ToggleCreateScheduleEvent(
index: 1));
},
icon: const Icon(Icons.add),
)
: const SizedBox(),
],
),
child: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
decoration: const ShapeDecoration(
color: ColorsManager.onPrimaryColor,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(30)),
),
),
child: TabBar(
onTap: (value) {
if (value == 0) {
if (twoTouchBloc.createSchedule ==
true) {
// oneTouchBloc.toggleCreateSchedule();
twoTouchBloc.add(
const ToggleCreateScheduleEvent(
index: 0));
}
twoTouchBloc.add(
const ToggleSelectedEvent(
index: 0));
} else {
twoTouchBloc.add(
const ToggleSelectedEvent(
index: 1));
}
},
indicatorColor:
Colors.white, // Customize the indicator
dividerHeight: 0,
indicatorSize: TabBarIndicatorSize.tab,
indicator: const ShapeDecoration(
color: ColorsManager.slidingBlueColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20)),
),
),
tabs: [
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: BodySmall(
text: 'Countdown',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
Tab(
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 10),
child: Text(
'Schedule',
style: context.bodySmall.copyWith(
color: ColorsManager.blackColor,
fontSize: 12,
fontWeight: FontWeight.w400,
),
),
),
),
],
),
),
Expanded(
child: TabBarView(
physics: const NeverScrollableScrollPhysics(), // Disable swiping
children: [
Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
countNum > 0
? BodyLarge(
text: _formatDuration(
countNum),
fontColor: ColorsManager
.slidingBlueColor,
fontSize: 40,
)
: CupertinoTimerPicker(
mode:
CupertinoTimerPickerMode
.hm,
onTimerDurationChanged:
(Duration
newDuration) {
duration = newDuration;
},
),
GestureDetector(
onTap: () {
if (state
is LoadingNewSate) {
return;
}
if (countNum > 0) {
twoTouchBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration: Duration
.zero));
} else if (duration !=
Duration.zero) {
twoTouchBloc.add(
SetCounterValue(
deviceCode:
deviceCode,
duration:
duration));
}
},
child: SvgPicture.asset(
countNum > 0
? Assets.pauseIcon
: Assets.playIcon)),
],
),
),
SizedBox(
child: twoTouchBloc.createSchedule ==
true
? CreateSchedule(
onToggleChanged: (bool isOn) {
twoTouchBloc.toggleSchedule =
isOn;
},
onDateTimeChanged:
(DateTime dateTime) {
twoTouchBloc.selectedTime =
dateTime;
},
days: twoTouchBloc.days,
selectDays: (List<String>
selectedDays) {
twoTouchBloc.selectedDays =
selectedDays;
},
)
: Padding(
padding: const EdgeInsets.only(
top: 10),
child: Column(
children: [
Expanded(
child: ScheduleListView(
listSchedule: twoTouchBloc
.listSchedule, // Pass the schedule list here
onDismissed:
(scheduleId) {
twoTouchBloc
.listSchedule
.removeWhere(
(schedule) =>
schedule
.scheduleId ==
scheduleId);
twoTouchBloc.add(
DeleteScheduleEvent(
id: scheduleId));
},
onToggleSchedule:
(scheduleId,
isEnabled) {
twoTouchBloc.add(
ToggleScheduleEvent(
id: scheduleId,
toggle: isEnabled,
));
},
),
),
],
),
),
),
],
),
),
],
),
)));
},
),
),
);
}
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';
}
}

View File

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/device_appbar.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_screen.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/constants.dart';
import 'package:syncrow_app/utils/resource_manager/font_manager.dart';
class TwoTouchInterface extends StatelessWidget {
const TwoTouchInterface({super.key, this.touchSwitch});
final DeviceModel? touchSwitch;
@override
Widget build(BuildContext context) {
return AnnotatedRegion(
value: SystemUiOverlayStyle(
statusBarColor: ColorsManager.primaryColor.withOpacity(0.5),
statusBarIconBrightness: Brightness.light,
),
child: Scaffold(
backgroundColor: ColorsManager.backgroundColor,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: touchSwitch != null
? DeviceAppbar(
deviceName: touchSwitch!.name!,
deviceUuid: touchSwitch!.uuid!,
)
: AppBar(
backgroundColor: Colors.transparent,
centerTitle: true,
title: BodyLarge(
text: touchSwitch?.name ?? 'Lights',
fontColor: ColorsManager.primaryColor,
fontWeight: FontsManager.bold,
),
),
body: Container(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(
Assets.assetsImagesBackground,
),
fit: BoxFit.cover,
opacity: 0.4,
),
),
child: SafeArea(
child: Padding(
padding: EdgeInsets.only(
left: Constants.defaultPadding,
right: Constants.defaultPadding,
bottom: Constants.bottomNavBarHeight,
),
child: TwoTouchScreen(device: touchSwitch),
),
),
),
),
);
}
}

View File

@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_state.dart';
import 'package:syncrow_app/features/devices/model/group_two_touch_model.dart';
import 'package:syncrow_app/features/shared_widgets/devices_default_switch.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
class TwoTouchList extends StatelessWidget {
const TwoTouchList(
{super.key, required this.twoTouchList, required this.allSwitches});
final List<GroupTwoTouchModel> twoTouchList;
final bool allSwitches;
@override
Widget build(BuildContext context) {
return BlocBuilder<TwoTouchBloc, TwoTouchState>(
builder: (context, state) {
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 10),
const BodySmall(text: 'All Lights'),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: allSwitches,
action: () {
BlocProvider.of<TwoTouchBloc>(context).add(GroupAllOnEvent());
},
secondAction: () {
BlocProvider.of<TwoTouchBloc>(context).add(GroupAllOffEvent());
},
),
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
padding: const EdgeInsets.all(0),
itemCount: twoTouchList.length,
itemBuilder: (context, index) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 10),
BodySmall(text: twoTouchList[index].deviceName),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: twoTouchList[index].firstSwitch,
action: () {
BlocProvider.of<TwoTouchBloc>(context).add(
ChangeFirstWizardSwitchStatusEvent(
value: twoTouchList[index].firstSwitch,
deviceId: twoTouchList[index].deviceId));
},
),
const SizedBox(height: 10),
BodySmall(text: twoTouchList[index].deviceName),
const SizedBox(height: 5),
DevicesDefaultSwitch(
switchValue: twoTouchList[index].secondSwitch,
action: () {
BlocProvider.of<TwoTouchBloc>(context).add(
ChangeSecondWizardSwitchStatusEvent(
value: twoTouchList[index].secondSwitch,
deviceId: twoTouchList[index].deviceId));
},
),
],
);
},
),
],
),
);
},
);
}
}

View File

@ -0,0 +1,333 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/two_touch_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/circular_button.dart';
import 'package:syncrow_app/features/devices/view/widgets/three_gang/gang_switch.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_setting.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_schedule_screen.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/text_widgets/body_small.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class TwoTouchScreen extends StatelessWidget {
const TwoTouchScreen({super.key, this.device, this.switchCode});
final DeviceModel? device;
final String? switchCode;
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => TwoTouchBloc(
switchCode: switchCode ?? '', twoTouchId: device?.uuid ?? '')
..add(const InitialEvent()),
child: BlocBuilder<TwoTouchBloc, TwoTouchState>(
builder: (context, state) {
TwoTouchModel twoTouchModel = TwoTouchModel(
firstSwitch: false,
secondSwitch: false,
firstCountDown: 0,
secondCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off,
relay_status_2: status.off,
);
if (state is LoadingNewSate) {
twoTouchModel = state.twoTouchModel;
} else if (state is UpdateState) {
twoTouchModel = state.twoTouchModel;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: RefreshIndicator(
onRefresh: () async {
BlocProvider.of<TwoTouchBloc>(context)
.add(const InitialEvent());
},
child: ListView(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Expanded(child: SizedBox.shrink()),
Expanded(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: twoTouchModel.firstSwitch,
action: () {
BlocProvider.of<TwoTouchBloc>(context)
.add(ChangeFirstSwitchStatusEvent(
value: twoTouchModel
.firstSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 77,
child: BodySmall(
text: "Cove Light",
fontColor:
ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
Column(
children: [
GangSwitch(
threeGangSwitch: device!,
value: twoTouchModel.secondSwitch,
action: () {
BlocProvider.of<TwoTouchBloc>(context)
.add(
ChangeSecondSwitchStatusEvent(
value: twoTouchModel
.secondSwitch));
},
),
const SizedBox(height: 20),
const SizedBox(
width: 77,
child: BodySmall(
text: "Chandelier",
fontColor:
ColorsManager.textPrimaryColor,
textAlign: TextAlign.center,
),
),
],
),
],
),
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircularButton(
device: device,
icons: Icons.u_turn_left,
label: "All On",
onTap: () {
BlocProvider.of<TwoTouchBloc>(context)
.add(AllOnEvent());
},
),
// Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// Card(
// elevation: 3,
// shape: RoundedRectangleBorder(
// borderRadius:
// BorderRadius.circular(100),
// ),
// child: GestureDetector(
// onTap: () {
// BlocProvider.of<TwoTouchBloc>(
// context)
// .add(AllOnEvent());
// },
// child: Stack(
// alignment: Alignment.center,
// children: [
// Container(
// width: 60,
// height: 60,
// decoration: BoxDecoration(
// color: Colors.grey[300],
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// child: Center(
// child: BodySmall(
// text: "On",
// style: context.bodyMedium
// .copyWith(
// color: ColorsManager
// .primaryColorWithOpacity,
// fontWeight:
// FontWeight
// .bold),
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// const SizedBox(height: 10),
// BodySmall(
// text: "All On",
// style: context.bodyMedium.copyWith(
// color: ColorsManager.textPrimaryColor,
// ),
// ),
// ],
// ),
const SizedBox(
width: 20,
),
CircularButton(
device: device,
icons: Icons.access_time,
label: "Timer",
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
TwoTouchScheduleScreen(
device: device!,
)));
},
),
// Column(
// mainAxisSize: MainAxisSize.min,
// children: [
// Card(
// elevation: 3,
// shape: RoundedRectangleBorder(
// borderRadius:
// BorderRadius.circular(100),
// ),
// child: GestureDetector(
// onTap: () {
// Navigator.push(
// context,
// PageRouteBuilder(
// pageBuilder: (context,
// animation1,
// animation2) =>
// TwoTouchScheduleScreen(
// device: device!,
// )));
// },
// child: Stack(
// alignment: Alignment.center,
// children: [
// Container(
// width: 60,
// height: 60,
// decoration: BoxDecoration(
// color: Colors.grey[300],
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// ),
// Container(
// width: 40,
// height: 40,
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius:
// BorderRadius.circular(
// 100),
// ),
// child: Center(
// child: Icon(
// Icons.access_time,
// color: ColorsManager
// .primaryColorWithOpacity,
// size: 25,
// ),
// ),
// ),
// ],
// ),
// ),
// ),
// const SizedBox(height: 10),
// BodySmall(
// text: "Timer",
// style: context.bodyMedium.copyWith(
// color: ColorsManager.textPrimaryColor,
// ),
// ),
// ],
// ),
const SizedBox(
width: 20,
),
CircularButton(
device: device,
icons: Icons.access_time,
label: "Setting",
onTap: () {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, animation1,
animation2) =>
TwoTouchSetting(
device: device,
)));
},
),
const SizedBox(
width: 20,
),
CircularButton(
device: device,
icons: Icons.access_time,
label: "All Off",
onTap: () {
BlocProvider.of<TwoTouchBloc>(context)
.add(AllOffEvent());
},
),
],
),
),
Expanded(child: SizedBox())
],
),
),
],
),
);
},
),
);
}
}

View File

@ -0,0 +1,613 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/two_touch_model.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.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/features/shared_widgets/text_widgets/body_medium.dart';
import 'package:syncrow_app/utils/resource_manager/color_manager.dart';
import 'package:syncrow_app/utils/resource_manager/constants.dart';
class TwoTouchSetting extends StatelessWidget {
const TwoTouchSetting({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
return DefaultScaffold(
title: 'Setting',
child: BlocProvider(
create: (context) =>
TwoTouchBloc(switchCode: '', twoTouchId: device?.uuid ?? '')
..add(const InitialEvent()),
child: BlocBuilder<TwoTouchBloc, TwoTouchState>(
builder: (context, state) {
final twoTouchBloc = BlocProvider.of<TwoTouchBloc>(context);
TwoTouchModel? twoTouchModel = TwoTouchModel(
relay_status_2: status.off,
secondCountDown: 0,
secondSwitch: false,
firstSwitch: false,
firstCountDown: 0,
light_mode: lightStatus.off,
relay: status.off,
relay_status_1: status.off);
// if (state is UpdateState) {
// TwoTouchModel = state.TwoTouchModel;
// }
if (state is UpdateState) {
twoTouchModel = state.twoTouchModel;
}
return state is LoadingInitialState
? const Center(
child: DefaultContainer(
width: 50,
height: 50,
child: CircularProgressIndicator()),
)
: Column(
children: [
Container(
child: DefaultContainer(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'relay_status';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
twoTouchModel!.relay.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// Future.delayed(const Duration(seconds: 1),
// () async {
// oneTouchBloc.add(const InitialEvent(
// groupScreen: false));
// });
}
},
child: Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text:
twoTouchModel.relay.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
)),
),
const Divider(
color: ColorsManager.graysColor,
),
Padding(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'light_mode';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
twoTouchModel!.light_mode.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Indicator Status',
label1: 'Off',
label2: 'On/Off Status',
label3: 'Switch Position',
onTapLabel1: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// oneTouchBloc.add(const InitialEvent(
// groupScreen: false));
}
},
child: SizedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Indicator Status',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: twoTouchBloc.deviceStatus
.light_mode.value,
fontColor: ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
)),
),
),
const Divider(
color: ColorsManager.graysColor,
),
Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'relay_status_1';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
twoTouchModel!
.relay_status_1.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status 1',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// twoTouchBloc
// .add(const InitialEvent());
}
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status 1',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: twoTouchBloc.deviceStatus
.relay_status_1.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
),
)),
const Divider(
color: ColorsManager.graysColor,
),
Container(
padding: const EdgeInsets.only(
bottom: 10, top: 10),
child: InkWell(
onTap: () async {
twoTouchBloc.optionSelected =
'relay_status_2';
final result = await showDialog(
context: context,
builder: (context) {
return RestartStatusDialog(
initialSelectedLabel:
twoTouchModel!
.relay_status_2.value,
cancelTab: () {
Navigator.of(context).pop();
},
confirmTab: () {
twoTouchBloc.add(
ChangeStatusEvent(
deviceId: device!.uuid!,
context: context));
Navigator.of(context).pop(true);
},
title: 'Restart Status 2',
label1: 'Power Off',
label2: 'Power On',
label3: 'Restart Memory',
onTapLabel1: (selected) {
print('selected===$selected');
twoTouchBloc.statusSelected =
selected;
},
onTapLabel2: (selected) {
print('selected===$selected');
twoTouchBloc.statusSelected =
selected;
},
onTapLabel3: (selected) {
print('selected===$selected');
twoTouchBloc.statusSelected =
selected;
},
);
},
);
if (result == true) {
// twoTouchBloc
// .add(const InitialEvent());
}
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
const BodyLarge(
fontSize: 15,
text: 'Restart Status 2',
fontWeight: FontWeight.w400,
),
Row(
children: [
BodyMedium(
fontSize: 13,
text: twoTouchBloc.deviceStatus
.relay_status_1.value,
fontColor:
ColorsManager.textGray,
),
const Icon(
Icons.keyboard_arrow_right,
color: ColorsManager.textGray,
),
],
)
],
),
)),
],
),
),
),
],
);
},
),
));
}
}
class RestartStatusDialog extends StatefulWidget {
final String label1;
final String label2;
final String label3;
final String title;
final Function(String)? onTapLabel1;
final Function(String)? onTapLabel2;
final Function(String)? onTapLabel3;
final Function()? cancelTab;
final Function()? confirmTab;
final String? initialSelectedLabel;
RestartStatusDialog({
required this.label1,
required this.label2,
required this.label3,
required this.title,
this.onTapLabel1,
this.onTapLabel2,
this.onTapLabel3,
required this.cancelTab,
required this.confirmTab,
this.initialSelectedLabel,
});
@override
_RestartStatusDialogState createState() => _RestartStatusDialogState();
}
class _RestartStatusDialogState extends State<RestartStatusDialog> {
late String _selectedOption;
@override
void initState() {
super.initState();
_selectedOption = widget.initialSelectedLabel ?? '';
}
@override
Widget build(BuildContext context) {
return AlertDialog(
contentPadding: EdgeInsets.zero,
content: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const SizedBox(
height: 10,
),
BodyLarge(
text: widget.title,
fontWeight: FontWeight.w700,
fontColor: ColorsManager.primaryColor,
fontSize: 16,
),
const Padding(
padding: EdgeInsets.only(left: 15, right: 15),
child: Divider(
color: ColorsManager.textGray,
),
),
Padding(
padding: const EdgeInsets.only(left: 15, right: 15),
child: Column(
children: [
_buildCheckboxOption(
label: widget.label1,
onTap: widget.onTapLabel1,
),
_buildCheckboxOption(
label: widget.label2,
onTap: widget.onTapLabel2,
),
_buildCheckboxOption(
label: widget.label3,
onTap: widget.onTapLabel3,
),
],
),
),
Row(
children: [
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
right: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: SizedBox(
child: InkWell(
onTap: widget.cancelTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Cancel',
style: TextStyle(
color: ColorsManager.textGray,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
),
),
),
),
),
Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border(
left: BorderSide(
color: ColorsManager.textGray,
width: 0.5,
),
top: BorderSide(
color: ColorsManager.textGray,
width: 1.0,
),
)),
child: InkWell(
onTap: widget.confirmTab,
child: const Padding(
padding: EdgeInsets.all(15),
child: Center(
child: Text(
'Confirm',
style: TextStyle(
color: ColorsManager.primaryColor,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
)),
))
],
)
],
),
);
}
Widget _buildCheckboxOption(
{required String label, Function(String)? onTap}) {
return Padding(
padding: const EdgeInsets.only(bottom: 10, top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
BodyMedium(
text: label,
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w400),
),
CircularCheckbox(
value: _selectedOption == label,
onChanged: (bool? value) {
if (value == true) {
setState(() {
_selectedOption = label;
});
if (onTap != null) {
onTap(label);
}
}
},
),
],
),
);
}
}
class CircularCheckbox extends StatefulWidget {
final bool value;
final ValueChanged<bool?> onChanged;
CircularCheckbox({required this.value, required this.onChanged});
@override
_CircularCheckboxState createState() => _CircularCheckboxState();
}
class _CircularCheckboxState extends State<CircularCheckbox> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
widget.onChanged(!widget.value);
},
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: widget.value
? ColorsManager.primaryColorWithOpacity.withOpacity(0.01)
: Colors.grey,
width: 2.0,
),
color: widget.value
? ColorsManager.primaryColorWithOpacity
: Colors.transparent,
),
width: 24.0,
height: 24.0,
child: widget.value
? const Icon(
Icons.check,
color: Colors.white,
size: 16.0,
)
: null,
),
);
}
}

View File

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_bloc.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_event.dart';
import 'package:syncrow_app/features/devices/bloc/two_touch_bloc/two_touch_state.dart';
import 'package:syncrow_app/features/devices/model/device_model.dart';
import 'package:syncrow_app/features/devices/model/group_two_touch_model.dart';
import 'package:syncrow_app/features/devices/view/widgets/two_touch/two_touch_list.dart';
import 'package:syncrow_app/features/shared_widgets/default_container.dart';
import 'package:syncrow_app/features/shared_widgets/default_scaffold.dart';
class TwoTouchWizard extends StatelessWidget {
const TwoTouchWizard({super.key, this.device});
final DeviceModel? device;
@override
Widget build(BuildContext context) {
List<GroupTwoTouchModel> groupTwoTouchModel = [];
return DefaultScaffold(
child: BlocProvider(
create: (context) =>
TwoTouchBloc(switchCode: '', twoTouchId: device?.uuid ?? '')..add(InitialWizardEvent()),
child: BlocBuilder<TwoTouchBloc, TwoTouchState>(
builder: (context, state) {
bool allSwitchesOn = false;
if (state is UpdateGroupState) {
groupTwoTouchModel = state.twoTouchList;
allSwitchesOn = state.allSwitches;
}
return state is LoadingInitialState
? const Center(
child:
DefaultContainer(width: 50, height: 50, child: CircularProgressIndicator()),
)
: TwoTouchList(
twoTouchList: groupTwoTouchModel,
allSwitches: allSwitchesOn,
);
},
),
));
}
}

View File

@ -51,6 +51,9 @@ enum DeviceType {
WH,
DS,
OneTouch,
TowTouch,
ThreeTouch,
Other,
}
@ -78,6 +81,8 @@ Map<String, DeviceType> devicesTypesMap = {
"WH": DeviceType.WH,
"DS": DeviceType.DS,
"1GT": DeviceType.OneTouch,
"2GT": DeviceType.TowTouch,
"3GT": DeviceType.ThreeTouch,
};
Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
DeviceType.AC: [
@ -321,6 +326,110 @@ Map<DeviceType, List<FunctionModel>> devicesFunctionsMap = {
"range": ['power_off', 'power_on', 'last']
})),
],
DeviceType.TowTouch: [
FunctionModel(
code: 'switch_1',
type: functionTypesMap['Boolean'],
values: ValueModel.fromJson({})),
FunctionModel(
code: 'switch_2',
type: functionTypesMap['Boolean'],
values: ValueModel.fromJson({})),
FunctionModel(
code: 'countdown_1',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson(
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
FunctionModel(
code: 'countdown_2',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson(
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
FunctionModel(
code: 'relay_status',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['power_off', 'power_on', 'last']
})),
FunctionModel(
code: 'light_mode',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['none', 'relay', 'pos']
})),
FunctionModel(
code: 'relay_status_1',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['power_off', 'power_on', 'last']
})),
FunctionModel(
code: 'relay_status_2',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['power_off', 'power_on', 'last']
})),
],
DeviceType.ThreeTouch: [
FunctionModel(
code: 'switch_1',
type: functionTypesMap['Boolean'],
values: ValueModel.fromJson({})),
FunctionModel(
code: 'switch_2',
type: functionTypesMap['Boolean'],
values: ValueModel.fromJson({})),
FunctionModel(
code: 'switch_3',
type: functionTypesMap['Boolean'],
values: ValueModel.fromJson({})),
FunctionModel(
code: 'countdown_1',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson(
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
FunctionModel(
code: 'countdown_2',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson(
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
FunctionModel(
code: 'countdown_3',
type: functionTypesMap['Integer'],
values: ValueModel.fromJson(
{"unit": "s", "min": 0, "max": 43200, "scale": 0, "step": 1})),
FunctionModel(
code: 'relay_status',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['power_off', 'power_on', 'last']
})),
FunctionModel(
code: 'light_mode',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['none', 'relay', 'pos']
})),
FunctionModel(
code: 'relay_status_1',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['power_off', 'power_on', 'last']
})),
FunctionModel(
code: 'relay_status_2',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['power_off', 'power_on', 'last']
})),
FunctionModel(
code: 'relay_status_3',
type: functionTypesMap['Enum'],
values: ValueModel.fromJson({
"range": ['power_off', 'power_on', 'last']
})),
],
};
enum TempModes { hot, cold, wind }
@ -662,9 +771,9 @@ extension lightStatusExtension on lightStatus {
switch (this) {
case lightStatus.off:
return "Off";
case lightStatus.on_off:
return "On/Off Status";
case lightStatus.switchPosition:
return "On/Off Status";
case lightStatus.on_off:
return "Restart Memory";
}
}
@ -674,9 +783,9 @@ extension lightStatusExtension on lightStatus {
case "none":
return lightStatus.off;
case "relay":
return lightStatus.on_off;
case "pos":
return lightStatus.switchPosition;
case "pos":
return lightStatus.on_off;
default:
throw ArgumentError("Invalid access type: $value");
}